K8s Pod Security Standards

Pod Security Standards란?

Kubernetes 1.25에서 PodSecurityPolicy(PSP)가 완전히 제거되면서, 그 대안으로 Pod Security Standards(PSS)와 이를 강제하는 Pod Security Admission(PSA)이 정식 GA가 되었다. PSS는 Pod의 보안 수준을 3단계로 정의하고, PSA는 네임스페이스 레벨에서 이를 강제한다.

PSP 대비 훨씬 단순하고 표준화된 접근이며, 별도 Webhook 없이 빌트인으로 동작한다는 것이 핵심이다.

3가지 보안 레벨

PSS는 세 가지 프로파일을 정의한다. 상위 레벨은 하위 레벨의 규칙을 모두 포함한다.

레벨 설명 사용 시나리오
Privileged 제한 없음. 모든 권한 허용 kube-system, 시스템 컴포넌트
Baseline 알려진 권한 상승 차단. 최소한의 제한 일반 워크로드 기본값
Restricted 강력한 보안 제한. Pod 하드닝 모범 사례 강제 민감 워크로드, 금융/의료

Baseline이 차단하는 것

Baseline 프로파일은 다음을 금지한다:

  • privileged: true 컨테이너
  • hostNetwork, hostPID, hostIPC 사용
  • hostPath 볼륨 마운트
  • 위험한 Linux Capabilities (SYS_ADMIN, NET_RAW 등)
  • /proc 마스킹 해제 (procMount: Unmasked)
  • 특정 seccomp 프로파일 외 사용

Restricted가 추가로 강제하는 것

Restricted는 Baseline의 모든 규칙에 더해 다음을 요구한다:

  • runAsNonRoot: true 필수
  • allowPrivilegeEscalation: false 필수
  • 모든 Capabilities drop 후 필요한 것만 add: drop: ["ALL"] 필수
  • Seccomp 프로파일 명시 필수 (RuntimeDefault 또는 Localhost)
  • readOnlyRootFilesystem 권장 (필수는 아님)

PSA 적용: 네임스페이스 Label

Pod Security Admission은 네임스페이스 Label로 설정한다. 3가지 모드를 조합할 수 있다:

모드 동작 용도
enforce 위반 Pod 생성 거부 실제 차단
audit 감사 로그에 기록, 허용 모니터링/전환기
warn 경고 메시지 표시, 허용 개발자 알림
# Baseline enforce + Restricted warn 조합
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # Baseline 위반 시 Pod 생성 거부
    pod-security.kubernetes.io/enforce: baseline
    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

이 패턴이 가장 권장되는 전환 전략이다. Baseline을 강제하면서, Restricted로 전환 준비를 동시에 한다.

Restricted 준수 Pod 작성법

Restricted 레벨을 만족하는 Pod 스펙을 작성해 보자:

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:1.0
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
      # 쓰기 필요한 경로만 emptyDir로 마운트
      volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /app/cache
  volumes:
    - name: tmp
      emptyDir: {}
    - name: cache
      emptyDir:
        sizeLimit: 100Mi

핵심 포인트: readOnlyRootFilesystem: true로 설정하면 컨테이너가 파일시스템에 쓸 수 없다. /tmp이나 캐시 디렉토리는 emptyDir로 별도 마운트한다.

기존 클러스터 전환 전략

이미 운영 중인 클러스터에 PSA를 도입하는 단계별 전략이다:

1단계: 현황 파악 (Dry-run)

# 모든 네임스페이스에서 Baseline 위반 Pod 확인
kubectl label --dry-run=server --overwrite ns 
  --all pod-security.kubernetes.io/enforce=baseline

# 특정 네임스페이스에서 Restricted 위반 확인
kubectl label --dry-run=server --overwrite ns production 
  pod-security.kubernetes.io/enforce=restricted

--dry-run=server는 실제 Label을 적용하지 않고, 위반하는 Pod 목록만 보여준다.

2단계: Audit + Warn 모드 적용

# 경고만 표시, 차단하지 않음
kubectl label ns production 
  pod-security.kubernetes.io/warn=baseline 
  pod-security.kubernetes.io/audit=baseline

3단계: 위반 Pod 수정

경고/감사 로그를 확인하며 위반 Pod의 securityContext를 수정한다.

4단계: Enforce 적용

# 모든 위반이 해결된 후 강제 적용
kubectl label ns production 
  pod-security.kubernetes.io/enforce=baseline 
  pod-security.kubernetes.io/warn=restricted 
  pod-security.kubernetes.io/audit=restricted

클러스터 전역 기본값 설정

모든 네임스페이스에 기본 정책을 적용하려면 Admission Configuration을 사용한다:

# /etc/kubernetes/admission-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
  - name: PodSecurity
    configuration:
      apiVersion: pod-security.admission.config.k8s.io/v1
      kind: PodSecurityConfiguration
      defaults:
        enforce: baseline
        enforce-version: latest
        warn: restricted
        warn-version: latest
        audit: restricted
        audit-version: latest
      exemptions:
        # 시스템 네임스페이스 면제
        namespaces:
          - kube-system
          - kube-node-lease
          - cert-manager
        # 특정 사용자/SA 면제
        usernames:
          - system:serviceaccount:monitoring:prometheus
        # 특정 런타임 클래스 면제
        runtimeClasses:
          - kata

exemptions로 시스템 네임스페이스나 특정 서비스 어카운트를 면제할 수 있다. cert-manager, 모니터링 에이전트 등 특권이 필요한 컴포넌트에 사용한다.

OPA Gatekeeper와의 비교

PSA와 OPA Gatekeeper는 상호 보완적이다:

항목 PSA OPA Gatekeeper
설치 빌트인 (추가 설치 불필요) 별도 설치 필요
정책 유연성 3단계 고정 프로파일 Rego로 커스텀 정책 무제한
적용 범위 Pod 보안 컨텍스트만 모든 K8s 리소스
복잡도 낮음 높음 (Rego 학습 필요)
권장 사용 기본 보안 베이스라인 조직별 세밀한 정책

권장: PSA로 기본 보안 수준을 확보하고, 조직 고유의 세밀한 정책은 OPA Gatekeeper로 추가 적용하라.

흔한 위반 사례와 해결법

1. Nginx Ingress Controller

# 위반: NET_BIND_SERVICE capability 필요 (80/443 포트 바인딩)
# 해결: Baseline에서는 허용됨. Restricted에서는 네임스페이스 면제 설정
exemptions:
  namespaces:
    - ingress-nginx

2. 로그 수집 에이전트 (Fluent Bit)

# 위반: hostPath 볼륨 (/var/log) 마운트 필요
# 해결: 시스템 네임스페이스에 배포하거나 면제 설정
# 또는 sidecar 패턴으로 전환

3. 컨테이너 이미지가 root로 실행

# 위반: runAsNonRoot: true 위반
# 해결: Dockerfile에서 USER 지시어 추가
FROM node:20-slim
RUN groupadd -r app && useradd -r -g app app
USER app
COPY --chown=app:app . /app

운영 베스트 프랙티스

  • 모든 네임스페이스에 최소 Baseline enforce: 클러스터 전역 기본값으로 설정하라
  • 점진적 Restricted 전환: warn/audit로 시작하여 위반을 파악한 후 enforce로 전환하라
  • CI/CD에서 사전 검증: kubectl --dry-run=server 또는 Trivy 같은 도구로 배포 전 PSS 준수 여부를 검증하라
  • 면제는 최소화: exemptions는 반드시 필요한 시스템 컴포넌트에만 적용하라
  • 버전 고정 vs latest: 운영 환경에서는 enforce-version: v1.30처럼 고정하여 업그레이드 시 예기치 않은 차단을 방지하라

정리

Pod Security Standards는 PSP의 복잡함을 걷어내고, 3단계 보안 프로파일로 단순화한 Kubernetes 빌트인 보안 메커니즘이다. Baseline으로 기본 보안을 확보하고, Restricted로 점진적으로 강화하는 전략이 가장 효과적이다. OPA Gatekeeper와 조합하면 표준 보안 + 커스텀 정책이라는 완전한 보안 체계를 구축할 수 있다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux