Split View: 보안 취약점 조치 플레이북: OS 패키지 · 컨테이너 이미지 · 런타임 하드닝
보안 취약점 조치 플레이북: OS 패키지 · 컨테이너 이미지 · 런타임 하드닝
들어가며
보안 스캐너가 CVE 목록을 쏟아내면 어디서부터 손대야 할지 막막해진다. 중요한 것은 모든 취약점을 즉시 고치는 것이 아니라, 리스크를 기준으로 우선순위를 매기고, 체계적으로 조치하고, 재발을 방지하는 프로세스를 갖추는 것이다.
이 글에서는 OS 패키지 취약점 패치, 컨테이너 이미지 보안, 런타임 하드닝을 아우르는 실전 플레이북을 제시한다.
1. 취약점 대응 프로세스 개요
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 발견 │ → │ 분류 │ → │ 조치 │ → │ 검증 │ → │ 보고 │
│ Scanning │ │ Triage │ │ Remediate│ │ Verify │ │ Report │
└─────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
대응 SLA (권장)
| 심각도 | CVSS 점수 | 조치 기한 | 예시 |
|---|---|---|---|
| Critical | 9.0~10.0 | 24~72시간 | RCE, 인증 우회 |
| High | 7.0~8.9 | 7일 | 권한 상승, 정보 유출 |
| Medium | 4.0~6.9 | 30일 | XSS, 서비스 거부 |
| Low | 0.1~3.9 | 90일 또는 다음 정기 패치 | 정보 노출 (제한적) |
핵심 원칙: CVSS 점수만으로 판단하지 말고, Exploit 가능 여부(EPSS), 인터넷 노출 여부, 영향받는 자산의 중요도를 종합 판단한다.
2. OS 패키지 취약점 관리
2.1 취약점 스캔
# RHEL / Rocky - 보안 업데이트 확인
dnf updateinfo list security
dnf updateinfo list --sec-severity=Critical
dnf updateinfo info RHSA-2026:1234
# Ubuntu - 보안 업데이트 확인
apt update
apt list --upgradable 2>/dev/null | grep -i security
# 설치된 패키지의 CVE 확인 (Trivy)
trivy rootfs --severity CRITICAL,HIGH /
# OpenSCAP 스캔 (컴플라이언스)
oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis \
--results results.xml \
--report report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
2.2 패치 적용 절차
#!/usr/bin/env bash
# patch-os.sh - OS 보안 패치 적용 스크립트
set -euo pipefail
LOG_FILE="/var/log/security-patch-$(date +%Y%m%d).log"
SNAPSHOT_NAME="pre-patch-$(date +%Y%m%d-%H%M%S)"
log() { printf '[%s] %s\n' "$(date +%T)" "$1" | tee -a "$LOG_FILE"; }
# 1단계: 스냅샷/백업
log "=== 패치 시작 ==="
log "스냅샷 생성: $SNAPSHOT_NAME"
# LVM 스냅샷 (해당 시)
# lvcreate -L 10G -s -n "$SNAPSHOT_NAME" /dev/vg0/root
# 2단계: 현재 상태 기록
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /tmp/packages-before.txt
# 3단계: 보안 업데이트만 적용
log "보안 업데이트 적용 중..."
if command -v dnf &>/dev/null; then
dnf update --security -y 2>&1 | tee -a "$LOG_FILE"
elif command -v apt-get &>/dev/null; then
apt-get update
apt-get upgrade -y -o Dpkg::Options::="--force-confold" 2>&1 | tee -a "$LOG_FILE"
fi
# 4단계: 변경된 패키지 목록
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /tmp/packages-after.txt
diff /tmp/packages-before.txt /tmp/packages-after.txt > /tmp/packages-diff.txt || true
log "변경된 패키지:"
cat /tmp/packages-diff.txt | tee -a "$LOG_FILE"
# 5단계: 서비스 재시작 필요 여부 확인
if command -v needs-restarting &>/dev/null; then
log "재시작 필요 서비스:"
needs-restarting -s 2>&1 | tee -a "$LOG_FILE"
if needs-restarting -r 2>&1 | grep -q "Reboot is required"; then
log "WARNING: 커널 업데이트로 리부팅 필요"
fi
fi
log "=== 패치 완료 ==="
2.3 자동 보안 업데이트 설정
RHEL / Rocky
# dnf-automatic 설치·설정
dnf install -y dnf-automatic
# /etc/dnf/automatic.conf
# [commands]
# apply_updates = yes
# upgrade_type = security # 보안 업데이트만
systemctl enable --now dnf-automatic-install.timer
Ubuntu
# unattended-upgrades 설정
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades
# Unattended-Upgrade::Allowed-Origins {
# "${distro_id}:${distro_codename}-security";
# };
# Unattended-Upgrade::Automatic-Reboot "false";
# Unattended-Upgrade::Mail "admin@example.com";
2.4 패치 관리 체크리스트
- 보안 업데이트 알림 채널 구독 (RHSA, USN, CVE 메일링 리스트)
- 주간 취약점 스캔 자동화
- 스테이징 → 프로덕션 패치 파이프라인 구축
- 패치 적용 전 스냅샷/백업 필수
- 패치 후 서비스 헬스체크 자동화
- 커널 업데이트 시 재부팅 일정 수립
- 패치 이력·감사 로그 보존 (최소 1년)
3. 컨테이너 이미지 보안
3.1 이미지 스캔 도구 비교
| 도구 | 라이선스 | 특징 | CI/CD 통합 |
|---|---|---|---|
| Trivy | OSS (Apache-2.0) | OS + 언어 패키지 + IaC + Secret | GitHub Actions, GitLab CI |
| Grype | OSS (Apache-2.0) | SBOM 기반 스캔 | CLI 중심 |
| Snyk Container | 상용 (무료 플랜) | 개발자 친화적 Fix PR | 대부분 CI |
| Prisma Cloud | 상용 | 전체 CNAPP | 엔터프라이즈 CI |
| AWS ECR Scanning | AWS 포함 | Inspector 기반 | AWS 네이티브 |
3.2 Trivy 실전 사용
# 이미지 스캔 (Critical + High만)
trivy image --severity CRITICAL,HIGH myapp:latest
# SBOM 생성
trivy image --format spdx-json -o sbom.json myapp:latest
# 취약점이 있으면 빌드 실패 (CI용)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
# .trivyignore - 허용된 취약점 (예외 처리)
# CVE-2024-XXXX # 해당 코드 경로 미사용, 2026-04-01까지 예외
3.3 안전한 Dockerfile 작성
# 1. 최소 베이스 이미지 사용
FROM cgr.dev/chainguard/python:latest-dev AS builder
# 또는 distroless, Alpine, UBI-micro
# 2. 빌드 의존성과 런타임 분리 (멀티스테이지)
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
COPY . .
FROM cgr.dev/chainguard/python:latest
WORKDIR /app
COPY /install /usr/local
COPY /app .
# 3. non-root 사용자 (Chainguard은 기본 non-root)
# 일반 이미지의 경우:
# RUN addgroup -S app && adduser -S app -G app
# USER app
# 4. 불필요한 패키지 제거, 캐시 정리
# (멀티스테이지로 해결)
# 5. 건강 검사
HEALTHCHECK \
CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
ENTRYPOINT ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]
3.4 베이스 이미지 선택 가이드
| 이미지 유형 | 크기 | 취약점 수 | 패키지 매니저 | 쉘 | 추천 용도 |
|---|---|---|---|---|---|
ubuntu:24.04 | ~78MB | 중간 | apt | bash | 범용 |
alpine:3.20 | ~7MB | 낮음 | apk | ash | 경량 서비스 |
distroless | ~20MB | 매우 낮음 | 없음 | 없음 | 프로덕션 런타임 |
chainguard | ~15MB | 거의 0 | apk (dev만) | 없음(dev만) | 보안 중시 |
ubi-micro | ~35MB | 낮음 | 없음 | 없음 | RHEL 호환 필요 |
scratch | 0MB | 0 | 없음 | 없음 | Go 바이너리 |
3.5 CI/CD 파이프라인 통합
# GitHub Actions 예시
name: Container Security
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: CRITICAL,HIGH
exit-code: 1
format: sarif
output: trivy-results.sarif
- name: Upload scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
- name: Generate SBOM
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: spdx-json
output: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.spdx.json
4. 런타임 하드닝
4.1 컨테이너 런타임 보안
Docker 하드닝
# /etc/docker/daemon.json
{
"userns-remap": "default",
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"live-restore": true,
"icc": false,
"default-ulimits": {
"nofile": { "Name": "nofile", "Hard": 65535, "Soft": 65535 }
}
}
컨테이너 실행 시 보안 옵션
docker run -d \
--name myapp \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges:true \
--security-opt seccomp=default.json \
--pids-limit 100 \
--memory 512m \
--cpus 1.0 \
--user 1000:1000 \
myapp:latest
Kubernetes Pod Security
# Pod Security Standards - Restricted 프로파일
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ['ALL']
resources:
limits:
memory: 512Mi
cpu: '1'
requests:
memory: 256Mi
cpu: '0.5'
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
sizeLimit: 100Mi
4.2 Kubernetes 클러스터 하드닝 체크리스트
| 영역 | 항목 | 명령/설정 |
|---|---|---|
| 인증 | 익명 접근 차단 | --anonymous-auth=false |
| 인가 | RBAC 활성화 | --authorization-mode=RBAC |
| API | NodeRestriction 어드미션 | --enable-admission-plugins=NodeRestriction |
| Etcd | 암호화 설정 | --encryption-provider-config |
| 네트워크 | NetworkPolicy 적용 | Calico/Cilium 네트워크 정책 |
| Pod | PSA (Pod Security Admission) | 네임스페이스에 enforce: restricted |
| 시크릿 | 외부 시크릿 관리자 | Vault, AWS Secrets Manager |
| 감사 | Audit 로깅 | --audit-log-path, --audit-policy-file |
| 이미지 | 서명 검증 | Cosign + Admission Webhook |
| 런타임 | Seccomp/AppArmor 프로파일 | Pod securityContext |
4.3 네트워크 정책 예시
# 기본 거부 정책 (deny-all)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 앱 특정 허용 정책
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-traffic
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: nginx-ingress
ports:
- port: 8080
protocol: TCP
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432
protocol: TCP
- to: # DNS 허용
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
5. 취약점 대응 시나리오별 플레이북
시나리오 1: Critical CVE 긴급 패치
1. [즉시] CVE 공지 확인 → 영향받는 패키지·버전 식별
2. [1시간] 자산 인벤토리에서 영향 범위 파악
3. [2시간] 패치 가용 여부 확인
├── 패치 있음 → 스테이징 적용 → 테스트 → 프로덕션 롤링
└── 패치 없음 → Workaround 적용 (WAF 룰, 설정 변경, 서비스 격리)
4. [24시간] 프로덕션 패치 완료
5. [48시간] 스캔으로 조치 검증 → 보고서 작성
시나리오 2: 컨테이너 이미지 취약점
1. 이미지 스캔 결과 확인 (Trivy/Snyk)
2. 취약점 분류:
├── OS 패키지 → 베이스 이미지 업데이트
├── 언어 라이브러리 → dependency 업데이트
└── 설정 문제 → Dockerfile 수정
3. 이미지 재빌드 + 스캔 재실행
4. 스테이징 배포 → E2E 테스트
5. 프로덕션 롤링 업데이트
6. 이전 이미지 태그 비활성화
시나리오 3: 런타임 침해 탐지 대응
1. [즉시] 알림 확인 (Falco, 감사 로그)
2. [즉시] 해당 Pod/컨테이너 격리 (NetworkPolicy deny-all)
3. [1시간] 포렌식 데이터 수집:
- 컨테이너 프로세스 목록, 네트워크 연결
- 감사 로그, 런타임 이벤트 로그
- 이미지 레이어 분석
4. [4시간] 침입 경로 파악 → 취약점 조치
5. [24시간] 클린 이미지로 재배포
6. [1주] 사후 분석 보고서 + 재발 방지 대책
6. 보안 스캔 자동화 아키텍처
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 코드 푸시 │ → │ CI 파이프라인 │ → │ 이미지 빌드 │
└─────────────┘ └──────┬──────┘ └──────┬──────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ SAST 스캔 │ │ 이미지 스캔 │
│ (Semgrep) │ │ (Trivy) │
└──────┬──────┘ └──────┬──────┘
│ │
┌──────▼───────────────────▼──────┐
│ 결과 집계 + 판정 │
│ (Critical → 빌드 실패) │
│ (High → 경고 + Jira 생성) │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 레지스트리 푸시 (통과 시에만) │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 정기 스캔 (주간, 레지스트리 전체) │
└─────────────────────────────────┘
7. 컴플라이언스 매핑
| 프레임워크 | 관련 요구사항 | 이 플레이북의 대응 |
|---|---|---|
| CIS Benchmark | OS·Docker·K8s 벤치마크 | 섹션 2, 4 |
| NIST 800-53 | SI-2 (Flaw Remediation) | 섹션 2 (패치 관리) |
| PCI DSS 4.0 | 6.3 (취약점 식별·조치) | 전체 프로세스 |
| SOC 2 | CC7.1 (모니터링), CC8.1 (변경관리) | 섹션 5, 6 |
| ISMS-P | 2.10 (시스템·서비스 보안관리) | 전체 |
8. 도구 체인 추천
필수 도구
| 용도 | OSS | 상용 |
|---|---|---|
| 이미지 스캔 | Trivy, Grype | Snyk, Prisma Cloud |
| OS 컴플라이언스 | OpenSCAP, Lynis | Qualys, Tenable |
| 런타임 보안 | Falco | Sysdig Secure |
| SBOM 생성 | Syft, Trivy | Anchore |
| 시크릿 스캔 | Gitleaks, TruffleHog | GitGuardian |
| SAST | Semgrep, CodeQL | SonarQube, Checkmarx |
| 이미지 서명 | Cosign (Sigstore) | Docker Content Trust |
| 정책 엔진 | OPA/Gatekeeper, Kyverno | Styra DAS |
최소 구성 추천
코드 단계: Gitleaks (시크릿) + Semgrep (SAST)
빌드 단계: Trivy (이미지 스캔) + Syft (SBOM)
배포 단계: Cosign (이미지 서명) + Kyverno (정책)
런타임: Falco (이상 탐지) + 감사 로그
9. 보고서 템플릿
취약점 조치 보고서
# 보안 취약점 조치 보고서
## 개요
- 보고일: YYYY-MM-DD
- 작성자: 보안 운영팀
- 대상 기간: YYYY-MM-DD ~ YYYY-MM-DD
## 요약
| 심각도 | 발견 | 조치 완료 | 예외 처리 | 미조치 |
| -------- | ---- | --------- | --------- | ------ |
| Critical | 3 | 3 | 0 | 0 |
| High | 12 | 10 | 2 | 0 |
| Medium | 45 | 30 | 5 | 10 |
## Critical 취약점 상세
### CVE-YYYY-XXXXX
- 영향: [설명]
- 영향 자산: [서버/이미지 목록]
- 조치: [패치 버전/설정 변경]
- 조치일: YYYY-MM-DD
- 검증: [스캔 결과 첨부]
## 예외 처리 목록
| CVE | 사유 | 보완 조치 | 만료일 |
| -------------- | --------------------- | ----------- | ---------- |
| CVE-YYYY-XXXXX | 해당 코드 경로 미사용 | WAF 룰 추가 | YYYY-MM-DD |
## 개선 권고사항
1. [구체적 개선 사항]
2. [구체적 개선 사항]
10. 실전 점검 체크리스트
OS 보안
- 불필요한 서비스 비활성화 (
systemctl list-unit-files --state=enabled) - SSH 키 기반 인증만 허용, root 로그인 차단
- 자동 보안 업데이트 설정
- 방화벽 기본 거부(deny) 정책
- 감사 로그(auditd) 활성화
- AIDE/OSSEC 파일 무결성 모니터링
컨테이너 보안
- 최소 베이스 이미지 사용 (distroless/chainguard)
- 멀티스테이지 빌드로 빌드 도구 제거
- non-root 사용자로 실행
- 읽기 전용 파일시스템
- 리소스 제한 (CPU, 메모리, PID)
- 이미지 서명 + 검증
Kubernetes 보안
- PSA(Pod Security Admission) restricted 모드
- NetworkPolicy 기본 deny-all
- RBAC 최소 권한 원칙
- Etcd 암호화
- 감사 로깅 활성화
- 시크릿 외부 관리 (Vault 등)
마무리
보안은 한 번의 조치가 아니라 지속적인 프로세스다. 이 플레이북의 핵심을 세 줄로 요약한다.
- 자동화: 스캔·패치·검증을 CI/CD에 내장하여 수동 누락을 방지한다.
- 계층 방어: OS·이미지·런타임·네트워크를 모두 다루는 심층 방어 전략을 수립한다.
- 대응 체계: 발견→분류→조치→검증→보고의 사이클을 반복하며, SLA를 지킨다.
완벽한 보안은 불가능하지만, 체계적인 운영으로 리스크를 관리 가능한 수준으로 낮출 수 있다.
Security vulnerability action playbook: OS package, container image, runtime hardening
Entering
When a security scanner pours out a list of CVEs, it becomes difficult to know where to start. The important thing is not to immediately fix all vulnerabilities, but to have a process to prioritize based on risk, take systematic action, and prevent recurrence.
In this article, we present a practical playbook covering OS package vulnerability patching, container image security, and runtime hardening.
1. Vulnerability response process overview
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 발견 │ → │ 분류 │ → │ 조치 │ → │ 검증 │ → │ 보고 │
│ Scanning │ │ Triage │ │ Remediate│ │ Verify │ │ Report │
└─────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
Responsive SLA (recommended)
| Severity | CVSS score | Action Deadline | Example |
|---|---|---|---|
| Critical | 9.0~10.0 | 24~72 hours | RCE, authentication bypass |
| High | 7.0~8.9 | 7 days | Escalation of privilege, information leakage |
| Medium | 4.0~6.9 | 30 days | XSS, Denial of Service |
| Low | 0.1~3.9 | 90 days or next regular patch | Information disclosure (limited) |
Core Principle: Do not judge only the CVSS score, but comprehensively judge Exploit Possibility (EPSS), Internet Exposure, and Importance of Affected Assets.
2. OS package vulnerability management
2.1 Vulnerability scan
# RHEL / Rocky - 보안 업데이트 확인
dnf updateinfo list security
dnf updateinfo list --sec-severity=Critical
dnf updateinfo info RHSA-2026:1234
# Ubuntu - 보안 업데이트 확인
apt update
apt list --upgradable 2>/dev/null | grep -i security
# 설치된 패키지의 CVE 확인 (Trivy)
trivy rootfs --severity CRITICAL,HIGH /
# OpenSCAP 스캔 (컴플라이언스)
oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis \
--results results.xml \
--report report.html \
/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
2.2 Patch application procedure
#!/usr/bin/env bash
# patch-os.sh - OS 보안 패치 적용 스크립트
set -euo pipefail
LOG_FILE="/var/log/security-patch-$(date +%Y%m%d).log"
SNAPSHOT_NAME="pre-patch-$(date +%Y%m%d-%H%M%S)"
log() { printf '[%s] %s\n' "$(date +%T)" "$1" | tee -a "$LOG_FILE"; }
# 1단계: 스냅샷/백업
log "=== 패치 시작 ==="
log "스냅샷 생성: $SNAPSHOT_NAME"
# LVM 스냅샷 (해당 시)
# lvcreate -L 10G -s -n "$SNAPSHOT_NAME" /dev/vg0/root
# 2단계: 현재 상태 기록
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /tmp/packages-before.txt
# 3단계: 보안 업데이트만 적용
log "보안 업데이트 적용 중..."
if command -v dnf &>/dev/null; then
dnf update --security -y 2>&1 | tee -a "$LOG_FILE"
elif command -v apt-get &>/dev/null; then
apt-get update
apt-get upgrade -y -o Dpkg::Options::="--force-confold" 2>&1 | tee -a "$LOG_FILE"
fi
# 4단계: 변경된 패키지 목록
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /tmp/packages-after.txt
diff /tmp/packages-before.txt /tmp/packages-after.txt > /tmp/packages-diff.txt || true
log "변경된 패키지:"
cat /tmp/packages-diff.txt | tee -a "$LOG_FILE"
# 5단계: 서비스 재시작 필요 여부 확인
if command -v needs-restarting &>/dev/null; then
log "재시작 필요 서비스:"
needs-restarting -s 2>&1 | tee -a "$LOG_FILE"
if needs-restarting -r 2>&1 | grep -q "Reboot is required"; then
log "WARNING: 커널 업데이트로 리부팅 필요"
fi
fi
log "=== 패치 완료 ==="
2.3 Automatic security update settings
RHEL/Rocky
# dnf-automatic 설치·설정
dnf install -y dnf-automatic
# /etc/dnf/automatic.conf
# [commands]
# apply_updates = yes
# upgrade_type = security # 보안 업데이트만
systemctl enable --now dnf-automatic-install.timer
Ubuntu
# unattended-upgrades 설정
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades
# Unattended-Upgrade::Allowed-Origins {
# "${distro_id}:${distro_codename}-security";
# };
# Unattended-Upgrade::Automatic-Reboot "false";
# Unattended-Upgrade::Mail "admin@example.com";
2.4 Patch Management Checklist
- Subscribe to security update notification channel (RHSA, USN, CVE mailing list)
- Automated weekly vulnerability scanning
- Staging → Building a production patch pipeline
- Snapshot/backup required before patch application
- Automation of service health check after patch
- Establish reboot schedule when updating kernel
- Preservation of patch history and audit log (at least 1 year)
3. Container image security
3.1 Comparison of image scanning tools
| tools | License | Features | CI/CD integration |
|---|---|---|---|
| Trivy | OSS (Apache-2.0) | OS + language package + IaC + Secret | GitHub Actions, GitLab CI |
| Grype | OSS (Apache-2.0) | SBOM-based scanning | CLI-centric |
| Snyk Container | Commercial (Free Plan) | Developer-friendly Fix PR | Most CI |
| Prisma Cloud | commercial | All CNAPP | Enterprise CI |
| AWS ECR Scanning | Includes AWS | Inspector-based | AWS Native |
3.2 Practical use of Trivy
# 이미지 스캔 (Critical + High만)
trivy image --severity CRITICAL,HIGH myapp:latest
# SBOM 생성
trivy image --format spdx-json -o sbom.json myapp:latest
# 취약점이 있으면 빌드 실패 (CI용)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
# .trivyignore - 허용된 취약점 (예외 처리)
# CVE-2024-XXXX # 해당 코드 경로 미사용, 2026-04-01까지 예외
3.3 Writing a secure Dockerfile
# 1. 최소 베이스 이미지 사용
FROM cgr.dev/chainguard/python:latest-dev AS builder
# 또는 distroless, Alpine, UBI-micro
# 2. 빌드 의존성과 런타임 분리 (멀티스테이지)
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
COPY . .
FROM cgr.dev/chainguard/python:latest
WORKDIR /app
COPY /install /usr/local
COPY /app .
# 3. non-root 사용자 (Chainguard은 기본 non-root)
# 일반 이미지의 경우:
# RUN addgroup -S app && adduser -S app -G app
# USER app
# 4. 불필요한 패키지 제거, 캐시 정리
# (멀티스테이지로 해결)
# 5. 건강 검사
HEALTHCHECK \
CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
ENTRYPOINT ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]
3.4 Base image selection guide
| Image Type | size | Number of vulnerabilities | package manager | shell | Recommended use |
|---|---|---|---|---|---|
ubuntu:24.04 | ~78MB | middle | apt | bash | universal |
alpine:3.20 | ~7MB | low | apk | ash | lightweight service |
distroless | ~20MB | very low | None | None | Production Runtime |
chainguard | ~15MB | almost 0 | apk (dev only) | None (dev only) | Focus on security |
ubi-micro | ~35MB | low | None | None | Requires RHEL Compatibility |
scratch | 0MB | 0 | None | None | Go binary |
3.5 CI/CD pipeline integration
# GitHub Actions 예시
name: Container Security
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: CRITICAL,HIGH
exit-code: 1
format: sarif
output: trivy-results.sarif
- name: Upload scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
- name: Generate SBOM
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: spdx-json
output: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.spdx.json
4. Runtime hardening
4.1 Container runtime security
Docker hardening
# /etc/docker/daemon.json
{
"userns-remap": "default",
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"live-restore": true,
"icc": false,
"default-ulimits": {
"nofile": { "Name": "nofile", "Hard": 65535, "Soft": 65535 }
}
}
Security options when running containers
docker run -d \
--name myapp \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges:true \
--security-opt seccomp=default.json \
--pids-limit 100 \
--memory 512m \
--cpus 1.0 \
--user 1000:1000 \
myapp:latest
Kubernetes Pod Security
# Pod Security Standards - Restricted 프로파일
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ['ALL']
resources:
limits:
memory: 512Mi
cpu: '1'
requests:
memory: 256Mi
cpu: '0.5'
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
sizeLimit: 100Mi
4.2 Kubernetes cluster hardening checklist
| area | Item | Command/Settings |
|---|---|---|
| Certification | Block anonymous access | --anonymous-auth=false |
| Is it | Enable RBAC | --authorization-mode=RBAC |
| API | NodeRestriction Admission | --enable-admission-plugins=NodeRestriction |
| Etcd | Encryption Settings | --encryption-provider-config |
| Network | Apply NetworkPolicy | Calico/Cilium Network Policy |
| Pod | PSA (Pod Security Admission) | in the namespaceenforce: restricted |
| Secret | External Secret Manager | Vault, AWS Secrets Manager |
| Thanks | Audit logging | --audit-log-path, --audit-policy-file |
| Image | Signature Verification | Cosign + Admission Webhook |
| Runtime | Seccomp/AppArmor Profile | Pod securityContext |
4.3 Network policy example
# 기본 거부 정책 (deny-all)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 앱 특정 허용 정책
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-traffic
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: nginx-ingress
ports:
- port: 8080
protocol: TCP
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432
protocol: TCP
- to: # DNS 허용
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
5. Playbook for each vulnerability response scenario
Scenario 1: Critical CVE Emergency Patch
1. [즉시] CVE 공지 확인 → 영향받는 패키지·버전 식별
2. [1시간] 자산 인벤토리에서 영향 범위 파악
3. [2시간] 패치 가용 여부 확인
├── 패치 있음 → 스테이징 적용 → 테스트 → 프로덕션 롤링
└── 패치 없음 → Workaround 적용 (WAF 룰, 설정 변경, 서비스 격리)
4. [24시간] 프로덕션 패치 완료
5. [48시간] 스캔으로 조치 검증 → 보고서 작성
Scenario 2: Container image vulnerability
1. 이미지 스캔 결과 확인 (Trivy/Snyk)
2. 취약점 분류:
├── OS 패키지 → 베이스 이미지 업데이트
├── 언어 라이브러리 → dependency 업데이트
└── 설정 문제 → Dockerfile 수정
3. 이미지 재빌드 + 스캔 재실행
4. 스테이징 배포 → E2E 테스트
5. 프로덕션 롤링 업데이트
6. 이전 이미지 태그 비활성화
Scenario 3: Runtime breach detection response
1. [즉시] 알림 확인 (Falco, 감사 로그)
2. [즉시] 해당 Pod/컨테이너 격리 (NetworkPolicy deny-all)
3. [1시간] 포렌식 데이터 수집:
- 컨테이너 프로세스 목록, 네트워크 연결
- 감사 로그, 런타임 이벤트 로그
- 이미지 레이어 분석
4. [4시간] 침입 경로 파악 → 취약점 조치
5. [24시간] 클린 이미지로 재배포
6. [1주] 사후 분석 보고서 + 재발 방지 대책
6. Security scan automation architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 코드 푸시 │ → │ CI 파이프라인 │ → │ 이미지 빌드 │
└─────────────┘ └──────┬──────┘ └──────┬──────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ SAST 스캔 │ │ 이미지 스캔 │
│ (Semgrep) │ │ (Trivy) │
└──────┬──────┘ └──────┬──────┘
│ │
┌──────▼───────────────────▼──────┐
│ 결과 집계 + 판정 │
│ (Critical → 빌드 실패) │
│ (High → 경고 + Jira 생성) │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 레지스트리 푸시 (통과 시에만) │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ 정기 스캔 (주간, 레지스트리 전체) │
└─────────────────────────────────┘
7. Compliance mapping
| framework | Related Requirements | Response from this playbook |
|---|---|---|
| CIS Benchmark | OS·Docker·K8s benchmark | Section 2, 4 |
| NIST 800-53 | SI-2 (Flaw Remediation) | Section 2 (Patch Management) |
| PCI DSS 4.0 | 6.3 (Vulnerability identification/action) | Full process |
| SOC 2 | CC7.1 (Monitoring), CC8.1 (Change Management) | Section 5, 6 |
| ISMS-P | 2.10 (System/Service Security Management) | All |
8. Toolchain Recommendation
Essential tools
| Use | OSS | commercial |
|---|---|---|
| image scan | Trivy, Grype | Snyk, Prisma Cloud |
| OS Compliance | OpenSCAP, Lynis | Qualys, Tenable |
| runtime security | Falco | Sysdig Secure |
| Create SBOM | Syft, Trivy | Anchore |
| Secret Scan | Gitleaks, TruffleHog | GitGuardian |
| SAST | Semgrep, CodeQL | SonarQube, Checkmarx |
| image signature | Cosign (Sigstore) | Docker Content Trust |
| Policy Engine | OPA/Gatekeeper, Kyverno | Styra DAS |
Recommended minimum configuration
코드 단계: Gitleaks (시크릿) + Semgrep (SAST)
빌드 단계: Trivy (이미지 스캔) + Syft (SBOM)
배포 단계: Cosign (이미지 서명) + Kyverno (정책)
런타임: Falco (이상 탐지) + 감사 로그
9. Report template
Vulnerability Action Report
# 보안 취약점 조치 보고서
## 개요
- 보고일: YYYY-MM-DD
- 작성자: 보안 운영팀
- 대상 기간: YYYY-MM-DD ~ YYYY-MM-DD
## 요약
| 심각도 | 발견 | 조치 완료 | 예외 처리 | 미조치 |
| -------- | ---- | --------- | --------- | ------ |
| Critical | 3 | 3 | 0 | 0 |
| High | 12 | 10 | 2 | 0 |
| Medium | 45 | 30 | 5 | 10 |
## Critical 취약점 상세
### CVE-YYYY-XXXXX
- 영향: [설명]
- 영향 자산: [서버/이미지 목록]
- 조치: [패치 버전/설정 변경]
- 조치일: YYYY-MM-DD
- 검증: [스캔 결과 첨부]
## 예외 처리 목록
| CVE | 사유 | 보완 조치 | 만료일 |
| -------------- | --------------------- | ----------- | ---------- |
| CVE-YYYY-XXXXX | 해당 코드 경로 미사용 | WAF 룰 추가 | YYYY-MM-DD |
## 개선 권고사항
1. [구체적 개선 사항]
2. [구체적 개선 사항]
10. Actual inspection checklist
OS Security
- Disable unnecessary services (
systemctl list-unit-files --state=enabled) - Allow only SSH key-based authentication, block root login
- Automatic security update settings
- Firewall default deny policy
- Activate audit log (auditd)
- AIDE/OSSEC file integrity monitoring
Container Security
- Use minimal base image (distroless/chainguard)
- Remove build tools with multistage build
- Run as non-root user
- Read-only file system
- Resource limits (CPU, memory, PID)
- Image signature + verification
Kubernetes Security
- PSA (Pod Security Admission) restricted mode
- NetworkPolicy default deny-all
- RBAC principle of least privilege
- Etcd encryption
- Enable audit logging
- Secret external management (Vault, etc.)
Finish
Security is not a one-time action, but a continuous process. Summarize the core of this playbook in three lines.
- Automation: Prevent manual omission by embedding scan, patch, and verification into CI/CD.
- Layered defense: Establish an in-depth defense strategy that covers OS, image, runtime, and network.
- Response system: Repeat the cycle of discovery → classification → action → verification → reporting, and maintain SLA.
Perfect security is impossible, but through systematic operation risk can be reduced to a manageable level.
Quiz
Q1: What is the main topic covered in "Security vulnerability action playbook: OS package,
container image, runtime hardening"?
We organize a practical security operation playbook that covers everything from CVE discovery to action, verification, and reporting, OS package vulnerability patching, container image security, and runtime hardening.
Q2: What is Entering?
When a security scanner pours out a list of CVEs, it becomes difficult to know where to start. The
important thing is not to immediately fix all vulnerabilities, but to have a process to prioritize
based on risk, take systematic action, and prevent recurrence.
Q3: Explain the core concept of Runtime hardening.
4.1 Container runtime security Docker hardening
bash /etc/docker/daemon.json "userns-remap": "default", "no-new-privileges": true, "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" "storage-driver": "overlay2", "live-restore": true, "icc": false, "defa...
Q4: What are the key aspects of Playbook for each vulnerability response scenario?
Scenario 1: Critical CVE Emergency Patch
[1시간] 자산 인벤토리에서 영향 범위 파악 [2시간] 패치 가용 여부 확인 ├── 패치 있음 → 스테이징 적용
→ 테스트 → 프로덕션 롤링 └── 패치 없음 → Workaround 적용 (WAF 룰, 설정 변경, 서비스 격리) [24시간]
프로덕션 패치 완료 [48시간] 스캔으로 조치 검증 → 보고서 작성 [즉시] 알림 확인 (Falco, 감사 로그)
[즉시]...
Q5: How does Toolchain Recommendation work?
Essential tools Recommended minimum configuration
코드 단계: Gitleaks (시크릿) + Semgrep (SAST)
빌드 단계: Trivy (이미지 스캔) + Syft (SBOM) 배포 단계: Cosign (이미지 서명) + Kyverno (정책)
런타임: Falco (이상 탐지) + 감사 로그