Files
2nd/10_Wiki/Topics/Coding/DevSec_Container_Scanning.md
T
2026-05-09 21:08:02 +09:00

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
devsecops
container
security
vibe-coding
language applicable_to
Docker / CI
DevOps
Trivy
Grype
Snyk Container
Docker Scout
base image
distroless

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 표준.

🔗 관련 문서