docker scout cves myapp:1.0
trivy image myapp:1.0
grype myapp:1.0
스캐너는 이미지 안 패키지 목록을 뽑아 CVE 데이터베이스와 대조한다
결과를 다루는 법
-
전부 0 으로 만들려 하지 않는다 — 현실적으로 불가능하다
-
Critical/High 부터, 그중 '실제로 쓰는 경로' 를 먼저 본다
- (설치돼 있지만 호출되지 않는 라이브러리의 CVE 도 많다)
-
대부분은 베이스 이미지를 최신으로 올리면 함께 해결된다
-
안 쓰는 패키지를 빼는 것이 가장 확실한 해결이다
- 그래서 크기 줄이기와 같은 문제다
-
CI 에 넣되 처음부터 빌드를 막지 않는다
- 기준선을 정하고 '새로 늘어난 것' 만 실패시키면 정착이 쉽다
SBOM
이미지에 무엇이 들었는지의 목록이다
docker buildx build --sbom=true --provenance=true --push .
Log4Shell 때 드러난 문제가 "우리가 무엇을 쓰는지 목록이 없다" 였다 SBOM 이 있으면 새 CVE 가 나왔을 때 영향 범위를 검색으로 찾는다 공급망 보안의 출발점이다
- provenance 는 '누가 언제 무엇으로 빌드했는가' 를 남긴다
- 이미지가 우리 파이프라인에서 나온 것인지 검증할 수 있다
기준선 — CIS Benchmark
CIS Docker Benchmark · CIS Kubernetes Benchmark 비상업적 용도로 PDF 를 무료로 받을 수 있다 (간단한 정보 입력 필요) 호스트·데몬·이미지·런타임 항목별 점검 기준을 제공한다
자동 점검
Docker Bench for Security 호스트·데몬 설정
kube-bench 쿠버네티스 클러스터
"무엇을 점검해야 하는지" 를 처음부터 만들 필요가 없다 기준선으로 시작해 조직에 맞게 예외를 정리하는 순서가 효율적이다
스캔만으로는 부족하다
-
스캐너가 못 잡는 것
- 잘못된 설정 (root 실행 · privileged · 소켓 마운트)
- 이미지에 박힌 비밀
- 애플리케이션 코드의 취약점
-
설정 검사(Docker Bench · 정책 엔진)와 비밀 스캔(gitleaks 류)을 함께 건다
-
스캔 통과가 곧 안전을 뜻하지 않는다
실무 파이프라인 형태
빌드 → SBOM 생성 → 스캔 → 서명 → 푸시
↓
신규 Critical 이면 실패
운영 중에도 주기적으로 다시 스캔한다
이미지는 그대로인데 새 CVE 가 발표되기 때문이다
"빌드 시점에 깨끗했다" 는 지금 안전하다는 뜻이 아니다
스캐너가 보는 것과 못 보는 것
-
본다 — OS 패키지 (apk · apt · yum)
- 언어 의존성 (package-lock.json · pom.xml · go.sum)
- 알려진 CVE 와의 대조
-
**못 본다 — 직접 넣은 바이너리 (패키지 매니저를 안 거친 것)**
- 벤더링된 소스
- 설정 문제
- 비즈니스 로직 취약점
-
"직접 받아서 넣은 바이너리" 가 스캔 사각지대다
-
가능하면 패키지 매니저를 거치거나 SBOM 에 수동으로 등록한다
오탐과 무시 규칙
실제로 쓰지 않는 경로의 CVE 는 대응 우선순위가 낮다
- trivy 는 .trivyignore 로 특정 CVE 를 제외할 수 있다
- 다만 '왜 무시했는지' 를 반드시 함께 적는다
- 무시 목록이 이유 없이 쌓이면 스캔 자체가 의미를 잃는다
- 만료일을 두는 것이 좋다 — 3개월 뒤 다시 판단한다
VEX(취약점 활용 가능성 문서)로 이 판단을 표준 형식으로 남기는 흐름도 있다
면접 함정
- ❌ "스캔에서 0이면 안전하다" → 설정 문제와 코드 취약점은 안 잡힌다.
- ❌ "빌드 때 스캔했으니 됐다" → 새 CVE는 나중에 발표된다. 주기적 재스캔이 필요하다.