[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
---
|
||||
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]]
|
||||
Reference in New Issue
Block a user