LabHub
배우기 러닝패스 코스

CKS — Kubernetes Security Specialist

Pod Security Admission and securityContext

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

네임스페이스 라벨만으로 워크로드의 보안 하한선을 정하는 방법을 익히고, restricted 프로파일을 실제로 통과하는 파드 스펙을 손으로 완성합니다.

왜 중요한가

PodSecurityPolicy 는 1.25 에서 제거됐습니다. 사용하려면 ServiceAccount 에 "이 PSP 를 use 할 권한"을 줘야 했는데 그 구조 자체가 권한 상승 경로였고, 여러 PSP 중 무엇이 적용될지 예측하기 어려웠기 때문입니다. 대체재인 PSA 는 네임스페이스 라벨 몇 줄로 끝나고, enforce·audit·warn 세 모드를 따로 켤 수 있어 점진적 도입이 가능합니다. 기존 클러스터에 곧바로 enforce 를 걸면 워크로드가 대량으로 막히므로 warn 과 audit 를 먼저 켜서 관찰하는 것이 표준 절차입니다.

restricted 프로파일이 요구하는 네 가지(runAsNonRoot, allowPrivilegeEscalation false, capabilities drop ALL, seccompProfile)는 CKS 에서 가장 자주 나오는 조합입니다. 외우는 것보다 직접 하나씩 빼 보면서 어떤 오류가 나는지 확인하는 편이 오래 갑니다.

이 환경의 API 서버에는 PodSecurity 어드미션이 켜져 있으므로, 위반 파드는 실제로 거부됩니다.

단계

  1. 네임스페이스 cks-psa 를 만들고 라벨 pod-security.kubernetes.io/enforce=baseline 을 붙인다.
  2. 네임스페이스 cks-psa-strict 를 만들고 enforce·audit·warn 세 라벨을 모두 restricted 로, 그리고 enforce-version·audit-version·warn-version 세 라벨을 모두 latest 로 붙인다.
  3. cks-psa-strict 에 파드 hardened(컨테이너 이름 app, 이미지 nginx:1.27-alpine)를 만든다. restricted 를 통과해야 하므로 파드 레벨에 runAsNonRoot: trueseccompProfile.type: RuntimeDefault, 컨테이너 레벨에 allowPrivilegeEscalation: falsecapabilities.drop: [ALL] 이 필요하다.
  4. cks-psa-strictprivileged: true 컨테이너를 가진 파드 bad-pod 를 apply 해 본다. 그 출력(표준 오류 포함)을 /root/cks-securitycontext/denied.txt 에 저장한다. 파드는 생성되면 안 된다.
  5. cks-psa 에 파드 nonroot-app(컨테이너 이름 app)을 만든다. 파드 레벨 securityContext 에 runAsNonRoot: true, runAsUser: 10001, runAsGroup: 10001, fsGroup: 20001 을 넣는다.
  6. cks-psa-strict 에 파드 dropped(컨테이너 이름 app)를 만든다. 파드 레벨 seccompProfile.typeRuntimeDefault, runAsNonRoottrue 이고, 컨테이너 레벨에 allowPrivilegeEscalation: false, capabilities.drop: [ALL], readOnlyRootFilesystem: true 를 넣는다.
  7. RuntimeClass cks-sandbox 를 만든다. handlerrunsc, overhead.podFixed 는 메모리 160Mi 와 CPU 250m 이다.
  8. cks-psa-strict 에 Deployment payments 를 만든다. replicas 2, 셀렉터와 파드 라벨은 app=payments, 파드 스펙의 runtimeClassNamecks-sandbox 이고, 파드 템플릿은 restricted 를 통과하도록 3 단계와 같은 네 조건을 모두 갖춘다.

참고

baseline 프로파일 적용

네임스페이스 cks-psa 를 만들고 라벨 pod-security.kubernetes.io/enforce=baseline 을 붙인다.

PSA 는 네임스페이스 라벨로 동작합니다. 라벨 키는 pod-security.kubernetes.io/ 로 시작합니다.

세 모드와 버전 라벨 전부 걸기

네임스페이스 cks-psa-strict 를 만들고 enforce·audit·warn 세 라벨을 모두 restricted 로, 그리고 enforce-version·audit-version·warn-version 세 라벨을 모두 latest 로 붙인다.

enforce·audit·warn 각각에 대응하는 -version 라벨이 따로 있습니다. 버전을 못 박으면 클러스터 업그레이드가 곧 정책 강화로 이어지지 않습니다.

restricted 를 통과하는 파드

cks-psa-strict 에 파드 hardened(컨테이너 이름 app, 이미지 nginx:1.27-alpine)를 만든다. restricted 를 통과해야 하므로 파드 레벨에 runAsNonRoot: trueseccompProfile.type: RuntimeDefault, 컨테이너 레벨에 allowPrivilegeEscalation: falsecapabilities.drop: [ALL] 이 필요하다.

restricted 는 네 가지를 필수로 요구합니다. 하나라도 빠지면 거부되고, 오류 메시지가 어떤 필드가 걸렸는지 알려 줍니다.

한 가지 더 알아 두세요. runAsNonRoot: trueUID 를 정해 주지 않습니다. "root 로 돌지 마라" 고 말할 뿐이라, 이미지가 UID 를 지정하지 않으면 진짜 노드에서는 kubelet 이 파드를 띄우지 못하고 CreateContainerConfigError 를 냅니다. 실제 클러스터에서는 runAsUser 를 함께 박거나 비-root 로 만들어진 이미지를 쓰세요. 이 실습 환경은 파드를 실제로 실행하지 않아 그 차이가 드러나지 않습니다.

위반 파드가 거부되는지 확인

cks-psa-strictprivileged: true 컨테이너를 가진 파드 bad-pod 를 apply 해 본다. 그 출력(표준 오류 포함)을 /root/cks-securitycontext/denied.txt 에 저장한다. 파드는 생성되면 안 된다.

apply 의 표준 출력과 표준 오류를 함께 파일로 남겨야 합니다. 2>&1 | tee 를 쓰세요. 파드가 만들어졌다면 정책이 걸리지 않은 것입니다.

실행 사용자와 그룹 지정

cks-psa 에 파드 nonroot-app(컨테이너 이름 app)을 만든다. 파드 레벨 securityContext 에 runAsNonRoot: true, runAsUser: 10001, runAsGroup: 10001, fsGroup: 20001 을 넣는다.

runAsUser/runAsGroup/fsGroup 은 파드 레벨 securityContext 에, runAsNonRoot 는 양쪽 다 가능합니다. fsGroup 은 볼륨 파일의 그룹 소유권을 바꿉니다.

seccomp 와 capability 조합

cks-psa-strict 에 파드 dropped(컨테이너 이름 app)를 만든다. 파드 레벨 seccompProfile.typeRuntimeDefault, runAsNonRoottrue 이고, 컨테이너 레벨에 allowPrivilegeEscalation: false, capabilities.drop: [ALL], readOnlyRootFilesystem: true 를 넣는다.

restricted 네임스페이스이므로 이 파드도 네 가지 필수 조건을 모두 만족해야 생성됩니다.

RuntimeClass 오브젝트

RuntimeClass cks-sandbox 를 만든다. handlerrunsc, overhead.podFixed 는 메모리 160Mi 와 CPU 250m 이다.

RuntimeClass 는 클러스터 범위 리소스입니다. handler 값은 노드의 컨테이너 런타임 설정에 있는 런타임 이름과 문자 단위로 같아야 합니다.

종합: 샌드박스 런타임 배포

cks-psa-strict 에 Deployment payments 를 만든다. replicas 2, 셀렉터와 파드 라벨은 app=payments, 파드 스펙의 runtimeClassNamecks-sandbox 이고, 파드 템플릿은 restricted 를 통과하도록 3 단계와 같은 네 조건을 모두 갖춘다.

Deployment 의 파드 템플릿도 PSA 검사를 받습니다. 앞에서 만든 RuntimeClass 이름을 파드 스펙의 runtimeClassName 에 씁니다.