Skip to content

Latest commit

 

History

History
329 lines (246 loc) · 8.01 KB

File metadata and controls

329 lines (246 loc) · 8.01 KB

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