SCA 스캔
프로젝트에서 사용하는 npm 패키지나 Docker 베이스 이미지에 보안 취약점이 있다면 어떻게 하시겠어요? SCA(Software Composition Analysis)는 컨테이너 이미지와 소프트웨어 의존성에 알려진 취약점(CVE)이 있는지 자동으로 분석해주는 기능입니다.
현대 소프트웨어는 수많은 외부 라이브러리에 의존합니다. 평균적으로 애플리케이션 코드의 80% 이상이 오픈소스 라이브러리로 구성됩니다. 이 라이브러리들 중 하나라도 보안 취약점이 있다면 전체 애플리케이션이 위험해질 수 있습니다. SCA는 이러한 숨겨진 위험을 자동으로 찾아줍니다.

개요
- 분석 대상: 컨테이너 이미지, 의존성 패키지
- 분석 엔진: Trivy (사용자에게는 단일 탐지 도구로 표시되며 도구 선택 UI 없음)
- 취약점 DB: NVD CVE 데이터베이스, Trivy DB 등
- 별도 스캔: 이미지 SBOM 및 라이선스 정보 (SCA에서 자동 생성되지 않으며 SBOM · 라이선스 탭에서 별도 실행)
백엔드 DB는 SCA 결과를 모두 tool_name='trivy'로 통합 적재합니다. 다만 UI는 각 항목의 실제 탐지 도구를 detected_by 필드로 구분 표시합니다. AST 백엔드가 Trivy와 Dependency-Check를 함께 실행해 합집합 머지하므로, 한 도구만 탐지한 항목은 '[도구명] 단독' 배지로, 두 도구가 모두 탐지한 항목은 '교차검증 (Trivy + Dependency-Check)' 배지로 표시됩니다. 사용자가 도구를 선택하는 토글은 제공되지 않습니다.
분석 대상
SCA는 다양한 유형의 패키지와 이미지를 분석합니다.
이미지 취약점
Docker 이미지에 포함된 모든 패키지를 분석합니다.
- OS 패키지: Alpine, Debian, Ubuntu 등의 시스템 패키지 (apt, apk로 설치된 패키지)
- 언어 패키지: npm, pip, maven, go 등 언어별 패키지 매니저로 설치된 패키지
- 베이스 이미지: Dockerfile의 FROM 절에 지정된 베이스 이미지 자체의 취약점
의존성 취약점
프로젝트의 의존성 파일을 분석합니다.
package-lock.json(Node.js)requirements.txt,Pipfile.lock(Python)pom.xml,build.gradle(Java)go.sum(Go)Gemfile.lock(Ruby)composer.lock(PHP)
package.json만으로는 실제 설치된 버전을 정확히 알 수 없습니다. package-lock.json 같은 lock 파일에는 실제 설치된 정확한 버전이 기록되어 있어, 취약점이 있는 버전을 정확하게 탐지할 수 있습니다.
Step 1: SCA 스캔 시작하기
- 사이드바의 "보안" 그룹 > [보안 분석] 메뉴를 클릭합니다.
- 페이지 상단의 카드 캐러셀에서 분석할 서비스를 선택합니다.
- SCA 탭을 선택합니다.
- 상단 트리거 바에서 분석할 이미지를 지정하고 스캔 시작 버튼을 클릭합니다.
/security?id={서비스ID}&area=sca URL로 진입하면 해당 서비스의 SCA 탭이 바로 열립니다.
Step 2: 스캔 대상 설정
2.1 이미지 선택 (2가지 방식)
분석할 컨테이너 이미지를 두 가지 방식 중 하나로 지정합니다.
- 빌드 이미지 Select 드롭다운: 해당 서비스에서 빌드된 이미지 목록에서 선택 (권장)
- 수동 입력: 전체 이미지 경로를 직접 입력 (예:
harbor.company.com/project/app:v1.2.3)
상단 이미지 테이블에서 선택한 이미지가 결과 영역과 연동되어, 여러 이미지가 있을 때 대상 이미지를 전환할 수 있습니다.
2.2 Registry 인증 자동 적용
- 선택한 이미지가 속한 레지스트리에 저장된 인증 정보가 있으면 자동으로 적용됩니다.
- 사용자가 별도로 자격증명을 입력할 필요 없이, 저장된 인증 정보가 백엔드로 자동 전송됩니다.
- 인증이 필요한 Private 레지스트리도 별도 입력 없이 곧바로 스캔할 수 있습니다.
VEX Hub 필터링은 사용자 UI에서 별도로 조정하지 않으며, 백엔드에서 기본값으로 항상 실행됩니다.
- VEX Hub 필터링 디폴트 ON
SBOM 생성과 라이선스 분석은 SCA(취약점) 스캔에서 자동으로 수행되지 않습니다. 이미지 SBOM은 별도의 SBOM 생성 요청(Syft)으로, 라이선스 분석은 SBOM · 라이선스 탭의 독립 스캔(Syft + ScanCode)으로 생성됩니다. 자세한 내용은 SBOM 생성 문서를 참조하세요.
Step 3: 스캔 실행
스캔이 시작되면 Trivy가 실행되고, AST 백엔드는 Dependency-Check를 병렬로 함께 실행합니다. 두 도구의 결과는 합집합으로 병합되며, 각 CVE에는 어떤 도구가 탐지했는지(detected_by 필드)가 기록됩니다. 진행률은 WebSocket을 통해 실시간으로 표시됩니다.
[1/4] Pulling image... ← 이미지 다운로드
[2/4] Scanning OS packages... ← OS 패키지 분석
[3/4] Scanning application packages... ← 애플리케이션 패키지 분석
[4/4] Applying VEX filters... ← VEX 적용
Scan completed! ← 완료
SCA 스캔은 SBOM이나 라이선스 정보를 자동으로 생성하지 않습니다. 이미지 SBOM (CycloneDX 1.6)과 라이선스 정보가 필요하면 SBOM · 라이선스 탭에서 별도의 스캔을 직접 실행해야 합니다. 자세한 내용은 SBOM 생성 문서를 참조하세요.
SBOM과 라이선스 영역이 하나로 통합되었으며, 라이선스 분석 결과는 license_analysis 테이블에 누적 저장됩니다. 라이선스 분석은 SBOM 생성 스캔 실행 시 옵션으로 함께 수행됩니다.
예상 스캔 시간
스캔 시간은 환경(이미지 크기, 네트워크 속도, 패키지 수, 취약점 DB 캐시 상태 등)에 따라 다릅니다. 아래 값은 일반적인 환경을 가정한 참고치입니다.
- 100MB 이하: 약 30초
- 100-500MB: 1-2분
- 500MB 이상: 2-5분
Step 4: 결과 확인
4.1 결과 요약
스캔이 완료되면 다음 정보를 한눈에 확인할 수 있습니다.
- 총 취약점: 탐지된 취약점의 총 개수
- 심각도 분포: Critical/High/Medium/Low별 취약점 수
- 수정 가능: 패키지 업데이트로 수정할 수 있는 취약점 수
- 탐지 도구: 각 항목에 실제 탐지 도구가 표시됩니다. 한 도구만 탐지한 항목은 '[도구명] 단독'(예: Trivy 단독, Dependency-Check 단독) 배지로, 두 도구가 모두 탐지한 항목은 '교차검증 (Trivy + Dependency-Check)' 배지로 표시됩니다(백엔드 저장은
tool_name='trivy'로 통합되지만 항목별detected_by로 출처를 구분). 모든 항목이 도구명을 명시하므로 어느 도구의 결과인지 추적 가능합니다.
4.2 카테고리별 결과 보기
각 취약점은 다음 상태로 분류 및 처리할 수 있습니다.
- open: 새로 발견된 미처리 항목
- resolved: 수정 완료
- false_positive: 오탐으로 확인됨
- accepted_risk: 위험 수용 (인지했으나 수정하지 않음)
4.3 취약점 상세
각 취약점을 클릭하면 다음 정보를 확인할 수 있습니다.
- CVE ID: 취약점의 고유 식별자 (예: CVE-2021-44228)
- 패키지명: 취약점이 있는 패키지 이름
- 현재 버전: 현재 설치된 버전
- 수정 버전: 취약점이 수정된 버전 (있는 경우)
- 심각도: CVSS 점수 기반 심각도
- 설명: 취약점에 대한 상세 설명
- 참조 링크: NVD, 공급사 보안 권고 등의 추가 정보
"수정 버전"이 표시된 취약점은 패키지를 업데이트하면 해결됩니다. 수정 버전이 없는 취약점보다 먼저 처리하면 빠르게 취약점 수를 줄일 수 있습니다.
Step 5: SCA 스캔 이력 보기
SCA는 매 스캔 결과를 누적하여 보관합니다. [보안 분석] 페이지에서 SCA 탭의 "스캔 이력" 섹션을 확인하면 다음을 볼 수 있습니다.
- 이미지 repo 별 부모 행: 이미지 저장소 단위로 그룹화되며, 최신 스캔의 심각도 카운트가 표시됩니다.
- 태그별 이력 펼치기: 부모 행을 펼치면 태그별 스캔 이력이 최신순으로 나열되고, 직전 스캔 대비 취약점 증감이 함께 표시됩니다.
- 스캔/재스캔 트리거: 각 행의 [스캔] / [재스캔] 버튼으로 해당 이미지에 대한 스캔을 바로 실행할 수 있습니다.
- 우선순위 배지: 현재 배포 중인 이미지와 최근 빌드된 이미지에는 배지가 표시되어, 어떤 이미지를 먼저 점검해야 하는지 쉽게 파악할 수 있습니다.
- "보는 중" 라벨: 선택된 이미지 행에는 눈 아이콘과 함께 파란색 "보는 중" 라벨이 표시되어, 결과 영역에 표시되고 있는 이미지를 시각적으로 명시합니다.
대시보드 및 보안 게이트의 위험도는 현재 배포된 이미지 기준으로만 계산됩니다. 이전 빌드나 미배포 이미지의 취약점은 현재 위험도에 반영되지 않으므로, 새로운 빌드를 배포하면 게이트 판정이 달라질 수 있습니다. 배포된 버전 추적 기능 도입으로 정확한 위험도 평가가 가능합니다.
VEX Hub 필터링 (백엔드 디폴트 ON)
VEX란?
VEX(Vulnerability Exploitability eXchange)는 특정 취약점이 실제로 해당 제품에 영향을 미치는지를 평가한 데이터입니다. 취약한 함수가 코드에 존재하더라도 실제로 그 함수가 호출되지 않으면 영향이 없습니다.
동작 방식
- KIOPS는 SCA 스캔 시 백엔드에서 VEX Hub 필터링을 디폴트로 활성화합니다.
- 사용자가 UI에서 VEX 필터를 켜고 끄는 토글은 제공되지 않습니다.
- VEX 판정 결과는 SBOM에 함께 기록됩니다.
필터링 상태
- Affected: 실제로 영향받음 - 조치가 필요합니다.
- Not Affected: 영향받지 않음 - VEX 판정에 의해 제외됩니다.
- Fixed: 이미 수정됨 - 최신 버전에서는 해결되었습니다.
- Suppressed: VEX 또는 사용자 처리에 의해 표시에서 제외된 항목
취약점 수정
패키지 업데이트
가장 일반적인 수정 방법은 취약점이 해결된 버전으로 패키지를 업데이트하는 것입니다.
- 스캔 결과에서 "수정 버전"을 확인합니다.
- 해당 버전으로 의존성 파일을 업데이트합니다.
# Node.js 예시
npm update lodash
# Python 예시
pip install --upgrade requests - 이미지를 다시 빌드합니다.
- 재스캔하여 취약점이 해결되었는지 확인합니다.
베이스 이미지 자체에 취약점이 많다면 더 최신 버전이나 다른 이미지로 변경하는 것이 효과적입니다. Alpine Linux는 최소한의 패키지만 포함하고 있어 취약점이 적은 경우가 많습니다.
# 취약한 버전
FROM node:16-alpine3.14
# 수정된 버전
FROM node:20-alpine3.19
문제 해결
스캔 실패
-
이미지 풀 실패: 저장된 레지스트리 자격증명이 만료되었거나 권한이 부족할 수 있습니다. 인증정보 설정에서 자격증명을 갱신하세요.
-
타임아웃: 이미지 크기가 너무 큰 경우 스캔이 타임아웃될 수 있습니다. 이미지 최적화를 고려하세요.
-
DB 업데이트 실패: 취약점 데이터베이스 업데이트에 실패한 경우입니다. 네트워크 연결을 확인하고 다시 시도해보세요.
과다 탐지 (너무 많은 취약점)
취약점이 너무 많이 탐지되어 관리가 어렵다면 확인된 항목을 false_positive 또는 accepted_risk로 분류하여 노이즈를 줄이세요. 베이스 이미지를 더 안전한 이미지로 교체하는 것도 효과적입니다.