Skip to content

Split View: Pod Security Standards(PSA/PSS) 실전 가이드

|

Pod Security Standards(PSA/PSS) 실전 가이드

Pod Security Standards Guide

1. Pod Security Standards란?

Kubernetes 1.25부터 PodSecurityPolicy(PSP)가 완전히 제거되고, **Pod Security Admission(PSA)**이 기본 보안 메커니즘이 되었습니다. PSA는 **Pod Security Standards(PSS)**라는 3단계 보안 프로파일을 기반으로 동작합니다.

PSP에서 PSA로의 전환 배경

PSP는 복잡한 RBAC 설정이 필요하고 디버깅이 어려웠습니다. PSA는 namespace 라벨만으로 간단하게 보안 정책을 적용할 수 있어 운영 부담이 크게 줄었습니다.

2. 3가지 보안 프로파일

Privileged (특권)

모든 것이 허용되는 프로파일입니다. 시스템 수준 워크로드(CNI, 스토리지 드라이버 등)에 사용합니다.

# kube-system namespace에 Privileged 적용
apiVersion: v1
kind: Namespace
metadata:
  name: kube-system
  labels:
    pod-security.kubernetes.io/enforce: privileged
    pod-security.kubernetes.io/audit: privileged
    pod-security.kubernetes.io/warn: privileged

Baseline (기본)

알려진 권한 상승을 방지하면서 대부분의 워크로드가 동작할 수 있는 프로파일입니다.

제한 항목:

  • hostNetwork, hostPID, hostIPC 사용 금지
  • privileged 컨테이너 금지
  • 위험한 capabilities 추가 금지 (NET_RAW 등)
  • hostPath 볼륨 금지
apiVersion: v1
kind: Namespace
metadata:
  name: app-staging
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.30
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Restricted (제한)

가장 엄격한 프로파일로, 보안 모범 사례를 강제합니다.

추가 제한 항목:

  • runAsNonRoot 필수
  • Seccomp 프로파일 설정 필수
  • 모든 capabilities drop 필수
  • allowPrivilegeEscalation: false 필수
apiVersion: v1
kind: Namespace
metadata:
  name: app-production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.30
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

3. PSA 동작 모드

PSA는 세 가지 모드로 동작합니다:

모드동작용도
enforce위반 Pod 생성 거부실제 정책 적용
audit감사 로그 기록모니터링
warn사용자에게 경고 표시마이그레이션 준비
# namespace에 라벨 적용
kubectl label namespace my-app \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

4. Restricted 프로파일 호환 Pod 작성

Restricted를 만족하는 Pod spec 예제입니다:

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: app-production
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: nginx:1.27-alpine
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        runAsNonRoot: true
        runAsUser: 1000
        capabilities:
          drop:
            - ALL
      resources:
        limits:
          memory: '128Mi'
          cpu: '500m'
        requests:
          memory: '64Mi'
          cpu: '250m'
      volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /var/cache/nginx
        - name: run
          mountPath: /var/run
  volumes:
    - name: tmp
      emptyDir: {}
    - name: cache
      emptyDir: {}
    - name: run
      emptyDir: {}

5. 마이그레이션 전략

기존 클러스터를 PSA로 마이그레이션하는 단계별 접근법입니다.

Step 1: 현재 상태 감사

# 모든 namespace에 대해 dry-run 검사
kubectl label --dry-run=server --overwrite ns --all \
  pod-security.kubernetes.io/enforce=baseline

# 특정 namespace의 위반 사항 확인
kubectl get pods -n my-app -o json | \
  kubectl apply --dry-run=server -f - 2>&1 | grep -i "warning"

Step 2: warn/audit 모드로 시작

# 먼저 warn과 audit만 적용
kubectl label namespace my-app \
  pod-security.kubernetes.io/warn=baseline \
  pod-security.kubernetes.io/audit=baseline

Step 3: 위반 워크로드 수정

# audit 로그에서 위반 사항 확인
kubectl logs -n kube-system -l component=kube-apiserver | \
  grep "pod-security.kubernetes.io"

Step 4: enforce 모드 활성화

# 충분한 테스트 후 enforce 적용
kubectl label namespace my-app \
  pod-security.kubernetes.io/enforce=baseline \
  --overwrite

6. Namespace별 예외 처리

특정 워크로드가 상위 권한이 필요한 경우, namespace를 분리하는 것이 권장됩니다:

# 모니터링 에이전트용 별도 namespace
apiVersion: v1
kind: Namespace
metadata:
  name: monitoring-agents
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: baseline
    pod-security.kubernetes.io/warn: restricted
---
# 일반 앱용 namespace
apiVersion: v1
kind: Namespace
metadata:
  name: production-apps
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

7. AdmissionConfiguration으로 클러스터 기본값 설정

API 서버 설정으로 클러스터 전체 기본 정책을 지정할 수 있습니다:

# /etc/kubernetes/psa-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'
        audit: 'restricted'
        audit-version: 'latest'
        warn: 'restricted'
        warn-version: 'latest'
      exemptions:
        usernames: []
        runtimeClasses: []
        namespaces:
          - kube-system
          - kube-public
          - istio-system

8. 실전 트러블슈팅

흔한 오류와 해결법

# 오류: Pod 생성 거부
# Error: pods "my-pod" is forbidden: violates PodSecurity "restricted:v1.30"

# 1. 어떤 필드가 위반인지 확인
kubectl describe pod my-pod -n production-apps 2>&1

# 2. 임시로 warn 모드에서 상세 확인
kubectl label namespace production-apps \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/warn=restricted \
  --overwrite

자주 발생하는 위반 체크리스트

#!/bin/bash
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
  echo "=== Namespace: $ns ==="
  kubectl get pods -n "$ns" -o json | \
    jq -r '.items[] | select(
      .spec.containers[].securityContext == null or
      .spec.securityContext == null
    ) | .metadata.name'
done

9. 퀴즈

Q1: PSA의 세 가지 동작 모드는 무엇이며, 각각의 역할은?
  1. enforce: 정책을 위반하는 Pod의 생성을 거부합니다.
  2. audit: 위반 사항을 감사 로그에 기록하지만 Pod 생성은 허용합니다.
  3. warn: kubectl 사용자에게 경고 메시지를 표시하지만 Pod 생성은 허용합니다.

마이그레이션 시에는 warn/audit를 먼저 적용하고, 충분한 검증 후 enforce를 활성화하는 것이 안전합니다.

Q2: Restricted 프로파일에서 반드시 설정해야 하는 securityContext 항목 4가지는?
  1. runAsNonRoot: true — root 사용자로 실행 금지
  2. allowPrivilegeEscalation: false — 권한 상승 금지
  3. capabilities.drop: ["ALL"] — 모든 Linux capabilities 제거
  4. seccompProfile.type: RuntimeDefault — Seccomp 프로파일 설정

이 4가지를 모두 설정하지 않으면 Restricted namespace에서 Pod 생성이 거부됩니다.

Q3: 기존 클러스터를 PSA로 마이그레이션할 때 권장되는 단계는?
  1. 현재 상태 감사: dry-run으로 위반 사항 파악
  2. warn/audit 적용: 실제 차단 없이 모니터링
  3. 위반 워크로드 수정: securityContext 추가, 권한 최소화
  4. enforce 활성화: 충분한 테스트 후 실제 정책 적용
  5. 클러스터 기본값 설정: AdmissionConfiguration으로 신규 namespace에 자동 적용

점진적 접근이 핵심이며, 절대 한 번에 enforce를 적용하지 않습니다.

Pod Security Standards (PSA/PSS) Practical Guide

Pod Security Standards Guide

1. What Are Pod Security Standards?

Starting with Kubernetes 1.25, PodSecurityPolicy (PSP) was completely removed and Pod Security Admission (PSA) became the default security mechanism. PSA operates based on Pod Security Standards (PSS), a three-tier security profile system.

Background: Transition from PSP to PSA

PSP required complex RBAC configuration and was difficult to debug. PSA dramatically reduces operational overhead by allowing security policies to be applied simply through namespace labels.

2. Three Security Profiles

Privileged

A profile that permits everything. Used for system-level workloads such as CNI plugins and storage drivers.

# Apply Privileged to kube-system namespace
apiVersion: v1
kind: Namespace
metadata:
  name: kube-system
  labels:
    pod-security.kubernetes.io/enforce: privileged
    pod-security.kubernetes.io/audit: privileged
    pod-security.kubernetes.io/warn: privileged

Baseline

A profile that prevents known privilege escalations while allowing most workloads to function.

Restricted items:

  • hostNetwork, hostPID, hostIPC usage prohibited
  • Privileged containers prohibited
  • Adding dangerous capabilities prohibited (NET_RAW, etc.)
  • hostPath volumes prohibited
apiVersion: v1
kind: Namespace
metadata:
  name: app-staging
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.30
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Restricted

The most stringent profile that enforces security best practices.

Additional restricted items:

  • runAsNonRoot required
  • Seccomp profile configuration required
  • Dropping all capabilities required
  • allowPrivilegeEscalation: false required
apiVersion: v1
kind: Namespace
metadata:
  name: app-production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.30
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

3. PSA Operating Modes

PSA operates in three modes:

ModeBehaviorPurpose
enforceRejects Pods that violate policyActual enforcement
auditRecords in audit logsMonitoring
warnDisplays warnings to usersMigration readiness
# Apply labels to a namespace
kubectl label namespace my-app \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

4. Writing Pods Compatible with the Restricted Profile

Here is an example Pod spec that satisfies the Restricted profile:

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: app-production
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: nginx:1.27-alpine
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        runAsNonRoot: true
        runAsUser: 1000
        capabilities:
          drop:
            - ALL
      resources:
        limits:
          memory: '128Mi'
          cpu: '500m'
        requests:
          memory: '64Mi'
          cpu: '250m'
      volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /var/cache/nginx
        - name: run
          mountPath: /var/run
  volumes:
    - name: tmp
      emptyDir: {}
    - name: cache
      emptyDir: {}
    - name: run
      emptyDir: {}

5. Migration Strategy

A step-by-step approach for migrating existing clusters to PSA.

Step 1: Audit the Current State

# Dry-run check against all namespaces
kubectl label --dry-run=server --overwrite ns --all \
  pod-security.kubernetes.io/enforce=baseline

# Check violations in a specific namespace
kubectl get pods -n my-app -o json | \
  kubectl apply --dry-run=server -f - 2>&1 | grep -i "warning"

Step 2: Start with warn/audit Mode

# Apply warn and audit first
kubectl label namespace my-app \
  pod-security.kubernetes.io/warn=baseline \
  pod-security.kubernetes.io/audit=baseline

Step 3: Fix Violating Workloads

# Check violations in audit logs
kubectl logs -n kube-system -l component=kube-apiserver | \
  grep "pod-security.kubernetes.io"

Step 4: Enable enforce Mode

# Apply enforce after sufficient testing
kubectl label namespace my-app \
  pod-security.kubernetes.io/enforce=baseline \
  --overwrite

6. Per-Namespace Exception Handling

When specific workloads require elevated privileges, separating namespaces is recommended:

# Separate namespace for monitoring agents
apiVersion: v1
kind: Namespace
metadata:
  name: monitoring-agents
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: baseline
    pod-security.kubernetes.io/warn: restricted
---
# Namespace for general applications
apiVersion: v1
kind: Namespace
metadata:
  name: production-apps
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

7. Setting Cluster Defaults with AdmissionConfiguration

You can specify cluster-wide default policies through API server configuration:

# /etc/kubernetes/psa-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'
        audit: 'restricted'
        audit-version: 'latest'
        warn: 'restricted'
        warn-version: 'latest'
      exemptions:
        usernames: []
        runtimeClasses: []
        namespaces:
          - kube-system
          - kube-public
          - istio-system

8. Practical Troubleshooting

Common Errors and Solutions

# Error: Pod creation denied
# Error: pods "my-pod" is forbidden: violates PodSecurity "restricted:v1.30"

# 1. Identify which field is in violation
kubectl describe pod my-pod -n production-apps 2>&1

# 2. Temporarily check details in warn mode
kubectl label namespace production-apps \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/warn=restricted \
  --overwrite

Frequently Occurring Violations Checklist

#!/bin/bash
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
  echo "=== Namespace: $ns ==="
  kubectl get pods -n "$ns" -o json | \
    jq -r '.items[] | select(
      .spec.containers[].securityContext == null or
      .spec.securityContext == null
    ) | .metadata.name'
done

9. Quiz

Q1: What are the three operating modes of PSA, and what are their roles?
  1. enforce: Rejects the creation of Pods that violate the policy.
  2. audit: Records violations in audit logs but allows Pod creation.
  3. warn: Displays warning messages to kubectl users but allows Pod creation.

During migration, it is safest to apply warn/audit first, then enable enforce after thorough validation.

Q2: What are the 4 securityContext fields that must be set under the Restricted profile?
  1. runAsNonRoot: true — Prohibits running as the root user
  2. allowPrivilegeEscalation: false — Prohibits privilege escalation
  3. capabilities.drop: ["ALL"] — Removes all Linux capabilities
  4. seccompProfile.type: RuntimeDefault — Sets the Seccomp profile

If all four are not set, Pod creation will be rejected in a Restricted namespace.

Q3: What are the recommended steps for migrating an existing cluster to PSA?
  1. Audit the current state: Identify violations using dry-run
  2. Apply warn/audit: Monitor without actual blocking
  3. Fix violating workloads: Add securityContext, minimize privileges
  4. Enable enforce: Apply actual policy enforcement after sufficient testing
  5. Set cluster defaults: Use AdmissionConfiguration to auto-apply to new namespaces

A gradual approach is key — never apply enforce all at once.

Quiz

Q1: What is the main topic covered in "Pod Security Standards (PSA/PSS) Practical Guide"?

Understand the Privileged/Baseline/Restricted profiles of Kubernetes Pod Security Standards, and learn namespace label configuration and migration strategies through hands-on examples.

Q2: What Are Pod Security Standards?? Starting with Kubernetes 1.25, PodSecurityPolicy (PSP) was completely removed and Pod Security Admission (PSA) became the default security mechanism. PSA operates based on Pod Security Standards (PSS), a three-tier security profile system.

Q3: Explain the core concept of Three Security Profiles. Privileged A profile that permits everything. Used for system-level workloads such as CNI plugins and storage drivers. Baseline A profile that prevents known privilege escalations while allowing most workloads to function.

Q4: What are the key aspects of PSA Operating Modes? PSA operates in three modes:

Q5: How does Writing Pods Compatible with the Restricted Profile work? Here is an example Pod spec that satisfies the Restricted profile: