목차
1. 컨테이너 위협 모델: 공격 표면 이해
컨테이너 환경은 기존 VM 기반 인프라와 다른 고유한 위협 표면을 가진다. 이미지 취약점, 설정 오류, 런타임 공격, 공급망 위협까지 다층적 보안 전략이 필요하다.
1.1 컨테이너 공격 표면
컨테이너 보안 레이어:
┌─────────────────────────────────────────────────┐
│ Layer 6: 공급망 (Supply Chain) │
│ - 베이스 이미지 오염, 의존성 변조, CI/CD 파이프라인 │
├─────────────────────────────────────────────────┤
│ Layer 5: 오케스트레이션 (Kubernetes) │
│ - RBAC 미설정, API 서버 노출, etcd 미암호화 │
├─────────────────────────────────────────────────┤
│ Layer 4: 네트워크 │
│ - 네트워크 정책 미설정, 서비스 메시 미적용 │
├─────────────────────────────────────────────────┤
│ Layer 3: 런타임 │
│ - 컨테이너 탈출, 권한 상승, 암호화폐 채굴 │
├─────────────────────────────────────────────────┤
│ Layer 2: 이미지 │
│ - CVE 취약점, 하드코딩된 시크릿, 과도한 패키지 │
├─────────────────────────────────────────────────┤
│ Layer 1: 호스트 OS / 컨테이너 런타임 │
│ - 커널 취약점, Docker 소켓 노출, runc 취약점 │
└─────────────────────────────────────────────────┘
1.2 주요 공격 벡터
1. 이미지 취약점 악용:
공격자 → 공개 이미지의 알려진 CVE 악용 → 컨테이너 침투
2. 공급망 공격:
공격자 → 베이스 이미지/라이브러리에 악성코드 주입 → 다운스트림 오염
3. 런타임 공격:
공격자 → 취약한 앱 악용 → 컨테이너 탈출 → 호스트 접근
4. 설정 오류 악용:
공격자 → 과도한 권한/미설정 네트워크 정책 → 횡적 이동
2. 이미지 보안: 안전한 컨테이너 이미지 구축
2.1 최소 베이스 이미지 선택
# BAD: 풀 이미지 사용 (200MB+, 수백 개 CVE 가능)
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]
# GOOD: Distroless 이미지 (최소한의 바이너리만 포함)
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
FROM gcr.io/distroless/python3-debian12
COPY /app /app
COPY /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
WORKDIR /app
CMD ["app.py"]
2.2 Chainguard 이미지
# Chainguard Images: 매일 리빌드, 제로 CVE 목표
FROM cgr.dev/chainguard/python:latest-dev AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
FROM cgr.dev/chainguard/python:latest
COPY /app /app
COPY /home/nonroot/.local/lib/python3.12/site-packages /home/nonroot/.local/lib/python3.12/site-packages
WORKDIR /app
ENTRYPOINT ["python", "app.py"]
2.3 멀티스테이지 빌드와 보안
# Go 앱 멀티스테이지 빌드
FROM golang:1.22-alpine AS builder
# 보안: 빌드 시에만 필요한 도구 설치
RUN apk add --no-cache git ca-certificates
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# 보안: 정적 바이너리 빌드 (CGO 비활성화)
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-w -s" -o /app/server ./cmd/server
# 최종 이미지: scratch (완전히 비어있는 이미지)
FROM scratch
# 보안: 비 root 사용자
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY /etc/passwd /etc/passwd
COPY /app/server /server
USER 65534:65534
ENTRYPOINT ["/server"]
2.4 Dockerfile 보안 베스트 프랙티스
# 보안 강화된 Dockerfile 예시
FROM node:20-slim AS builder
# 보안: 비 root 사용자 생성
RUN groupadd -r appuser && useradd -r -g appuser -d /app appuser
WORKDIR /app
# 보안: package.json만 먼저 복사 (레이어 캐시 활용)
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile --production
COPY . .
RUN yarn build
# 프로덕션 이미지
FROM node:20-slim
# 보안: 비 root 사용자
RUN groupadd -r appuser && useradd -r -g appuser -d /app appuser
WORKDIR /app
# 보안: 필요한 파일만 복사
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
COPY /app/package.json ./
# 보안: 비 root로 실행
USER appuser
# 보안: 읽기 전용 파일시스템 호환
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
3. 이미지 스캐닝: 취약점 탐지
3.1 스캐닝 도구 비교
| 도구 | 라이센스 | 특징 | CI/CD 통합 | SBOM 생성 |
|---|---|---|---|---|
| Trivy | Apache 2.0 | 종합 스캐너(이미지/IaC/시크릿) | 우수 | 지원 |
| Grype | Apache 2.0 | 빠른 취약점 스캔 | 우수 | syft 연동 |
| Docker Scout | 프리미엄 | Docker Desktop 통합 | Docker Hub | 지원 |
| Snyk Container | 프리미엄 | 수정 권고 우수 | 우수 | 지원 |
3.2 Trivy 사용법
# 이미지 스캔
trivy image nginx:1.25
# 심각도 필터링
trivy image --severity HIGH,CRITICAL nginx:1.25
# SARIF 형식 출력 (GitHub Security 연동)
trivy image --format sarif --output trivy-results.sarif nginx:1.25
# 시크릿 스캔
trivy image --scanners secret myapp:latest
# IaC 스캔 (Dockerfile, Kubernetes YAML)
trivy config .
# SBOM 생성
trivy image --format cyclonedx --output sbom.json nginx:1.25
# .trivyignore - 특정 CVE 무시
# 이유를 주석으로 기록
# CVE-2023-xxxx: 우리 환경에서는 영향 없음 (해당 기능 미사용)
CVE-2023-xxxx
3.3 Grype와 syft
# syft로 SBOM 생성
syft packages nginx:1.25 -o cyclonedx-json > sbom.json
# Grype로 SBOM 기반 스캔
grype sbom:./sbom.json
# Grype 직접 이미지 스캔
grype nginx:1.25
# 심각도 임계값 설정 (CI/CD에서 사용)
grype nginx:1.25 --fail-on critical
3.4 CI/CD 통합 스캐닝
# .github/workflows/image-scan.yml
name: Container Image Scan
on:
push:
branches: [main]
pull_request:
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:ci .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:ci'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Run Grype scan
uses: anchore/scan-action@v4
with:
image: 'myapp:ci'
fail-build: true
severity-cutoff: 'high'
4. 이미지 서명: Sigstore와 cosign
4.1 Sigstore 생태계
Sigstore 구성 요소:
┌──────────────────────────────────────────────────┐
│ cosign │
│ - 컨테이너 이미지/아티팩트 서명 및 검증 │
│ - 키리스(Keyless) 서명 지원 (OIDC 기반) │
├──────────────────────────────────────────────────┤
│ Rekor │
│ - 불변 투명성 로그 (Transparency Log) │
│ - 모든 서명 기록을 공개적으로 저장 │
├──────────────────────────────────────────────────┤
│ Fulcio │
│ - 단기 인증서 발급 (Certificate Authority) │
│ - OIDC 토큰을 X.509 인증서로 변환 │
└──────────────────────────────────────────────────┘
4.2 cosign으로 이미지 서명
# 키 쌍 생성
cosign generate-key-pair
# 이미지 서명
cosign sign --key cosign.key myregistry.com/myapp:v1.0
# 이미지 서명 검증
cosign verify --key cosign.pub myregistry.com/myapp:v1.0
# 키리스 서명 (CI/CD에서 권장)
# OIDC 토큰으로 자동 인증 (GitHub Actions, GitLab CI)
cosign sign myregistry.com/myapp:v1.0
# 키리스 검증
cosign verify \
--certificate-identity "https://github.com/myorg/myapp/.github/workflows/build.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
myregistry.com/myapp:v1.0
4.3 GitHub Actions에서 키리스 서명
# .github/workflows/sign-image.yml
name: Build, Sign, and Push
on:
push:
tags: ['v*']
permissions:
contents: read
packages: write
id-token: write # 키리스 서명에 필요
jobs:
build-sign-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: sigstore/cosign-installer@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: "${{ github.actor }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: "ghcr.io/${{ github.repository }}:${{ github.ref_name }}"
- name: Sign the image (keyless)
run: |
cosign sign --yes \
"ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}"
4.4 Kubernetes Admission Controller로 서명 검증
# Kyverno 정책: 서명된 이미지만 허용
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/myorg/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/myorg/*/.github/workflows/*@refs/heads/main"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: "https://rekor.sigstore.dev"
5. SBOM (Software Bill of Materials)
5.1 SBOM 포맷 비교
CycloneDX:
- OWASP 프로젝트
- 보안에 초점 (취약점, 라이센스)
- JSON, XML 포맷
- VEX (Vulnerability Exploitability eXchange) 지원
SPDX:
- Linux Foundation 프로젝트
- 라이센스 준수에 초점
- JSON, RDF, Tag-Value 포맷
- ISO/IEC 5962:2021 국제 표준
5.2 syft로 SBOM 생성
# CycloneDX 포맷으로 SBOM 생성
syft packages myapp:latest -o cyclonedx-json > sbom-cyclonedx.json
# SPDX 포맷으로 SBOM 생성
syft packages myapp:latest -o spdx-json > sbom-spdx.json
# 디렉토리 스캔
syft dir:./my-project -o cyclonedx-json > project-sbom.json
# SBOM을 이미지에 첨부 (cosign + SBOM)
cosign attach sbom --sbom sbom-cyclonedx.json myregistry.com/myapp:v1.0
# SBOM attestation 생성
cosign attest --predicate sbom-cyclonedx.json \
--type cyclonedx \
myregistry.com/myapp:v1.0
5.3 SBOM 기반 취약점 관리
# SBOM에서 취약점 스캔
grype sbom:./sbom-cyclonedx.json
# 특정 패키지 조회
syft packages myapp:latest | grep log4j
# 라이센스 분석
syft packages myapp:latest -o json | \
jq '.artifacts[].licenses[].value' | sort | uniq -c | sort -rn
6. Pod Security Standards
6.1 보안 수준 비교
Privileged (특권):
- 제한 없음
- 알려진 권한 상승 허용
- 시스템 데몬, CNI 플러그인용
Baseline (기본):
- 알려진 권한 상승 방지
- hostNetwork, hostPID, hostIPC 차단
- 특권 컨테이너 차단
- 대부분의 워크로드에 적합
Restricted (제한):
- 최소 권한 원칙 적용
- 비 root 강제
- 모든 capability 삭제
- seccomp 프로필 필수
- 보안이 중요한 워크로드용
6.2 Pod Security Admission 설정
# Namespace에 Pod Security Standards 적용
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# Restricted 수준 강제
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# Restricted 수준 경고
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
# Restricted 수준 감사
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
6.3 보안 강화된 Pod 명세
# Restricted 수준을 만족하는 Pod 명세
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
# 보안: 서비스 어카운트 토큰 자동 마운트 비활성화
automountServiceAccountToken: false
securityContext:
# 보안: 비 root 그룹으로 실행
runAsGroup: 1000
fsGroup: 1000
# 보안: Seccomp 프로필 적용
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: ghcr.io/myorg/secure-app:v1.0
ports:
- containerPort: 8080
protocol: TCP
securityContext:
# 보안: 비 root 사용자로 실행
runAsNonRoot: true
runAsUser: 1000
# 보안: 읽기 전용 루트 파일시스템
readOnlyRootFilesystem: true
# 보안: 권한 상승 차단
allowPrivilegeEscalation: false
# 보안: 모든 capability 삭제
capabilities:
drop:
- ALL
# 임시 쓰기 디렉토리
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: tmp
emptyDir:
sizeLimit: 100Mi
- name: cache
emptyDir:
sizeLimit: 200Mi
7. 네트워크 정책 (Network Policy)
7.1 기본 거부 정책
# 모든 인그레스/이그레스 차단 (기본 거부)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
7.2 세밀한 네트워크 정책
# API 서비스: 특정 소스에서만 인그레스 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-service-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-service
policyTypes:
- Ingress
- Egress
ingress:
# 인그레스 컨트롤러에서만 허용
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
podSelector:
matchLabels:
app: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
# 데이터베이스 접근 허용
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# DNS 허용
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
7.3 Cilium 네트워크 정책
# Cilium L7 네트워크 정책 (HTTP 경로 기반)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-service
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/v1/products"
- method: "POST"
path: "/api/v1/orders"
8. 런타임 보안: Falco와 Tetragon
8.1 Falco 규칙
# Falco 커스텀 규칙
- rule: Detect Reverse Shell
desc: 컨테이너에서 리버스 셸 연결 시도 탐지
condition: >
evt.type=connect and
evt.dir=< and
container and
fd.typechar=4 and
fd.rip != "127.0.0.1" and
proc.name in (bash, sh, zsh, dash, csh)
output: >
리버스 셸 탐지 (user=%user.name command=%proc.cmdline
connection=%fd.name container=%container.name
image=%container.image.repository)
priority: CRITICAL
tags: [network, shell, mitre_execution]
- rule: Detect Cryptomining
desc: 컨테이너에서 암호화폐 채굴 프로세스 탐지
condition: >
spawned_process and
container and
(proc.name in (xmrig, minerd, minergate, cpuminer) or
proc.cmdline contains "stratum+tcp" or
proc.cmdline contains "cryptonight")
output: >
암호화폐 채굴 탐지 (user=%user.name command=%proc.cmdline
container=%container.name image=%container.image.repository)
priority: CRITICAL
tags: [crypto, mining, mitre_resource_hijacking]
- rule: Sensitive File Access
desc: 민감한 파일 접근 탐지
condition: >
open_read and
container and
(fd.name startswith /etc/shadow or
fd.name startswith /etc/passwd or
fd.name startswith /proc/self/environ or
fd.name startswith /run/secrets)
output: >
민감 파일 접근 (user=%user.name file=%fd.name
command=%proc.cmdline container=%container.name)
priority: WARNING
tags: [filesystem, mitre_credential_access]
8.2 Falco Helm 배포
# Falco 설치
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco --create-namespace \
--set falcosidekick.enabled=true \
--set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/xxx" \
--set falcosidekick.config.slack.minimumpriority=warning \
--set driver.kind=ebpf
8.3 Tetragon eBPF 정책
# Tetragon 정책: 프로세스 실행 모니터링
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: monitor-process-execution
spec:
kprobes:
- call: "security_bprm_check"
syscall: false
args:
- index: 0
type: "linux_binprm"
selectors:
- matchBinaries:
- operator: "In"
values:
- "/bin/bash"
- "/bin/sh"
- "/usr/bin/curl"
- "/usr/bin/wget"
matchNamespaces:
- namespace: Mnt
operator: NotIn
values:
- "host_mnt_ns"
---
# Tetragon 정책: 네트워크 연결 모니터링
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: monitor-network-connections
spec:
kprobes:
- call: "tcp_connect"
syscall: false
args:
- index: 0
type: "sock"
selectors:
- matchArgs:
- index: 0
operator: "NotDAddr"
values:
- "127.0.0.1"
- "10.0.0.0/8"
9. 시크릿 관리
9.1 External Secrets Operator
# SecretStore 설정 (AWS Secrets Manager)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets
namespace: production
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
---
# ExternalSecret 정의
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: prod/database
property: username
- secretKey: password
remoteRef:
key: prod/database
property: password
9.2 Vault CSI Provider
# Vault SecretProviderClass
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-db-creds
namespace: production
spec:
provider: vault
parameters:
vaultAddress: "https://vault.example.com"
roleName: "app-role"
objects: |
- objectName: "db-username"
secretPath: "secret/data/prod/database"
secretKey: "username"
- objectName: "db-password"
secretPath: "secret/data/prod/database"
secretKey: "password"
---
# Pod에서 사용
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
serviceAccountName: app-sa
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secrets
mountPath: "/mnt/secrets"
readOnly: true
volumes:
- name: secrets
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: vault-db-creds
10. SLSA 프레임워크
10.1 SLSA 레벨
SLSA Level 1 - Provenance:
- 빌드 프로세스가 문서화됨
- 자동화된 빌드
SLSA Level 2 - Build Service:
- 호스팅된 빌드 서비스 사용
- 서명된 provenance 생성
- 버전 관리 소스
SLSA Level 3 - Build Integrity:
- 격리된 빌드 환경
- 변조 방지 provenance
- 소스 무결성 보장
SLSA Level 4 - Dependencies:
- 모든 종속성에 대한 재귀적 보증
- 재현 가능한 빌드
- (현재 이론적 단계)
10.2 SLSA Provenance 생성
# GitHub Actions에서 SLSA Provenance 생성
name: SLSA Build
on:
push:
tags: ['v*']
permissions:
contents: read
packages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
outputs:
digest: "${{ steps.build.outputs.digest }}"
steps:
- uses: actions/checkout@v4
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: "ghcr.io/${{ github.repository }}:${{ github.ref_name }}"
provenance:
needs: build
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: "ghcr.io/${{ github.repository }}"
digest: "${{ needs.build.outputs.digest }}"
secrets:
registry-username: "${{ github.actor }}"
registry-password: "${{ secrets.GITHUB_TOKEN }}"
11. CI/CD 보안 파이프라인
11.1 전체 파이프라인 구성
보안 CI/CD 파이프라인:
┌─────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│Build│ → │ Scan │ → │ Sign │ → │Attest│ → │Verify│ → │Deploy│
└─────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘
│ │ │ │ │ │
│ │ │ │ │ │
빌드 취약점 cosign SBOM Kyverno 서명 검증
이미지 스캔 서명 attestation 정책 후 배포
Trivy SLSA 검증
Grype provenance
11.2 CIS 벤치마크와 Kubescape
# kube-bench: CIS Kubernetes Benchmark 실행
kube-bench run --targets master,node
# Kubescape: NSA, MITRE, CIS 프레임워크 스캔
kubescape scan framework cis-v1.23 --exclude-namespaces kube-system
# 특정 컨트롤 스캔
kubescape scan control C-0002 --namespace production
# Kubescape YAML 스캔
kubescape scan .
12. 퀴즈
다음 퀴즈로 이 글에서 다룬 컨테이너 보안에 대한 이해를 점검해 보자.
Q1. 이미지 보안
질문: Distroless 이미지와 Alpine 이미지의 차이점은 무엇인가?
정답: Distroless 이미지는 셸(bash/sh)과 패키지 매니저가 없는 최소 이미지다. Alpine은 musl libc 기반의 경량 Linux 배포판으로, 셸과 패키지 매니저(apk)를 포함한다.
Distroless는 공격 표면이 더 작지만 디버깅이 어렵다. Alpine은 디버깅은 가능하지만 musl libc 호환성 문제가 발생할 수 있다. 프로덕션에서는 Distroless나 Chainguard 이미지를 권장하고, 디버깅이 필요한 경우 debug 태그 변종을 사용한다.
Q2. Sigstore 키리스 서명
질문: cosign 키리스 서명이 기존 키 기반 서명보다 CI/CD에서 선호되는 이유는 무엇인가?
정답: 키리스 서명은 OIDC 토큰(예: GitHub Actions의 워크플로 ID 토큰)을 사용하므로, 장기 비밀키를 관리하고 보호할 필요가 없다.
Fulcio가 OIDC 토큰을 단기 인증서로 변환하고, Rekor 투명성 로그에 서명이 기록된다. 키 순환, 키 유출, 키 보관 문제가 없어 CI/CD 환경에서 운영 부담이 크게 줄어든다.
Q3. Pod Security Standards
질문: Pod Security Standards의 Restricted 수준에서 반드시 충족해야 하는 보안 요구사항 3가지를 나열하시오.
정답:
- 비 root 사용자로 실행 (runAsNonRoot: true)
- 모든 Linux capability 삭제 (capabilities.drop: ALL)
- 권한 상승 차단 (allowPrivilegeEscalation: false)
추가적으로, seccomp 프로필 적용(RuntimeDefault 또는 Localhost), 읽기 전용 루트 파일시스템(readOnlyRootFilesystem: true)도 Restricted 수준의 권장 사항이다.
Q4. 런타임 보안
질문: Falco와 Tetragon의 아키텍처 차이를 설명하시오.
정답:
- Falco: 커널 모듈 또는 eBPF 드라이버로 시스템 콜을 캡처하고, 사용자 공간의 규칙 엔진에서 이벤트를 분석한다. 탐지(detection) 중심으로, 규칙에 매칭되면 알림을 생성한다.
- Tetragon: 순수 eBPF 기반으로 커널 수준에서 직접 정책을 실행한다. 탐지뿐만 아니라 차단(enforcement)도 가능하며, 프로세스 실행, 네트워크 연결, 파일 접근을 커널에서 직접 제어할 수 있다.
Q5. SLSA 프레임워크
질문: SLSA Level 3에서 요구하는 핵심 보안 속성 2가지는 무엇인가?
정답:
- 격리된 빌드 환경: 빌드가 다른 빌드와 격리된 환경에서 실행되어, 빌드 간 오염을 방지한다.
- 변조 방지(tamper-resistant) provenance: 빌드 시스템이 생성한 provenance를 빌드 자체가 수정할 수 없다. provenance는 빌드 서비스에 의해 서명되며, 소스와 빌드 프로세스의 무결성을 보장한다.
13. 참고 자료
- Trivy - https://aquasecurity.github.io/trivy/
- Sigstore (cosign, Rekor, Fulcio) - https://www.sigstore.dev/
- SLSA Framework - https://slsa.dev/
- Falco - https://falco.org/docs/
- Tetragon - https://tetragon.io/docs/
- Grype - https://github.com/anchore/grype
- syft - https://github.com/anchore/syft
- CycloneDX - https://cyclonedx.org/
- SPDX - https://spdx.dev/
- Kyverno - https://kyverno.io/docs/
- External Secrets Operator - https://external-secrets.io/
- Kubescape - https://kubescape.io/
- Chainguard Images - https://www.chainguard.dev/chainguard-images
- CIS Benchmarks - https://www.cisecurity.org/benchmark/kubernetes
이 글에서는 컨테이너 보안의 전체 라이프사이클을 다루었다. 이미지 보안(최소 베이스 이미지, 스캐닝), 서명 및 검증(Sigstore/cosign), SBOM, Pod Security Standards, 네트워크 정책, 런타임 보안(Falco/Tetragon), 시크릿 관리, SLSA 프레임워크, CI/CD 보안 파이프라인까지 포괄적으로 살펴보았다. 다층 방어(Defense in Depth) 전략을 채택하고, 보안을 개발 초기부터 CI/CD 파이프라인에 통합하는 것이 핵심이다.
현재 단락 (1/653)
컨테이너 환경은 기존 VM 기반 인프라와 다른 고유한 위협 표면을 가진다. 이미지 취약점, 설정 오류, 런타임 공격, 공급망 위협까지 다층적 보안 전략이 필요하다.