259 lines
5.8 KiB
Markdown
259 lines
5.8 KiB
Markdown
---
|
|
id: devsec-container-scanning
|
|
title: Container Scanning — Trivy / Grype / 정책
|
|
category: Coding
|
|
status: draft
|
|
source_trust_level: B
|
|
verification_status: conceptual
|
|
created_at: 2026-05-09
|
|
updated_at: 2026-05-09
|
|
tags: [devsecops, container, security, vibe-coding]
|
|
tech_stack: { language: "Docker / CI", applicable_to: ["DevOps"] }
|
|
applied_in: []
|
|
aliases: [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 (가장 인기)
|
|
```bash
|
|
# 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 통합
|
|
```yaml
|
|
# .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)
|
|
```bash
|
|
grype myapp:latest
|
|
grype dir:./
|
|
grype --output json --file report.json myapp:latest
|
|
```
|
|
|
|
### Docker Scout
|
|
```bash
|
|
docker scout cves myapp:latest
|
|
docker scout recommendations myapp:latest # base image 권장
|
|
```
|
|
|
|
### Multi-stage Dockerfile
|
|
```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 (가장 작고 안전)
|
|
```dockerfile
|
|
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)
|
|
```dockerfile
|
|
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 (안전)
|
|
```dockerfile
|
|
# ❌ 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
|
|
```
|
|
|
|
```bash
|
|
docker build --secret id=npmrc,src=$HOME/.npmrc .
|
|
```
|
|
|
|
### SBOM 생성 (Software Bill of Materials)
|
|
```bash
|
|
# 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 업데이트
|
|
```bash
|
|
trivy image --download-db-only
|
|
```
|
|
|
|
CI 매번 자동 download.
|
|
|
|
### 정책 (OPA / Kyverno)
|
|
```yaml
|
|
# 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)
|
|
```yaml
|
|
# 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)
|
|
```bash
|
|
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 표준.
|
|
|
|
## 🔗 관련 문서
|
|
- [[DevOps_Kubernetes_Basics]]
|
|
- [[DevSec_Supply_Chain]]
|
|
- [[DevOps_CI_CD_Pipeline_Patterns]]
|