Skip to content

pms241948/trivy_mcp

Repository files navigation

Trivy MCP Server

SSE 기반 MCP μ„œλ²„ - Trivyλ₯Ό ν™œμš©ν•œ λ³΄μ•ˆ 취약점 μŠ€μΊ” 및 SBOM 생성

Kakao PlayMCP와 ν˜Έν™˜λ˜λŠ” MCP(Model Context Protocol) μ„œλ²„λ‘œ, νŒŒμΌμ‹œμŠ€ν…œ 및 μ»¨ν…Œμ΄λ„ˆ 이미지에 λŒ€ν•œ λ³΄μ•ˆ 취약점 μŠ€μΊ”κ³Ό SBOM(Software Bill of Materials) 생성 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

μ£Όμš” κΈ°λŠ₯

  • πŸ” 취약점 μŠ€μΊ”: νŒŒμΌμ‹œμŠ€ν…œ 및 μ»¨ν…Œμ΄λ„ˆ 이미지 λ³΄μ•ˆ 취약점 뢄석
  • πŸ“‹ SBOM 생성: SPDX, CycloneDX ν˜•μ‹ 지원
  • πŸ“Š κ²°κ³Ό μš”μ•½: 심각도별 λΆ„λ₯˜, Top CVE/νŒ¨ν‚€μ§€, ꢌμž₯ 쑰치
  • 🌊 SSE 슀트리밍: μ‹€μ‹œκ°„ μ§„ν–‰ μƒνƒœ 전솑
  • πŸ”’ λ³΄μ•ˆ: Path traversal λ°©μ§€, λ™μ‹œ μ‹€ν–‰ μ œν•œ

λΉ λ₯Έ μ‹œμž‘

Docker Compose (ꢌμž₯)

# 1. ν”„λ‘œμ νŠΈ 클둠
git clone <repository-url>
cd trivy_mcp

# 2. μŠ€μΊ”ν•  ν”„λ‘œμ νŠΈ μ€€λΉ„
mkdir -p scan-input
cp -r /path/to/your/project ./scan-input/

# 3. μ‹€ν–‰
docker-compose up -d --build

# 4. 둜그 확인
docker-compose logs -f

# 5. ν…ŒμŠ€νŠΈ
curl http://localhost:8000/mcp/tools/list | jq .

둜컬 μ‹€ν–‰ (개발용)

# 1. Python ν™˜κ²½ μ€€λΉ„
python -m venv venv
source venv/bin/activate

# 2. μ˜μ‘΄μ„± μ„€μΉ˜
pip install -r requirements.txt

# 3. Trivy μ„€μΉ˜ (macOS)
brew install trivy

# 4. ν™˜κ²½ λ³€μˆ˜ μ„€μ •
cp .env.example .env
# .env νŒŒμΌμ„ 적절히 μˆ˜μ •

# 5. 디렉토리 생성
mkdir -p /tmp/trivy-mcp/{results,logs,cache,input}

# 6. ν™˜κ²½λ³€μˆ˜ μ„€μ • ν›„ μ‹€ν–‰
export SCAN_ROOT=/tmp/trivy-mcp/input
export RESULTS_DIR=/tmp/trivy-mcp/results
export TRIVY_CACHE_DIR=/tmp/trivy-mcp/cache
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

PlayMCP 등둝

상세 κ°€μ΄λ“œλŠ” CONNECTION_GUIDE.mdλ₯Ό μ°Έκ³ ν•˜μ„Έμš”.

MCP URL

  • 둜컬 μ—°κ²°: http://localhost:8000/mcp/tools/list
  • μ™ΈλΆ€ μ—°κ²°(터널링): ssh -R 80:localhost:8000 serveo.net μ‹€ν–‰ ν›„ μƒμ„±λœ URL + /mcp/tools/list

λ˜λŠ” Docker λ‚΄λΆ€ λ„€νŠΈμ›Œν¬ μ‚¬μš© μ‹œ:

http://trivy-mcp:8000/mcp/tools/list

API μ—”λ“œν¬μΈνŠΈ

λ©”μ„œλ“œ 경둜 μ„€λͺ…
GET /mcp/tools/list μ‚¬μš© κ°€λŠ₯ν•œ 도ꡬ λͺ©λ‘ 및 μŠ€ν‚€λ§ˆ
POST /mcp/tools/call 도ꡬ μ‹€ν–‰ (run_id λ°˜ν™˜)
GET /mcp/runs/{id}/events SSE μ§„ν–‰ 이벀트 슀트림
GET /mcp/runs/{id}/result μ΅œμ’… κ²°κ³Ό 쑰회
GET /mcp/runs/{id}/download/{artifact} κ²°κ³Ό 파일 λ‹€μš΄λ‘œλ“œ

도ꡬ λͺ©λ‘

1. healthcheck

μ„œλ²„ 및 Trivy μƒνƒœ 확인

curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{"name": "healthcheck", "arguments": {}}'

2. scan_filesystem

νŒŒμΌμ‹œμŠ€ν…œ 취약점 μŠ€μΊ”

curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "scan_filesystem",
    "arguments": {
      "path": "/scan/input/my-project",
      "severity": "HIGH,CRITICAL"
    }
  }'

3. scan_image

μ»¨ν…Œμ΄λ„ˆ 이미지 취약점 μŠ€μΊ”

# 이미지 레퍼런슀둜 μŠ€μΊ”
curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "scan_image",
    "arguments": {
      "image_ref": "nginx:latest"
    }
  }'

# tar 파일둜 μŠ€μΊ”
curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "scan_image",
    "arguments": {
      "image_tar_path": "/scan/input/image.tar"
    }
  }'

4. generate_sbom_filesystem

νŒŒμΌμ‹œμŠ€ν…œ SBOM 생성

curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "generate_sbom_filesystem",
    "arguments": {
      "path": "/scan/input/my-project",
      "sbom_format": "spdx-json"
    }
  }'

5. generate_sbom_image

이미지 SBOM 생성

curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "generate_sbom_image",
    "arguments": {
      "image_ref": "python:3.11-slim",
      "sbom_format": "cyclonedx"
    }
  }'

6. summarize_scan_result

μŠ€μΊ” κ²°κ³Ό μš”μ•½

curl -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "summarize_scan_result",
    "arguments": {
      "raw_result_path": "/data/results/{run_id}/trivy-result.json",
      "top_n": 10
    }
  }'

SSE 이벀트 λͺ¨λ‹ˆν„°λ§

μŠ€μΊ” μ‹€ν–‰ ν›„ SSE둜 μ§„ν–‰ μƒνƒœλ₯Ό μ‹€μ‹œκ°„ λͺ¨λ‹ˆν„°λ§:

# 1. μŠ€μΊ” μ‹œμž‘
RESPONSE=$(curl -s -X POST http://localhost:8000/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{"name": "scan_filesystem", "arguments": {"path": "/scan/input/project"}}')

RUN_ID=$(echo $RESPONSE | jq -r '.run_id')

# 2. SSE 이벀트 ꡬ독
curl -N http://localhost:8000/mcp/runs/$RUN_ID/events

SSE 이벀트 νƒ€μž…

이벀트 μ„€λͺ…
start μŠ€μΊ” μ‹œμž‘
progress μ§„ν–‰ 단계 (downloading-db, scanning, done λ“±)
log Trivy stdout/stderr
result μ΅œμ’… κ²°κ³Ό
error 였λ₯˜ λ°œμƒ

SSE 섀계 방식

POST /mcp/tools/call + GET /mcp/runs/{id}/events 뢄리 방식을 μ±„νƒν–ˆμŠ΅λ‹ˆλ‹€.

선택 이유

  1. 비차단 응닡: POST μš”μ²­μ΄ μ¦‰μ‹œ run_idλ₯Ό λ°˜ν™˜ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈκ°€ λΈ”λ‘œν‚Ήλ˜μ§€ μ•ŠμŒ
  2. μž¬μ—°κ²° 지원: SSE 연결이 λŠμ–΄μ Έλ„ λ™μΌν•œ run_id둜 μž¬μ—°κ²° κ°€λŠ₯
  3. 닀쀑 ꡬ독: μ—¬λŸ¬ ν΄λΌμ΄μ–ΈνŠΈκ°€ 동일 μž‘μ—…μ˜ μ§„ν–‰ μƒνƒœλ₯Ό λ™μ‹œμ— ꡬ독 κ°€λŠ₯
  4. PlayMCP ν˜Έν™˜μ„±: μš”μ²­/응닡과 이벀트 슀트림이 λΆ„λ¦¬λ˜μ–΄ ν‘œμ€€ MCP ν”„λ‘œν† μ½œκ³Ό ν˜Έν™˜

μ˜€ν”„λΌμΈ/폐쇄망 운영

1. μ™ΈλΆ€λ§μ—μ„œ DB λ‹€μš΄λ‘œλ“œ

# DB λ‹€μš΄λ‘œλ“œ μ „μš© μ»¨ν…Œμ΄λ„ˆ μ‹€ν–‰
docker run -it --rm \
  -v trivy-db-cache:/root/.cache/trivy \
  aquasec/trivy:latest \
  image --download-db-only

# μΊμ‹œ 디렉토리 μΆ”μΆœ
docker run --rm \
  -v trivy-db-cache:/cache \
  -v $(pwd):/output \
  alpine tar czf /output/trivy-db.tar.gz -C /cache .

2. νμ‡„λ§μœΌλ‘œ 전솑

scp trivy-db.tar.gz internal-server:/path/to/

3. νμ‡„λ§μ—μ„œ 적용

# docker-compose.yml이 μžˆλŠ” λ””λ ‰ν† λ¦¬μ—μ„œ
mkdir -p trivy-cache
tar xzf trivy-db.tar.gz -C trivy-cache/

# docker-compose.yml μˆ˜μ •: λ³Όλ₯¨μ„ 둜컬 λ””λ ‰ν† λ¦¬λ‘œ λ³€κ²½
# - trivy-cache:/data/trivy-cache
# β†’ - ./trivy-cache:/data/trivy-cache

# OFFLINE_MODE ν™œμ„±ν™”
# environment:
#   - OFFLINE_MODE=true

docker-compose up -d

μ˜ˆμ‹œ μ‹œλ‚˜λ¦¬μ˜€

"이 폴더 μŠ€μΊ”ν•˜κ³  SBOM μƒμ„±ν•΄μ€˜"

LLM이 λ‹€μŒ 도ꡬ듀을 순차적으둜 ν˜ΈμΆœν•©λ‹ˆλ‹€:

  1. scan_filesystem: 취약점 μŠ€μΊ”

    {"name": "scan_filesystem", "arguments": {"path": "/scan/input/project"}}
  2. generate_sbom_filesystem: SBOM 생성

    {"name": "generate_sbom_filesystem", "arguments": {"path": "/scan/input/project"}}
  3. (선택) summarize_scan_result: κ²°κ³Ό μš”μ•½

    {"name": "summarize_scan_result", "arguments": {"raw_result_path": "/data/results/{scan_id}/trivy-result.json"}}

ν™˜κ²½ λ³€μˆ˜

λ³€μˆ˜ κΈ°λ³Έκ°’ μ„€λͺ…
HOST 0.0.0.0 μ„œλ²„ λ°”μΈλ“œ μ£Όμ†Œ
PORT 8000 μ„œλ²„ 포트
SCAN_ROOT /scan/input μŠ€μΊ” ν—ˆμš© 루트 디렉토리
TRIVY_CACHE_DIR /data/trivy-cache Trivy DB μΊμ‹œ
RESULTS_DIR /data/results κ²°κ³Ό μ €μž₯ 디렉토리
MAX_CONCURRENT_SCANS 2 λ™μ‹œ μŠ€μΊ” μ΅œλŒ€ 수
DEFAULT_TIMEOUT_SEC 600 μŠ€μΊ” νƒ€μž„μ•„μ›ƒ
OFFLINE_MODE false DB μžλ™ λ‹€μš΄λ‘œλ“œ λΉ„ν™œμ„±ν™”

λ³΄μ•ˆ 고렀사항

  1. Path Traversal λ°©μ§€: λͺ¨λ“  κ²½λ‘œλŠ” SCAN_ROOT ν•˜μœ„λ‘œ μ œν•œ
  2. λ™μ‹œ μ‹€ν–‰ μ œν•œ: MAX_CONCURRENT_SCANS둜 λ¦¬μ†ŒμŠ€ 보호
  3. μš”μ²­ 크기 μ œν•œ: MAX_REQUEST_SIZE_MB둜 λŒ€μš©λŸ‰ μš”μ²­ 차단
  4. λͺ…λ Ή μ£Όμž… λ°©μ§€: λͺ¨λ“  subprocess ν˜ΈμΆœμ€ shell=False
  5. λΉ„λ£¨νŠΈ μ‹€ν–‰: Docker μ»¨ν…Œμ΄λ„ˆλŠ” μ „μš© trivy μ‚¬μš©μžλ‘œ μ‹€ν–‰

λΌμ΄μ„ μŠ€

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published