K8s Security - 05. pod-security-admission
"privileged: true"가 왜 기본으로 허용되는가 — Pod Security Admission과 PSP의 역사
한 팀이 보안 점검에서 지적받았다: 클러스터의 Pod 중 일부가 privileged: true로 돌고 있었다 — 컨테이너가 노드의 커널·장치에 직접 접근할 수 있는 위험 모드. "이걸 막는 기능이 있지 않았나?" 있었다 — PodSecurityPolicy(PSP). 그런데 Kubernetes 1.25에서 PSP는 제거됐다. 후속이 Pod Security Admission. 왜 바뀌었고, 새 모델은 어떻게 다른가?
이 글이 푸는 것은: Pod의 권한 상승을 통제하는 Pod Security Admission의 세 모드(privileged/baseline/restricted), 그리고 PSP가 왜 제거됐는가다.
Pod의 보안 문맥 — 위험한 설정들
Pod는 여러 "위험한" 설정을 가질 수 있다:
- privileged: true: 컨테이너가 노드의 거의 모든 능력(장치·커널)에 접근.
- hostNetwork/hostPID/hostPath: 노드의 네트워크/프로세스/파일시스템 직접 접근.
- allowPrivilegeEscalation: 컨테이너 내부에서 더 높은 권한 획득.
- runAsUser: 0: root로 실행.
이것들이 기본적으로 허용된다 — Kubernetes는 안전 기본값이 아니다. 그래서 통제가 필요하고, 그것이 Pod Security Admission이다.
Pod Security Admission — 세 프로파일
Pod Security Admission은 namespace에 라벨로 세 프로파일 중 하나를 적용:
| 프로파일 | 의미 | 전형 용도 |
|---|---|---|
| privileged | 제한 없음(위험 설정 허용) | 시스템/DaemonSet(노드 접근 필요) |
| baseline | 가장 위험한 권한 상승 차단, 일반 Pod 허용 | 일반 앱 |
| restricted | 엄격(hardening). 최신 보안 관행 강제 | 미션 크리티컬/규제 환경 |
# Kubernetes 1.36 — namespace에 restricted 적용
kubectl label namespace prod pod-security.kubernetes.io/enforce=restricted
kubectl label namespace prod pod-security.kubernetes.io/enforce-version=latest
이제 prod namespace에 privileged: true Pod를 만들려 하면 거부.
flowchart LR
NS["namespace<br/>enforce=restricted"] -. 라벨 .-> PSA["Pod Security Admission<br/>(내장 어드미션)"]
POD["Pod 생성 (privileged:true)"] --> PSA
PSA -->|거부| DENY["enforce: 위반"]
PSA -->|audit 경고| LOG["violation 로그"]
enforce / audit / warn — 세 모드
Pod Security Admission은 라벨로 세 가지 동작 모드를 따로 설정:
- enforce: 위반 시 거부(하드).
- audit: 거부 않고 감사 로그에 경고 기록(점진적 도입).
- warn: 사용자에게 경고(생성은 됨).
이 세 모드를 조합해 "일단 audit/warn으로 관찰 → 충분히 정리되면 enforce"로 점진 전환하는 패턴이 권장.
PSP는 왜 제거됐나 (1.25)
PodSecurityPolicy(이전 모델)는 강력했지만 설계 문제가 있었다:
- 거부 이유가 불투명 — 어느 필드가 위반인지 사용자가 알기 어려움.
- 기본 허용 모델 — 명시적으로 허용한 것만. 빠뜨리면 전부 거부(오토스케일 등 부작용).
- 복잡한 우선순위 — 여러 PSP의 매칭 규칙이 헷갈림.
그래서 1.21에서 deprecated, 1.25에서 제거. 단순한 라벨 기반 3단계 모델(Pod Security Admission)로 대체. 더 단순하고 예측 가능.
이 사실이 중요한 이유: 구형 자료(1.24 이전)가 여전히 "PSP로 막아라"라고 가르친다. 1.25+에선 PSP가 존재하지 않는다. 현재 진실은 Pod Security Admission. 1.36 기준 문서는 반드시 새 모델로.
restricted 프로파일이 강제하는 것들
restricted는 엄격:
privileged: true금지.hostNetwork/hostPID/hostIPC금지.allowPrivilegeEscalation: false강제.- 컨테이너
runAsNonRoot: true또는runAsUser != 0. seccompProfile설정 강제.- capability 삭제(
drop: [ALL]).
이것이 "현대 보안 hardening"의 기준. 단 모든 앱이 이 제약을 감당하는 건 아니다 — 레거시, 노드 접근 필요(DaemonSet)는 baseline이나 privileged가 필요.
exemptions — 예외
Pod Security Admission은 특정 Pod(예: kube-system 시스템 Pod)를 예외로 둘 수 있다(라벨/username 기반). 시스템 Pod는 restricted 위반(노드 접근 필요)이 흔하므로.
직접 확인하기
# Kubernetes 1.36 — restricted namespace에서 privileged Pod 거부
kubectl create ns secure
kubectl label ns secure pod-security.kubernetes.io/enforce=restricted
kubectl run x --image=nginx:1.27 -n secure --restart=Never \
--overrides='{"spec":{"containers":[{"name":"x","image":"nginx:1.27","securityContext":{"privileged":true}}]}}'
확인할 것: privileged:true Pod가 거부. 에러 메시지가 어느 필드 위반인지 알려줌.
# audit 모드로 경고만 (생성은 됨)
kubectl label ns secure pod-security.kubernetes.io/enforce- # enforce 제거
kubectl label ns secure pod-security.kubernetes.io/audit=restricted
kubectl run y --image=nginx:1.27 -n secure ... # 생성됨 + 경고
restricted가 정확히 강제하는 것들 — 항목별
restricted 프로파일이 강제하는 요구 사항을 항목별로 보면, "왜 이게 hardening인가"가 분명해진다:
| 요구 | 강제 내용 | 막는 공격 |
|---|---|---|
privileged: true 금지 |
컨테이너가 노드 권한 획득 불가 | 컨테이너 탈출 → 노드 장악 |
hostNetwork/PID/IPC 금지 |
노드의 네트워크/프로세스 공간 접근 차단 | 다른 Pod/노드 프로세스 간섭 |
allowPrivilegeEscalation: false |
컨테이너 내부에서 setuid 등 권한 상승 차단 | 악의적 바이너리의 권한 획득 |
runAsNonRoot: true 또는 runAsUser != 0 |
root가 아닌 사용자로 실행 | root 권한 남용 |
seccompProfile 설정 |
syscall 필터링(비정상 syscall 차단) | 커널 취약점 악용 |
capabilities: drop: [ALL] |
Linux capability 전부 제거 후 필요한 것만 추가 | 불필요 권한(예: NET_ADMIN) 악용 |
각 항목이 특정 공격 유형을 막는다. "restricted가 빡빡하다"는 불만은 이해되지만, 각 항목이 방어하는 위협을 보면 타협의 결과다. 특히 privileged와 hostPath는 컨테이너 탈출(컨테이너 → 노드)의 주요 경로 — restricted가 이것을 원천 차단.
audit → enforce 점진 전환의 실제 절차
새 보안 정책을 "바로 enforce"하면 기존 워크로드가 거부돼 장애. 그래서 표준 패턴:
flowchart LR
S1["1. warn만 설정<br/>(생성은 되되 경고)"] --> OBS["관찰: 어느 Pod가 위반?"]
OBS --> S2["2. audit 추가<br/>(감사 로그에 기록)"]
S2 --> FIX["위반 Pod 수정"]
FIX --> S3["3. enforce 전환<br/>(거부 시작)"]
- warn: 위반 Pod 생성 시 사용자에게 경고. 하지만 생성은 됨. "어떤 팀이 위반하나" 파악.
- audit: 감사 로그에 위반 기록. 위반 빈도/심각도 가시화.
- enforce: 충분히 정리한 뒤 실제 거부.
이 점진 전환을 안 하면 — enforce 켜는 순간 미처 수정 못 한 Pod가 거부돼 서비스 장애. 특히 시스템 Pod(kube-system 등)는 restricted 위반이 흔하므로 exemption으로 미리 제외해야.
exemption 설계 — 시스템 Pod는 규칙 밖으로
restricted를 모든 namespace에 강제하면 — kube-system의 시스템 Pod(DaemonSet, CNI 에이전트 등)이 거부된다. 이들은 노드 접근(hostPath, privileged)이 합법적으로 필요. 그래서 exemption으로 제외:
# exemption 예 (Pod Security Admission 구성)
exemptions:
- usernames: ["system:..."]
namespaces: ["kube-system"]
runtimeClasses: []
exemption 설계의 핵심: 최소. kube-system 전체를 예외로 두면 편하지만, kube-system의 비시스템 Pod(누군가 실수로 배포한)도 예외가 됨. 가능한 좁게(특정 SA/라벨만). 이 trade-off가 exemption 운영의 핵심.
세 라벨의 조합 매트릭스 — enforce/audit/warn을 어떻게 섞나
Pod Security Admission의 세 모드(enforce/audit/warn)를 다른 프로파일*로 조합할 수 있다. 예: "enforce는 baseline, audit/warn은 restricted" — baseline 위반은 *거부(강), restricted 위반은 경고만(유연). 점진적 강화 패턴.
| enforce | audit | warn | 효과 |
|---|---|---|---|
| privileged | — | — | 사실상 제한 없음 |
| baseline | — | — | 위험한 권한만 거부 |
| baseline | restricted | restricted | baseline은 강제, restricted는 경고(점진 강화) |
| restricted | restricted | restricted | 완전 restricted 강제 |
이 매트릭스가 "지금은 baseline만 강제하되, restricted 위반을 관찰해 나중에 강제로 올리겠다"를 표현. enforce를 올리는 건 거부를 일으키므로 신중해야 — audit/warn으로 먼저 관찰하는 것이 안전한 강화 경로.
enforce-version 핀닝 — 버전 고정의 안전망
Pod Security Admission은 버전을 고정할 수 있다:
pod-security.kubernetes.io/enforce-version: v1.36
pod-security.kubernetes.io/enforce-version: latest
latest는 "항상 최신 Pod Security Standard"를 — Kubernetes 버전업 시 기준이 바뀔 수 있어, 갑자기 더 엄격해져 기존 Pod가 거부될 위험. v1.36 핀닝은 "이 버전의 기준으로 고정" — 의도된 업그레이드 시점까지 안정. 프로덕션에선 latest 대신 구체 버전 핀닝이 안전.
이것이 Kubernetes의 GA/beta/alpha 규칙(03-fine-grained-kubelet에서 본)의 또 다른 적용 — "최신"은 예측 불가, "구체 버전"은 안정. Pod Security Standard도 버전이 있고, 핀닝이 예측 가능성을 준다.
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "PSP가 아직 있다" | 1.25 제거. 현재는 Pod Security Admission |
| "Pod Security Admission은 별도 설치한다" | 내장 어드미션. namespace 라벨로 켬 |
| "enforce는 모든 위반을 거부한다" | 맞음. 단 exemption 가능 |
| "restricted는 모든 앱에 적합하다" | 엄격. 노드 접근 필요/레거시엔 baseline/privileged |
| "audit은 거부다" | 거부 아님. 감사 로그 기록만. 점진 도입용 |
| "privileged Pod는 절대 쓰면 안 된다" | 시스템 Pod(DaemonSet)는 합리적 사용. 일반 앱은 금지 |
요약 — 이 글의 결론
- Pod의 위험 설정(privileged/hostNetwork 등)이 기본 허용. Kubernetes는 안전 기본값이 아님 — 통제가 필요.
- Pod Security Admission(내장 어드미션)이 namespace 라벨로 세 프로파일(privileged/baseline/restricted) 적용.
- 세 동작 모드(enforce/audit/warn)로 점진적 도입 — audit/warn으로 관찰 후 enforce.
- restricted가 현대 hardening 기준(privileged 금지, non-root, seccomp 등). 단 모든 앱이 감당하는 건 아님.
- PSP는 1.25 제거 — 거부 이유 불투명/기본 허용 모델/복잡 우선순위 문제. 단순 라벨 기반 모델로 대체.
- exemption으로 시스템 Pod(kube-system 등)는 예외 처리.
생각해 볼 문제
privileged: truePod가 왜 위험한가? 구체적 공격 시나리오를 하나.- PSP에서 Pod Security Admission으로 바뀐 이유 중 "기본 허용 모델"의 문제를 설명하라.
- enforce로 바로 켰더니 기존 Pod 배포가 막혔다. audit/warn으로 점진 전환하는 절차를 세라.
- restricted를 prod에, baseline을 dev에 두었다. 차이가 생기는 구체적 설정은?
- DaemonSet(노드 로그 수집)을 restricted namespace에 만들려 한다. 거부된다. 어떻게?
- Pod Security Admission과 NetworkPolicy가 함께 쓰일 때 "심층 방어"가 어떻게 구성되나?
참고
- Kubernetes 공식 문서 - Pod Security Admission - 접근 2026-07-12
- Kubernetes 공식 문서 - Pod Security Standards (프로파일) - 접근 2026-07-12
- Kubernetes 공식 문서 - PodSecurityPolicy deprecation/removal - 접근 2026-07-12 (1.25 제거)
- Kubernetes 공식 문서 - Security Context - 접근 2026-07-12
'Tech Artifacts > K8s Security' 카테고리의 다른 글
| K8s Security - 07. cert-manager (0) | 2026.07.16 |
|---|---|
| K8s Security - 06. secrets management (0) | 2026.07.16 |
| K8s Security - 04. admission-control (0) | 2026.07.16 |
| K8s Security - 03. fine-grained kubelet API authorization (0) | 2026.07.16 |
| K8s Security - 02. authentication (0) | 2026.07.16 |