5.8 KiB
5.8 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| devsec-container-scanning | Container Scanning — Trivy / Grype / 정책 | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
Container Scanning
Image 안 vulnerable lib → exploit. Trivy / Grype / Docker Scout / Snyk 가 CVE 검사. Distroless / Chainguard / Alpine 작은 base + multi-stage = 작은 attack surface.
📖 핵심 개념
- CVE: 알려진 취약점.
- Base image: 작을수록 좋음.
- Multi-stage: build 에 사용한 도구 prod 안 안 옴.
- Distroless: shell / package manager 없는 image.
💻 코드 패턴
Trivy (가장 인기)
# Image 검사
trivy image myapp:latest
# Severity 필터
trivy image --severity HIGH,CRITICAL myapp:latest
# JSON 출력 (CI)
trivy image --format json --output report.json myapp:latest
# IaC 검사
trivy config terraform/
# Filesystem (Dockerfile 빌드 전)
trivy fs --scanners vuln,secret,misconfig .
CI 통합
# .github/workflows/security.yml
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
exit-code: '1'
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: 'trivy-results.sarif' }
Grype (alternative)
grype myapp:latest
grype dir:./
grype --output json --file report.json myapp:latest
Docker Scout
docker scout cves myapp:latest
docker scout recommendations myapp:latest # base image 권장
Multi-stage Dockerfile
# Build stage — 큰 toolchain
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime stage — 작고 안전
FROM node:20-alpine
RUN addgroup -g 1001 -S nodejs && adduser -S app -u 1001
WORKDIR /app
COPY --from=builder --chown=app:nodejs /app/dist ./dist
COPY --from=builder --chown=app:nodejs /app/node_modules ./node_modules
USER app
EXPOSE 3000
CMD ["node", "dist/index.js"]
Distroless (가장 작고 안전)
FROM node:20 AS builder
# build 작업
FROM gcr.io/distroless/nodejs20-debian12
COPY --from=builder /app/dist /app/dist
COPY --from=builder /app/node_modules /app/node_modules
WORKDIR /app
USER nonroot
CMD ["dist/index.js"]
→ Shell 없음. Exploit 어려움.
Chainguard images (modern)
FROM cgr.dev/chainguard/node:latest
# 매일 패치, 최소 CVE
Alpine vs Debian
Alpine: ~5MB, musl libc — 일부 native module 호환 X
Debian slim: ~80MB, glibc — 호환성 좋음
Distroless: ~50MB, 매우 안전
Chainguard: 0 CVE 목표
.dockerignore
node_modules
.git
.env
*.log
coverage
.next
.cache
dist
→ 빌드 context 작게 + secret leak 방지.
Secrets in build (안전)
# ❌ ENV 에 secret
ENV API_KEY=secret
# ❌ ARG 에 secret 도 layer 에 보임
ARG API_KEY
RUN echo $API_KEY > /tmp/key
# ✅ Build secret (BuildKit)
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm install
docker build --secret id=npmrc,src=$HOME/.npmrc .
SBOM 생성 (Software Bill of Materials)
# Trivy
trivy image --format spdx-json --output sbom.json myapp:latest
# Syft
syft myapp:latest -o spdx-json > sbom.json
# 또는 Docker scout
docker scout sbom myapp:latest
→ Compliance / supply chain.
Vulnerability database 업데이트
trivy image --download-db-only
CI 매번 자동 download.
정책 (OPA / Kyverno)
# Kubernetes admission — 위험 image 거부
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: { name: disallow-critical-cves }
spec:
validationFailureAction: Enforce
rules:
- name: scan
match: { resources: { kinds: [Pod] } }
validate:
message: "Image has CRITICAL CVEs"
pattern:
spec:
containers:
- image: "!*:latest" # 또는 trivy + admission webhook
Daily rebuild (security patch)
# Schedule — base image 패치 적용
on:
schedule: [{ cron: '0 6 * * *' }]
jobs:
rebuild:
steps:
- run: docker pull node:20-alpine # latest base
- run: docker build -t myapp:nightly .
- run: trivy image --exit-code 1 --severity CRITICAL myapp:nightly
- if: success()
run: docker push registry/myapp:nightly
Image signing (Sigstore / cosign)
cosign sign --key cosign.key registry/myapp:v1
cosign verify --key cosign.pub registry/myapp:v1
→ Supply chain attack 방어.
Allowed registries (admission)
prod 만 trusted registry: company.io/...
public docker.io 차단 / proxy
🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| OSS / 무료 | Trivy / Grype |
| Docker 친화 | Docker Scout |
| Enterprise | Snyk / Aqua / Sysdig |
| 최소 attack surface | Distroless / Chainguard |
| 규제 / SBOM | Syft + cosign |
| Quick start | Alpine multi-stage |
❌ 안티패턴
- Latest tag prod: 추적 불가. semver.
- Root user: container escape 시 host 권한.
- 모든 거 한 stage: 큰 image + build 도구 노출.
- Secret in image layer: leak.
- Scan 안 함: CVE 모름.
- CRITICAL ignore: scan 의미 없음.
- Base 안 update: 옛 patch 가 누적.
- Daily rebuild 안: 새 CVE 패치 안 됨.
🤖 LLM 활용 힌트
- Trivy + multi-stage + non-root + distroless 4종.
- Daily rebuild + signing.
- SBOM 가 compliance 표준.