PodSecurityPolicy에서 내장 Pod Security 승인 컨트롤러로 마이그레이션하기
PodSecurityPolicy에서 내장 Pod Security 승인 컨트롤러로 마이그레이션하기
이 페이지는 PodSecurityPolicy에서 내장 PodSecurity 승인 컨트롤러로 마이그레이션하는 과정을 설명해요. dry-run과 audit, warn 모드를 조합하면 효과적으로 수행할 수 있지만, 변경(mutating) PSP를 사용한다면 더 어려워져요.
출처: 문서
본문
시작하기 전에 (Before you begin)
쿠버네티스 서버가 최소 v1.22 버전이어야 해요. 버전을 확인하려면 kubectl version을 입력하세요. 현재 1.37이 아닌 다른 버전의 쿠버네티스를 실행 중이라면, 실제로 실행 중인 쿠버네티스 버전의 문서에서 이 페이지를 볼 수 있도록 전환하고 싶을 거예요.
이 페이지는 기본 Pod Security Admission 개념에 이미 익숙하다고 가정해요.
전반적인 접근 방식 (Overall approach)
PodSecurityPolicy에서 Pod Security Admission으로 마이그레이션할 때 취할 수 있는 전략은 여러 가지가 있어요. 다음 단계는 프로덕션 중단과 보안 공백의 위험을 모두 최소화하는 것을 목표로 하는 가능한 마이그레이션 경로 중 하나예요.
- Pod Security Admission이 여러분의 사용 사례에 맞는지 결정
- 네임스페이스 권한 검토
- PodSecurityPolicy 단순화 및 표준화
- 네임스페이스 업데이트 — 적절한 Pod Security 레벨 식별
- Pod Security 레벨 검증
- Pod Security 레벨 강제
- PodSecurityPolicy 우회
- 네임스페이스 생성 프로세스 검토
- PodSecurityPolicy 비활성화
0. Pod Security Admission이 적합한지 결정하기 (Decide whether Pod Security Admission is right for you)
Pod Security Admission은 가장 일반적인 보안 요구를 즉시, 그리고 클러스터 전반에 걸친 표준 보안 레벨 집합을 제공하도록 설계됐어요. 하지만 PodSecurityPolicy보다는 덜 유연해요. 특히 다음 기능은 PodSecurityPolicy가 지원하지만 Pod Security Admission은 지원하지 않아요.
- 기본 보안 제약 설정 — Pod Security Admission은 변경하지 않는(non-mutating) 승인 컨트롤러예요. 즉 파드를 검증하기 전에 수정하지 않아요. PSP의 이 측면에 의존했다면, 워크로드를 Pod Security 제약을 충족하도록 수정하거나 Mutating Admission Webhook를 사용해 그 변경을 수행해야 해요. 아래 Simplify & Standardize PodSecurityPolicies에서 자세히 봐요.
- 정책 정의의 세밀한 제어 — Pod Security Admission은 3가지 표준 레벨만 지원해요. 특정 제약에 대해 더 많은 제어가 필요하다면 Validating Admission Webhook를 사용해 그 정책을 강제해야 해요.
- 하위 네임스페이스 정책 세분성 — PodSecurityPolicy는 단일 네임스페이스 안에서도 다른 Service Account나 사용자에 다른 정책을 바인딩할 수 있게 해 줘요. 이 접근은 많은 함정이 있어 권장되지 않지만, 어쨌든 이 기능이 필요하다면 서드파티 웹훅을 대신 사용해야 해요. 예외는 특정 사용자나 RuntimeClass를 완전히 면제하기만 하면 되는 경우인데, 이 경우 Pod Security Admission이 면제를 위한 정적 구성을 노출해요.
Pod Security Admission이 모든 요구를 충족하지 못하더라도, 다른 정책 강제 메커니즘을 보완하도록 설계됐으며 다른 승인 웹훅과 함께 유용한 폴백으로서 실행될 수 있어요.
1. 네임스페이스 권한 검토하기 (Review namespace permissions)
Pod Security Admission은 네임스페이스의 라벨로 제어돼요. 이는 네임스페이스를 업데이트(또는 patch, create)할 수 있는 사람은 누구나 그 네임스페이스의 Pod Security 레벨을 수정할 수 있다는 뜻이며, 이는 더 제한적인 정책을 우회하는 데 사용될 수 있어요. 진행하기 전에 신뢰할 수 있는 권한 있는 사용자만 이러한 네임스페이스 권한을 가지도록 하세요. 이러한 강력한 권한을 상승된 권한이 없어야 하는 사용자에게 부여하는 것은 권장되지 않지만, 어쩔 수 없다면 Namespace 객체에 Pod Security 라벨 설정에 추가 제한을 두기 위해 승인 웹훅을 사용해야 해요.
2. PodSecurityPolicy 단순화 및 표준화하기 (Simplify & standardize PodSecurityPolicies)
이 섹션에서는 변경(mutating) PodSecurityPolicy를 줄이고 Pod Security Standards의 범위 밖에 있는 옵션을 제거할 거예요. 여기서 권장하는 변경 사항은 수정 중인 원래 PodSecurityPolicy의 오프라인 복사본에 적용해야 해요. 복제된 PSP는 알파벳순으로 원본보다 앞에 오는 다른 이름을 가져야 해요(예: 0을 앞에 붙임). 아직 쿠버네티스에 새 정책을 만들지 마세요 — 그것은 아래 "업데이트된 정책 롤아웃" 섹션에서 다룰 거예요.
2.a. 순수하게 변경적인 필드 제거하기 (Eliminate purely mutating fields)
PodSecurityPolicy가 파드를 변경한다면, 결국 PodSecurityPolicy를 끄면 Pod Security 레벨 요구 사항을 충족하지 못하는 파드가 생길 수 있어요. 이를 피하려면 전환하기 전에 모든 PSP 변경을 제거해야 해요. 안타깝게도 PSP는 변경 필드와 검증 필드를 깔끔하게 분리하지 않아서, 이것은 간단한 마이그레이션이 아니에요.
순수하게 변경적이고 검증 정책과 아무 관련이 없는 필드를 제거하는 것부터 시작할 수 있어요. 이 필드들(PodSecurityPolicies를 Pod Security Standards에 매핑하기 참조에도 나열됨)은 다음과 같아요.
.spec.defaultAllowPrivilegeEscalation.spec.runtimeClass.defaultRuntimeClassName.metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName'].metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName'].spec.defaultAddCapabilities— 기술적으로 변경 및 검증 필드이지만, 변경 없이 동일한 검증을 수행하는.spec.allowedCapabilities로 병합해야 해요.
주의: 이것들을 제거하면 워크로드가 필요한 구성을 누락하고 문제가 생길 수 있어요. 이러한 변경을 안전하게 롤아웃하는 방법은 아래 "업데이트된 정책 롤아웃"을 참고하세요.
2.b. Pod Security Standards가 다루지 않는 옵션 제거하기 (Eliminate options not covered by the Pod Security Standards)
PodSecurityPolicy에는 Pod Security Standards가 다루지 않는 필드가 몇 개 있어요. 이 옵션들을 강제해야 한다면 Pod Security Admission을 승인 웹훅으로 보완해야 하는데, 이는 이 가이드의 범위 밖이에요.
먼저 Pod Security Standards가 다루지 않는 순수 검증 필드를 제거할 수 있어요. 이 필드들(Mapping... 참조에서 "no opinion"으로 나열됨)은 다음과 같아요.
.spec.allowedHostPaths.spec.allowedFlexVolumes.spec.allowedCSIDrivers.spec.forbiddenSysctls.spec.runtimeClass
또한 POSIX/UNIX 그룹 제어와 관련된 다음 필드도 제거할 수 있어요.
주의: 이 중 어떤 것이
MustRunAs전략을 사용한다면 변경적일 수 있어요! 이것들을 제거하면 워크로드가 필요한 그룹을 설정하지 못하고 문제가 생길 수 있어요. 아래 "업데이트된 정책 롤아웃"을 참고하세요.
.spec.runAsGroup.spec.supplementalGroups.spec.fsGroup
나머지 변경적 필드는 Pod Security Standards를 제대로 지원하는 데 필요하며 나중에 사례별로 처리해야 해요.
.spec.requiredDropCapabilities— Restricted 프로파일에ALL을 드롭하는 데 필요..spec.seLinux— (MustRunAs규칙에서만 변경적) Baseline & Restricted 프로파일의 SELinux 요구를 강제하는 데 필요..spec.runAsUser— (RunAsAny규칙에서 비변경적) Restricted 프로파일의RunAsNonRoot를 강제하는 데 필요..spec.allowPrivilegeEscalation— (false로 설정할 때만 변경적) Restricted 프로파일에 필요.
2.c. 업데이트된 PSP 롤아웃하기 (Rollout the updated PSPs)
다음으로 업데이트된 정책을 클러스터에 롤아웃할 수 있어요. 변경 옵션을 제거하면 워크로드가 필요한 구성을 누락할 수 있으므로 주의해서 진행해야 해요.
각 업데이트된 PodSecurityPolicy에 대해:
원래 PSP에서 실행 중인 파드를 식별해요. 이는 kubernetes.io/psp 어노테이션으로 할 수 있어요. 예를 들어 kubectl을 사용해:
PSP_NAME="original" # 확인 중인 PSP의 이름 설정
kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}"
이 실행 중인 파드를 원래 파드 스펙과 비교해 PodSecurityPolicy가 파드를 수정했는지 결정해요. 워크로드 리소스로 생성된 파드의 경우 파드를 컨트롤러 리소스의 PodTemplate과 비교할 수 있어요. 변경이 식별되면 원래 Pod 또는 PodTemplate을 원하는 구성으로 업데이트해야 해요. 검토할 필드는 다음과 같아요.
.metadata.annotations['container.apparmor.security.beta.kubernetes.io/*'](*를 각 컨테이너 이름으로 교체).spec.runtimeClassName.spec.securityContext.fsGroup.spec.securityContext.seccompProfile.spec.securityContext.seLinuxOptions.spec.securityContext.supplementalGroups- 컨테이너의 경우
.spec.containers[*]와.spec.initContainers[*]아래:.securityContext.allowPrivilegeEscalation.securityContext.capabilities.add.securityContext.capabilities.drop.securityContext.readOnlyRootFilesystem.securityContext.runAsGroup.securityContext.runAsNonRoot.securityContext.runAsUser.securityContext.seccompProfile.securityContext.seLinuxOptions
새 PodSecurityPolicy를 만들어요. 모든 PSP에 use를 부여하는 Role 또는 ClusterRole이 있다면 이로 인해 변경하는 대응 항목 대신 새 PSP가 사용될 수 있어요.
새 PSP에 접근을 부여하도록 인가를 업데이트해요. RBAC에서 이는 원래 PSP에 use 권한을 부여하는 Role이나 ClusterRole을 업데이트해 업데이트된 PSP에도 부여함을 의미해요.
검증: 일정 시간이 지난 후 1단계의 명령을 다시 실행해 여전히 원래 PSP를 사용하는 파드가 있는지 확인해요. 파드는 새 정책이 롤아웃된 후 재생성되어야 완전히 검증될 수 있다는 점에 주의하세요.
(선택) 원래 PSP가 더 이상 사용되지 않는 것을 확인한 후 삭제할 수 있어요.
3. 네임스페이스 업데이트하기 (Update Namespaces)
다음 단계는 클러스터의 모든 네임스페이스에서 수행해야 해요. 이 단계에서 참조하는 명령은 $NAMESPACE 변수를 사용해 업데이트 중인 네임스페이스를 가리켜요.
3.a. 적절한 Pod Security 레벨 식별하기 (Identify an appropriate Pod Security level)
Pod Security Standards를 검토하고 3가지 레벨에 익숙해지는 것부터 시작하세요. 네임스페이스의 Pod Security 레벨을 선택하는 방법은 여러 가지가 있어요.
- 네임스페이스의 보안 요구 사항으로 — 네임스페이스의 예상 접근 레벨에 익숙하다면 그 요구 사항에 기반해 적절한 레벨을 선택할 수 있어요. 새 클러스터에서 접근하는 방식과 비슷해요.
- 기존 PodSecurityPolicy로 — "PodSecurityPolicies를 Pod Security Standards에 매핑하기" 참조를 사용해 각 PSP를 Pod Security Standard 레벨에 매핑할 수 있어요. PSP가 Pod Security Standards에 기반하지 않았다면, 최소한 PSP만큼 허용적인 레벨을 선택할지 최소한만큼 제한적인 레벨을 선택할지 결정해야 할 수 있어요. 주어진 네임스페이스의 파드에 어떤 PSP가 사용 중인지 이 명령으로 확인할 수 있어요.
kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u
- 기존 파드로 — "Pod Security 레벨 검증"의 전략을 사용해 Baseline과 Restricted 레벨을 모두 테스트해 기존 워크로드에 충분히 허용적인지 확인하고, 최소 권한의 유효한 레벨을 선택할 수 있어요.
주의: 위 옵션 2와 3은 기존 파드에 기반하므로, 현재 실행되지 않는 CronJob, scale-to-zero 워크로드, 또는 아직 롤아웃되지 않은 다른 워크로드를 놓칠 수 있어요.
3.b. Pod Security 레벨 검증하기 (Verify the Pod Security level)
네임스페이스에 대한 Pod Security 레벨을 선택했다면(또는 여러 개를 시도한다면) 먼저 테스트하는 것이 좋아요 (Privileged 레벨을 사용한다면 이 단계를 건너뛸 수 있어요). Pod Security에는 프로파일을 테스트하고 안전하게 롤아웃하는 데 도움이 되는 여러 도구가 포함돼 있어요.
먼저 정책을 dry-run할 수 있어요. 이는 새 정책을 적용하지 않고 네임스페이스에서 현재 실행 중인 파드를 적용된 정책에 대해 평가해요.
# $LEVEL은 dry-run할 레벨, "baseline" 또는 "restricted" 중 하나
kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
이 명령은 제안된 레벨 아래에서 유효하지 않은 기존 파드에 대한 경고를 반환해요.
두 번째 옵션은 현재 실행되지 않는 워크로드를 잡는 데 더 좋아요: audit 모드. audit 모드에서(강제 대신) 정책 레벨을 위반하는 파드는 감사 로그에 기록되며, 일정 시간 후 검토할 수 있지만 금지되지는 않아요. warn 모드는 비슷하게 동작하지만 경고를 사용자에게 즉시 반환해요. 다음 명령으로 네임스페이스에 감사 레벨을 설정할 수 있어요.
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL
이 두 접근 방식 중 하나가 예상치 못한 위반을 산출하면, 위반 워크로드를 정책 요구 사항을 충족하도록 업데이트하거나 네임스페이스 Pod Security 레벨을 완화해야 해요.
3.c. Pod Security 레벨 강제하기 (Enforce the Pod Security level)
선택한 레벨이 네임스페이스에서 안전하게 강제될 수 있다고 만족한다면, 네임스페이스를 원하는 레벨을 강제하도록 업데이트할 수 있어요.
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
이 시점에서 정책 위반을 일으키며 실행하거나 생성되는 어떤 파드도 차단됩니다. 위반 워크로드를 계속 실행해야 한다면 네임스페이스 Pod Security 레벨을 재평가해야 합니다.
3.d. PodSecurityPolicy 우회하기 (Bypass PodSecurityPolicy)
PodSecurityPolicy를 우회할 수 있는 경우는 몇 가지가 있어요.
- 오직 권한 있는 사용자를 위한 것: 시도를 허용하기 전에 권한 있는 RBAC 그룹에서만
use권한을 유지하세요. Pod Security Admission은 여러분의 파드가 더 이상 PodSecurityPolicy에 따라 차단되지 않기 때문에 이제 적용될 것입니다. - 런타임 클래스 또는 사용자 면제: Pod Security Admission의 면제 구성을 검토하고 필요한 면제를 추가하세요.
다음 섹션들에서는 네임스페이스 생성 프로세스 검토와 PodSecurityPolicy 비활성화를 다루며, 모든 워크로드가 새 Pod Security Admission 정책을 준수한 것을 확인한 뒤 PSP 컨트롤러를 비활성화하는 과정을 안내합니다.