Kubernetes Pod Security Standards와 Pod Security Admission 기반 컨테이너 보안
1. 개요
정의: Kubernetes Pod Security Standards(PSS)는 Pod가 사용할 수 있는 권한과 격리 기능을 세 단계의 누적된 보안 프로파일로 정의하고, Pod Security Admission(PSA)은 그 프로파일을 네임스페이스 단위에서
enforce,audit,warn모드로 적용하는 내장 입장 제어 장치이다.
컨테이너는 프로세스와 파일시스템을 격리하지만, 격리 설정이 약하면 호스트 네트워크·프로세스·IPC 네임스페이스를 공유하거나 Linux capability를 과도하게 부여할 수 있다. privileged: true와 같은 설정은 컨테이너의 편의성을 높이는 대신 컨테이너 탈출이나 호스트 장악의 공격면을 크게 만든다. 따라서 이미지 취약점 점검만으로는 충분하지 않고, 배포 시점에 Pod의 실행 권한을 일관되게 검증해야 한다.
초기의 PodSecurityPolicy(PSP)는 사용 가능했지만 Kubernetes 1.21에서 폐지 수순에 들어갔고 1.25에서 제거되었다. PSA는 별도 웹훅을 설치하지 않고 API 서버의 내장 admission controller로 PSS를 적용한다. 다만 PSA는 모든 컨테이너 보안 정책을 표현하는 범용 정책 엔진이 아니므로, 네트워크 정책·이미지 서명·런타임 탐지와 함께 계층적으로 설계해야 한다.
PSS는 정책의 내용과 적용 방식을 분리한다. 정책 자체는 “어떤 Pod 보안 수준을 요구하는가”를 말하고, PSA의 모드는 위반을 거부할지, 기록할지, 사용자에게 경고할지를 정한다. 이 분리가 있어야 같은 기준을 개발·검증·운영 클러스터에서 재사용하면서도 점진적으로 enforcement를 강화할 수 있다.
Kubernetes 공식 문서의 최신 페이지는 세 프로파일과 모드, 네임스페이스 레이블, 버전 고정, 면제 설정을 설명한다. 문서 버전은 클러스터 버전과 다를 수 있으므로, 운영 설계에서는 실제 control plane과 kubelet 버전에 맞는 PSS 문서를 확인해야 한다.
1.1 등장 배경과 필요성
첫째, 컨테이너 이미지는 애플리케이션 구성물일 뿐 실행 권한의 최종 결정자가 아니다. 동일한 이미지를 사용하더라도 hostNetwork, hostPID, privileged, allowPrivilegeEscalation, seccomp, capability 설정에 따라 위험도가 달라진다. PSS는 이런 런타임 속성을 표준 프로파일로 묶어 조직의 최소 기준을 만든다.
둘째, 멀티테넌트 클러스터에서는 개발팀이 만든 YAML이 플랫폼 경계를 넘지 않도록 해야 한다. 네임스페이스에 프로파일을 부착하면 팀별 배포 파이프라인이 달라도 같은 admission 기준을 통과해야 하므로, 보안 검사를 애플리케이션 개발자의 기억에만 의존하지 않게 된다.
셋째, 보안 기준을 처음부터 restricted로 거부하면 기존 워크로드와 운영 도구가 한꺼번에 중단될 수 있다. PSA의 warn과 audit는 위반을 관찰하면서도 배포를 허용하는 완충 단계다. 이를 활용해 예외를 줄이고, 필요한 경우에만 명시적인 특권 네임스페이스를 허용해야 한다.
2. PSS 프로파일과 보안 경계
flowchart LR
P[Pod manifest] --> PSA[Pod Security Admission]
PSA --> L{Namespace labels}
L --> PR[Privileged<br/>unrestricted]
L --> BA[Baseline<br/>known escalation prevention]
L --> RE[Restricted<br/>hardening best practices]
PR --> A[Pod admitted]
BA --> B[Baseline-compliant Pod]
RE --> C[Restricted-compliant Pod]
PSA --> M{Mode}
M --> E[enforce: reject]
M --> U[audit: audit annotation]
M --> W[warn: client warning]
PSS의 세 수준은 서로 독립적인 메뉴가 아니라 누적되는 경계다. privileged는 제한이 없는 프로파일이고, baseline은 알려진 권한 상승을 막되 일반적인 컨테이너 실행과의 호환성을 중시한다. restricted는 baseline의 제약을 포함하면서 non-root, seccomp, capability 최소화 등 현재의 Pod 강화 관행을 요구한다.
privileged는 노드 에이전트, 장치 플러그인, 네트워크·스토리지 시스템처럼 호스트와 직접 상호작용해야 하는 기반 워크로드에서 불가피할 수 있다. 그러나 편의상 모든 운영 도구를 privileged로 실행하면 네임스페이스 격리의 의미가 사라진다. 이 프로파일은 신뢰된 운영 주체와 좁은 네임스페이스에 한정하고, 허용 사유·이미지·서비스 계정·노드 범위를 문서화해야 한다.
baseline은 일반 애플리케이션의 현실적인 출발점이다. host namespace 공유, privileged 컨테이너, 위험한 추가 capability, 허용되지 않은 hostPath·hostPort·sysctl 같은 알려진 위험을 제한한다. 특정 컨테이너 하나가 기준을 위반하면 Pod 전체가 검증 실패하므로, init container와 ephemeral container까지 포함해 점검해야 한다.
restricted는 호환성을 일부 희생하여 강한 Pod hardening을 적용한다. Linux 컨테이너는 privilege escalation을 허용하지 않아야 하고, seccomp는 RuntimeDefault 또는 Localhost로 지정하며, capability는 ALL을 제거하고 필요한 경우 NET_BIND_SERVICE만 다시 추가한다. 컨테이너와 이미지가 non-root로 동작하지 않으면 애플리케이션 수정이 필요하다.
| 프로파일 | 목적 | 일반 대상 | 대표 통제 |
|---|---|---|---|
| Privileged | 최대 호환성과 권한 | 노드·인프라 운영 워크로드 | 제한 없음, 예외 사유 필수 |
| Baseline | 알려진 권한 상승 차단 | 일반 애플리케이션 | host namespace·privileged·위험 capability 제한 |
| Restricted | 강한 Pod hardening | 보안 중요·저신뢰 워크로드 | non-root·seccomp·capability 최소화 |
프로파일의 이름만 네임스페이스에 부착하는 것으로 보안이 완성되는 것은 아니다. 예를 들어 baseline은 취약한 이미지를 검사하지 않고, restricted도 서비스 계정 토큰의 사용 목적이나 네트워크의 동서 이동을 제어하지 않는다. PSS는 “Pod가 어떤 권한으로 시작할 수 있는가”를 다루는 첫 번째 방어선으로 이해해야 한다.
3. PSA 동작과 레이블 모델
sequenceDiagram
participant C as Client or Controller
participant API as kube-apiserver
participant PSA as Pod Security Admission
participant NS as Namespace labels
participant AUD as Audit log
participant K as Kubelet
C->>API: Create Deployment or Pod
API->>PSA: Admission request
PSA->>NS: Read enforce/audit/warn level and version
PSA-->>API: Decision and warnings
PSA->>AUD: Record violation annotation when audit applies
API-->>C: Reject, warning, or success
API->>K: Schedule admitted Pod
PSA는 네임스페이스 레이블을 읽어 모드별 프로파일을 결정한다. 기본 형식은 pod-security.kubernetes.io/<MODE>: <LEVEL>이며, MODE는 enforce, audit, warn, LEVEL은 privileged, baseline, restricted 중 하나다. 예를 들어 pod-security.kubernetes.io/enforce=baseline은 baseline을 위반하는 Pod 생성을 거부한다.
enforce는 위반을 API 요청 실패로 처리한다. 사용자는 Forbidden과 함께 어떤 필드가 기준을 위반했는지 확인하고 매니페스트를 수정해야 한다. Deployment를 생성할 때는 템플릿이 곧바로 Pod가 되지 않더라도 템플릿 검증 경고를 파이프라인에서 확인하고, 실제 Pod 생성 시 enforcement가 적용된다는 점을 구분한다.
audit는 요청을 허용하지만 audit annotation을 남겨 중앙 감사 로그에서 위반을 집계할 수 있게 한다. 운영팀이 “어떤 네임스페이스에서 어떤 컨트롤이 얼마나 위반되는가”를 수치로 파악할 때 유용하다. 로그 수집이 누락되면 audit은 조용한 허용으로 변하므로 API 서버 감사 정책과 로그 보존기간을 함께 설계해야 한다.
warn은 요청을 허용하되 클라이언트에 사용자 지향 경고를 반환한다. 개발자와 배포 파이프라인이 즉시 확인할 수 있다는 장점이 있지만, 자동화 도구가 경고를 버리면 개선으로 이어지지 않는다. CI에서 warning을 오류 또는 작업 항목으로 변환하는 운영 규칙이 필요하다.
세 모드는 동시에 서로 다른 수준으로 설정할 수 있다. 예를 들어 enforce=baseline, audit=restricted, warn=restricted로 설정하면 baseline은 강제하고 restricted 전환 준비 상태는 관찰한다. 프로덕션에서는 이 조합을 사용하여 가용성을 지키면서 더 강한 목표 수준의 위반을 줄여 나갈 수 있다.
3.1 정책 버전 고정
PSS의 기준은 Kubernetes 마이너 버전과 함께 변할 수 있다. pod-security.kubernetes.io/<MODE>-version 레이블을 사용하면 특정 버전의 기준을 고정할 수 있고, latest를 사용하면 현재 문서 기준을 따라간다. 클러스터 업그레이드 때 기준이 갑자기 강화되는 것을 막으려면 enforcement는 검증된 버전에 고정하고 audit·warn은 최신 기준으로 운영하는 방식을 검토한다.
버전 고정은 보안을 영원히 낮은 수준으로 유지하는 면허가 아니다. 고정 버전에서 허용되지만 최신 기준에서 제한되는 필드를 audit과 warn으로 가시화하고, 애플리케이션 수정 계획을 세워 다음 업그레이드 전에 기준을 올려야 한다. 특히 오래된 kubelet이 Pod OS 필드를 충분히 집행하지 못하는 혼합 버전 클러스터는 Restricted 버전 선택에 주의한다.
4. 주요 통제 항목과 적용 절차
4.1 호스트 격리와 권한 상승
hostNetwork, hostPID, hostIPC를 사용하면 Pod가 노드의 네트워크·프로세스·IPC 영역과 결합한다. 모니터링이나 네트워크 플러그인처럼 목적이 명확한 시스템 Pod를 제외하고는 이 필드를 허용하지 않는 것이 원칙이다. host namespace가 필요한 경우에도 동일 노드에 배치될 수 있는 다른 워크로드와 공격 경로를 분석해야 한다.
privileged 컨테이너는 대부분의 컨테이너 격리 메커니즘을 우회할 수 있다. allowPrivilegeEscalation이 true이면 실행 중인 프로세스가 setuid나 file capability를 통해 권한을 확대할 수 있으므로 restricted는 이를 false로 요구한다. runAsNonRoot와 runAsUser를 이미지의 실제 사용자 ID와 일치시키지 않으면 서비스가 시작되지 않을 수 있어, 이미지 빌드 단계의 사용자 정의가 중요하다.
Linux capability는 root 전체 권한보다 작지만, NET_ADMIN, SYS_ADMIN처럼 시스템에 영향을 줄 수 있는 권한은 공격면을 크게 만든다. restricted에서는 모든 capability를 제거한 뒤 정말 필요한 경우에만 NET_BIND_SERVICE를 추가하는 패턴을 사용한다. 애플리케이션이 높은 포트를 사용하도록 바꾸는 것이 capability 예외를 유지하는 것보다 안전할 수 있다.
4.2 seccomp·AppArmor·SELinux
seccomp는 컨테이너 프로세스가 호출할 수 있는 시스템 콜을 제한한다. RuntimeDefault는 런타임이 제공하는 기본 프로파일을 사용하고, 특수한 애플리케이션은 Localhost 프로파일을 명시할 수 있다. 프로파일 없이 privileged로 우회하면 장애는 줄어들어도 커널 공격면이 넓어지므로, 성능·호환성 테스트를 통해 필요한 시스템 콜만 허용해야 한다.
AppArmor와 SELinux는 이미지와 노드 운영체제의 정책에 의존한다. PSS가 특정 필드의 허용 형태를 검사하더라도, 실제 노드에서 프로파일이 로드되었는지와 감사 이벤트가 수집되는지는 별도로 검증해야 한다. 서로 다른 노드 OS를 섞는 경우 동일한 Pod가 보안 프로파일 차이로 다르게 동작할 수 있다.
4.3 YAML 설계와 공급망 연계
PSS 통과 여부는 최종 PodSpec을 기준으로 판단되므로 Helm 기본값, Kustomize overlay, Operator가 생성하는 템플릿을 모두 검사해야 한다. 개발자가 작성한 Deployment가 안전해도 Operator가 privileged init container를 추가하면 배포 결과는 달라진다. 따라서 렌더링된 매니페스트에 대해 서버 dry-run과 정책 검사를 수행한다.
이미지 서명과 SBOM은 PSS의 대체물이 아니다. 서명은 어떤 이미지를 배포했는지를, SBOM은 어떤 구성요소가 들어 있는지를, PSS는 그 이미지가 어떤 권한으로 실행되는지를 설명한다. 세 신호를 하나의 배포 승인 정책으로 결합하면 취약한 이미지와 과도한 런타임 권한을 동시에 줄일 수 있다.
4.4 권한 있는 워크로드의 면제
PSA는 사용자 이름, RuntimeClass, 네임스페이스를 명시적 면제 목록으로 구성할 수 있다. 면제 요청은 enforce, audit, warn을 모두 건너뛰므로 광범위한 면제는 사실상 정책 우회다. 서비스 계정을 면제할 때 그 서비스 계정으로 Deployment를 만들 수 있는 사용자까지 간접적으로 면제되는지 확인해야 한다.
면제는 “시스템이라서”가 아니라 구체적 기능과 통제책을 기준으로 승인해야 한다. 예를 들어 네트워크 플러그인 네임스페이스, 장치 플러그인 RuntimeClass, 노드 진단 도구의 이미지 digest와 실행 노드를 고정하고, RBAC·NetworkPolicy·감사 로그를 추가한다. 정기적으로 면제 목록을 재검토하여 더 이상 필요한 권한이 남아 있지 않도록 한다.
5. 적용·운영 절차
첫 단계는 모든 네임스페이스와 워크로드를 목록화하는 것이다. 시스템 네임스페이스, 빌드·배포 도구, 애플리케이션, 관측·보안 에이전트를 구분하고 privileged·hostPath·hostNetwork·capability 사용 현황을 수집한다. 레이블이 없는 네임스페이스를 “안전하다”가 아니라 “아직 평가하지 않았다”로 취급해야 한다.
둘째, 목표 수준을 정하고 warn과 audit을 먼저 켠다. 예를 들어 개발 네임스페이스는 baseline을 경고하고, 민감 서비스는 restricted를 경고·감사한다. 위반 필드와 소유 팀, 수정 난이도, 업무 영향도를 표로 관리하되, 실제 개선은 원인과 대안을 설명하는 산문형 런북으로 남긴다.
셋째, 테스트·스테이징에서 enforce를 적용한다. kubectl label --dry-run=server로 기존 Pod를 새 기준에 대입하고, Deployment·Job·CronJob·Operator가 생성하는 Pod까지 검증한다. 한 번의 성공적인 배포보다 롤링 업데이트, 장애 복구, 디버그 ephemeral container, 노드 교체를 포함한 운영 시나리오의 통과가 중요하다.
넷째, 프로덕션은 네임스페이스 단위로 점진 전환한다. 기본 애플리케이션은 baseline enforcement를 우선 적용하고, 수정이 끝난 서비스부터 restricted로 승격한다. 불가피한 privileged 워크로드는 별도 네임스페이스와 승인된 면제로 격리하며 일반 애플리케이션과 섞지 않는다.
다섯째, 업그레이드 전후의 기준 차이를 관찰한다. enforcement 버전을 고정했다면 최신 기준을 audit·warn으로 계속 평가하고, 새 Kubernetes 버전의 변경점을 릴리스 검증 항목으로 넣는다. 정책 위반 수, 면제 수, 배포 실패율, 보안 사고의 탐지 시간을 대시보드와 경영 지표로 연결한다.
6. 비교 분석
6.1 PSS와 범용 정책 엔진
PSS는 Kubernetes에 내장되고 세 가지 프로파일과 네임스페이스 레이블이라는 단순한 운영 모델을 제공한다. 설치·업그레이드해야 할 별도 웹훅이 적고, 기본 보안선을 빠르게 적용하는 데 유리하다. 반면 조직별 이미지 레지스트리, 허용된 registry prefix, hostPath 경로, 필드 간 조건 같은 세밀한 정책은 표현하기 어렵다.
OPA Gatekeeper나 Kyverno 같은 범용 엔진은 정책을 조직의 규칙으로 확장하고 감사·변조·자동 변환을 제공할 수 있다. 대신 웹훅의 가용성, 정책 순서, 성능, 실패 시 동작, CRD 수명주기를 운영해야 한다. 실무에서는 PSS로 공통 최소선을 강제하고, 범용 엔진으로 기업 고유의 추가 조건을 보완하는 조합이 합리적이다.
| 비교 축 | PSS·PSA | 범용 정책 엔진 |
|---|---|---|
| 설치 | Kubernetes 내장 기능 중심 | 별도 컨트롤러·웹훅 필요 |
| 정책 표현 | 세 프로파일과 Pod 보안 필드 | 조직별 조건·변환·검사 확장 |
| 적용 범위 | 주로 Pod 보안과 네임스페이스 | 이미지·레이블·리소스 관계 등 광범위 |
| 장점 | 단순성·일관성·낮은 도입 장벽 | 높은 표현력·자동화 |
| 주의점 | 세밀한 예외와 기업 규칙의 한계 | 웹훅 가용성·정책 충돌·운영 복잡성 |
6.2 PSS와 런타임 보안
PSS는 Pod 생성 또는 변경 시점의 예방 통제다. Falco 같은 런타임 도구는 실행 중인 프로세스, 파일 접근, 네트워크 행위를 관찰하여 정책을 우회한 공격이나 이미 실행된 이상 행위를 탐지한다. 전자는 “이 설정으로 시작하지 못하게 함”이고 후자는 “시작 후 이상 행동을 발견함”이므로 경쟁 관계가 아니라 방어 심층화 관계다.
예를 들어 restricted를 통과한 이미지가 애플리케이션 취약점을 통해 정상 프로세스에서 쉘을 실행하면 PSS만으로는 탐지할 수 없다. 반대로 런타임 탐지만 의존하면 공격이 실행된 뒤에야 대응하게 된다. Pod 생성 정책, 네트워크 격리, 이미지 신뢰, 런타임 탐지를 함께 운영해야 한다.
7. 적용 사례와 심화
7.1 금융 거래 API 클러스터
금융 거래 API는 restricted를 목표로 설정하고 enforce=baseline, audit=restricted, warn=restricted로 시작한다. 개발팀은 이미지에서 non-root 사용자와 read-only root filesystem을 지원하고, 플랫폼팀은 seccomp RuntimeDefault와 capability drop을 공통 Helm 차트에 반영한다. 감사 로그는 서비스별 위반과 승인된 면제를 추적한다.
스테이징에서 restricted enforcement를 켠 뒤 결제 승인·롤링 배포·장애 복구를 반복한다. 디버깅을 위해 임시 ephemeral container가 필요하다면 일반 운영자에게 unrestricted 권한을 주는 대신, 승인된 디버그 RuntimeClass와 짧은 TTL의 접근 계정을 사용한다. 이렇게 해야 장애 대응 편의가 장기적인 privileged 경로로 굳어지지 않는다.
7.2 제조 엣지 클러스터
공장 엣지 노드에서는 장치 플러그인과 네트워크 에이전트가 host namespace나 특정 capability를 요구할 수 있다. 이들을 애플리케이션 네임스페이스와 분리하고 면제 대상을 이미지 digest·RuntimeClass·서비스 계정으로 좁힌다. 센서 수집 서비스는 baseline 또는 restricted로 운영하여 현장 장비의 특권 경로가 업무 API로 확산되지 않게 한다.
엣지 클러스터는 연결이 불안정해 중앙 정책 업데이트가 늦을 수 있으므로, 클러스터 프로비저닝 단계에서 레이블과 PSA 설정을 선언하고 로컬 audit 로그를 보존한다. 중앙으로 복귀했을 때 면제 목록과 위반 이벤트를 동기화하여 현장별 예외가 누적되지 않도록 한다.
7.3 기출·연계 답안 전략
시험 답안에서는 PSS의 정의만 쓰기보다 “위험한 PodSpec → PSA 모드 판정 → API 응답 또는 감사 → kubelet 실행 → 런타임 관측”의 인과 흐름을 개념도로 제시하면 좋다. 그 다음 세 프로파일을 표로 요약하고 각 프로파일이 필요한 조직적 이유를 산문으로 설명한다.
유사 주제인 컨테이너 보안, DevSecOps, 제로 트러스트, 공급망 보안과 연결할 때는 통제 시점을 구분한다. PSS는 워크로드 권한, 이미지 서명은 출처, SBOM은 구성 투명성, NetworkPolicy는 통신 범위, 런타임 보안은 행위를 다룬다. 이 구분을 제시하면 “보안 도구를 많이 설치한다”는 나열식 답안을 피할 수 있다.
8. 고려사항 및 시사점
가용성과 최소권한의 균형을 설계해야 한다. Restricted를 무조건 즉시 강제하면 운영 도구와 배포가 중단될 수 있으므로 warn·audit으로 위반을 수집하고 서비스별 수정 순서를 정한다. 반대로 privileged를 기본값처럼 허용하면 사고 범위가 커지므로 예외는 별도 네임스페이스·RBAC·감사·만료일로 통제한다.
정책 버전과 클러스터 버전을 함께 관리해야 한다. Kubernetes 업그레이드로 PSS 기준이 달라질 수 있고, 혼합 버전 kubelet은 OS별 필드 집행이 다를 수 있다. enforcement 버전은 사전 검증하고 audit·warn은 최신 기준으로 운용하여 다음 업그레이드의 위험을 미리 발견한다.
면제를 보안 자산처럼 관리해야 한다. 사용자·RuntimeClass·네임스페이스 면제는 세 모드를 모두 건너뛰므로, 사유·소유자·이미지·허용 노드·만료일을 등록한다. 면제 서비스 계정이 생성할 수 있는 하위 리소스까지 검토하고 정기적인 접근 재인증을 실시한다.
PSS 밖의 통제를 명확히 연결해야 한다. PSS가 통과해도 취약한 이미지, 과도한 네트워크 접근, 탈취된 서비스 계정, 런타임 이상 행위는 남을 수 있다. 이미지 스캔·서명, SBOM·VEX, NetworkPolicy, Secret 관리, 런타임 탐지를 정책 흐름에 연결하고 각 통제의 소유자를 정한다.
운영 지표로 정책 효과를 검증해야 한다. 위반 건수만 줄이는 것이 목표가 아니라 privileged 비율, 면제 비율, 배포 실패율, 정책 예외의 평균 수명, 사고 탐지 시간을 함께 추적해야 한다. 이 지표가 있어야 보안 강화가 개발 생산성과 가용성에 미친 영향을 기술사 관점에서 설명할 수 있다.
참고자료
- https://kubernetes.io/docs/concepts/security/pod-security-standards/
- https://kubernetes.io/docs/concepts/security/pod-security-admission/
- https://kubernetes.io/docs/setup/best-practices/enforcing-pod-security-standards/
- https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels/
- https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-admission-controller/
한 줄 요약: PSS는 Pod 권한의 최소 보안선을 정의하고 PSA는 이를 네임스페이스별 warn·audit·enforce로 점진 적용하므로, 버전·면제·공급망·런타임 통제를 함께 설계해야 실효성 있는 컨테이너 보안이 된다.