KCSA — 쿠버네티스 보안 어소시에이트 · 플랫폼 보안 · 실습
Pod Security Admission 을 라벨로 걸기
목표
네임스페이스 라벨만으로 파드 보안 정책을 걸어 보고, restricted 위반 파드가 실제로 거부되는 것과
그 거부 메시지를 확인하고, 마지막으로 등급을 올려도 이미 돌고 있는 파드는 쫓겨나지 않는다는
PSA 의 핵심 성질을 직접 관찰합니다.
왜 중요한가
PSP 가 실패한 이유는 기능이 부족해서가 아니라 디버깅이 불가능했기 때문입니다.
여러 PSP 가 매칭될 때 어느 것이 적용됐는지 알기 어려웠고, mutating 이라 내가 쓴 스펙과
실행되는 스펙이 달랐습니다. 쓰이지 않는 보안 기능은 보안이 아닙니다.
PSA 는 그 교훈으로 만들어졌습니다. 라벨 하나면 정책이고, 거부 메시지에 위반 필드가 다 나옵니다.
표현력을 잃은 대신 운영 가능성을 얻은 교환이며, 이런 교환이 왜 옳았는지 이해하는 것이
KCSA 에서 자주 묻는 지점입니다.
7 단계가 이 실습의 하이라이트입니다. PSA 는 어드미션 시점에만 동작하므로enforce 를 restricted 로 올려도 이미 도는 파드는 그대로 삽니다. 아무 일도 안 일어난 것처럼
보이다가 다음 롤아웃이나 노드 교체 때 파드가 안 뜨면서 터집니다.
정책 변경과 사고 사이에 시차가 있다는 것을 손으로 확인해 두면 마이그레이션을 설계할 때 달라집니다.
단계
1. 네임스페이스 kcsa-psa-baseline 을 만들고 라벨 네 개를 붙입니다 — 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.
2. 네임스페이스 kcsa-psa-restricted 를 만들고 라벨 네 개를 붙입니다 — 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. kcsa-psa-restricted 에 privileged 컨테이너를 가진 파드 bad 를 만들려고 시도합니다. 거부되어야 하며, 그 거부 메시지 전체를 /root/kcsa-psa/reject.txt 에 저장합니다. 파드 bad 는 끝까지 만들어지지 않은 상태여야 합니다.
4. kcsa-psa-baseline 에 파드 app-baseline 을 만듭니다 — 이미지 nginx:1.27-alpine, securityContext 는 아무것도 지정하지 않습니다. Running 까지 갑니다.
5. kcsa-psa-restricted 에 파드 app-restricted 를 만듭니다 — 이미지 nginx:1.27-alpine, 파드 레벨에 securityContext.runAsNonRoot: true 와 securityContext.seccompProfile.type: RuntimeDefault, 컨테이너 레벨에 allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], runAsUser: 1000.
6. /root/kcsa-psa/exempt.yaml 에 AdmissionConfiguration 을 작성합니다 — plugins[0].name 은 PodSecurity, configuration.kind 는 PodSecurityConfiguration, defaults.enforce 는 baseline, exemptions.namespaces 의 첫 항목은 kube-system. 그리고 /root/kcsa-psa/exempt-note.txt 에 PSA 면제의 세 축을 한 줄씩 정확히 usernames, runtimeClasses, namespaces 로 적습니다.
7. kcsa-psa-baseline 의 enforce 라벨만 restricted 로 바꿉니다. 그다음 (a) 기존 파드 app-baseline 의 현재 상태를 확인해 /root/kcsa-psa/upgrade.txt 에 existing-pod=<상태> 로 적고, (b) 4단계와 같은 스펙의 파드 app-baseline2 를 만들어 보고 거부되는 것을 확인한 뒤 같은 파일에 new-pod=rejected 줄을 추가합니다. 파드 app-baseline2 는 만들어지지 않은 상태여야 합니다.
참고
- 라벨은
kubectl label namespace <이름> <키>=<값>으로 붙이고, 이미 있는 값을 바꿀 때는--overwrite가 필요합니다. - 거부 메시지는 표준 에러로 나오므로
kubectl apply -f bad.yaml 2> /root/kcsa-psa/reject.txt처럼 저장해야 합니다. - 파드 상태는
kubectl get pod app-baseline -n kcsa-psa-baseline -o jsonpath='{.status.phase}'로 확인합니다. - 흔한 실수 1: 4단계 파드에 보안 설정을 미리 넣어 두는 것. 그러면 7단계에서 대비가 사라지고 채점도 통과하지 못합니다.
- 흔한 실수 2: 3단계나 7단계에서 거부된 파드를 어떻게든 만들려고 라벨을 잠깐 낮추는 것. 채점은 그 파드가 없는 것을 확인합니다.
단계 7개
- baseline 네임스페이스 만들기
- restricted 네임스페이스 만들기
- restricted 위반 파드가 거부되는지 확인
- baseline 만 통과하는 평범한 파드
- restricted 를 통과하는 파드
- 면제 설정과 면제 축 정리
- 라벨만 올렸을 때 기존 파드는 어떻게 되나