CKS — 쿠버네티스 보안 전문가 · 마이크로서비스 취약점 최소화 · 실습
Pod Security Admission 과 securityContext
목표
네임스페이스 라벨만으로 워크로드의 보안 하한선을 정하는 방법을 익히고, 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: true 와seccompProfile.type: RuntimeDefault, 컨테이너 레벨에 allowPrivilegeEscalation: false
와 capabilities.drop: [ALL] 이 필요하다.
4. cks-psa-strict 에 privileged: 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.type 은 RuntimeDefault, runAsNonRoot 는 true 이고,
컨테이너 레벨에 allowPrivilegeEscalation: false, capabilities.drop: [ALL],readOnlyRootFilesystem: true 를 넣는다.
7. RuntimeClass cks-sandbox 를 만든다. handler 는 runsc, overhead.podFixed 는
메모리 160Mi 와 CPU 250m 이다.
8. cks-psa-strict 에 Deployment payments 를 만든다. replicas 2, 셀렉터와 파드 라벨은app=payments, 파드 스펙의 runtimeClassName 은 cks-sandbox 이고, 파드 템플릿은
restricted 를 통과하도록 3 단계와 같은 네 조건을 모두 갖춘다.
참고
kubectl label ns cks-psa-strict pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/enforce-version=latest ...- 4 단계 실행 예:
kubectl apply -f bad-pod.yaml 2>&1 | tee /root/cks-securitycontext/denied.txt kubectl explain pod.spec.securityContext와kubectl explain pod.spec.containers.securityContext는 서로 다른 필드 목록을 보여 줍니다.- 흔한 실수 1:
capabilities를 파드 레벨에 넣습니다. 컨테이너 레벨 전용입니다. - 흔한 실수 2:
-version라벨을 빼먹으면 클러스터 업그레이드 때 프로파일 정의가 바뀌어 멀쩡하던 파드가 거부될 수 있습니다.
단계 8개
- baseline 프로파일 적용
- 세 모드와 버전 라벨 전부 걸기
- restricted 를 통과하는 파드
- 위반 파드가 거부되는지 확인
- 실행 사용자와 그룹 지정
- seccomp 와 capability 조합
- RuntimeClass 오브젝트
- 종합: 샌드박스 런타임 배포