Skip to content
Published on

컨테이너 보안 & 공급망 보안 완전 가이드 2025: 이미지 스캐닝, Sigstore, SBOM, 런타임 보안

Authors

목차

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 --from=builder /app /app
COPY --from=builder /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 --from=builder /app /app
COPY --from=builder /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 --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /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 --from=builder --chown=appuser:appuser /app/dist ./dist
COPY --from=builder --chown=appuser:appuser /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appuser /app/package.json ./

# 보안: 비 root로 실행
USER appuser

# 보안: 읽기 전용 파일시스템 호환
ENV NODE_ENV=production

EXPOSE 3000
CMD ["node", "dist/index.js"]

3. 이미지 스캐닝: 취약점 탐지

3.1 스캐닝 도구 비교

도구라이센스특징CI/CD 통합SBOM 생성
TrivyApache 2.0종합 스캐너(이미지/IaC/시크릿)우수지원
GrypeApache 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가지를 나열하시오.

정답:

  1. 비 root 사용자로 실행 (runAsNonRoot: true)
  2. 모든 Linux capability 삭제 (capabilities.drop: ALL)
  3. 권한 상승 차단 (allowPrivilegeEscalation: false)

추가적으로, seccomp 프로필 적용(RuntimeDefault 또는 Localhost), 읽기 전용 루트 파일시스템(readOnlyRootFilesystem: true)도 Restricted 수준의 권장 사항이다.

Q4. 런타임 보안

질문: Falco와 Tetragon의 아키텍처 차이를 설명하시오.

정답:

  • Falco: 커널 모듈 또는 eBPF 드라이버로 시스템 콜을 캡처하고, 사용자 공간의 규칙 엔진에서 이벤트를 분석한다. 탐지(detection) 중심으로, 규칙에 매칭되면 알림을 생성한다.
  • Tetragon: 순수 eBPF 기반으로 커널 수준에서 직접 정책을 실행한다. 탐지뿐만 아니라 차단(enforcement)도 가능하며, 프로세스 실행, 네트워크 연결, 파일 접근을 커널에서 직접 제어할 수 있다.

Q5. SLSA 프레임워크

질문: SLSA Level 3에서 요구하는 핵심 보안 속성 2가지는 무엇인가?

정답:

  1. 격리된 빌드 환경: 빌드가 다른 빌드와 격리된 환경에서 실행되어, 빌드 간 오염을 방지한다.
  2. 변조 방지(tamper-resistant) provenance: 빌드 시스템이 생성한 provenance를 빌드 자체가 수정할 수 없다. provenance는 빌드 서비스에 의해 서명되며, 소스와 빌드 프로세스의 무결성을 보장한다.

13. 참고 자료

  1. Trivy - https://aquasecurity.github.io/trivy/
  2. Sigstore (cosign, Rekor, Fulcio) - https://www.sigstore.dev/
  3. SLSA Framework - https://slsa.dev/
  4. Falco - https://falco.org/docs/
  5. Tetragon - https://tetragon.io/docs/
  6. Grype - https://github.com/anchore/grype
  7. syft - https://github.com/anchore/syft
  8. CycloneDX - https://cyclonedx.org/
  9. SPDX - https://spdx.dev/
  10. Kyverno - https://kyverno.io/docs/
  11. External Secrets Operator - https://external-secrets.io/
  12. Kubescape - https://kubescape.io/
  13. Chainguard Images - https://www.chainguard.dev/chainguard-images
  14. CIS Benchmarks - https://www.cisecurity.org/benchmark/kubernetes

이 글에서는 컨테이너 보안의 전체 라이프사이클을 다루었다. 이미지 보안(최소 베이스 이미지, 스캐닝), 서명 및 검증(Sigstore/cosign), SBOM, Pod Security Standards, 네트워크 정책, 런타임 보안(Falco/Tetragon), 시크릿 관리, SLSA 프레임워크, CI/CD 보안 파이프라인까지 포괄적으로 살펴보았다. 다층 방어(Defense in Depth) 전략을 채택하고, 보안을 개발 초기부터 CI/CD 파이프라인에 통합하는 것이 핵심이다.