從 PodSecurityPolicy 遷移至內建 PodSecurity 許可控制器
本頁說明從 PodSecurityPolicies 遷移至內建 PodSecurity 許可控制器的程序。這可以使用乾式執行與 audit
和 warn
模式的組合有效地完成,但如果使用 mutating PSPs,則會變得更加困難。
開始之前
您的 Kubernetes 伺服器必須為 v1.22 或更新版本。若要檢查版本,請輸入 kubectl version
。
如果您目前執行的 Kubernetes 版本不是 1.32,您可能需要切換到您實際執行的 Kubernetes 版本的文件中檢視此頁面。
本頁假設您已熟悉基本的 Pod 安全許可 概念。
整體方法
您可以採取多種策略從 PodSecurityPolicy 遷移至 Pod 安全許可。以下步驟是一種可能的遷移路徑,目標是盡可能減少生產中斷和安全性漏洞的風險。
- 決定 Pod 安全許可是否適合您的使用案例。
- 審閱命名空間權限
- 簡化與標準化 PodSecurityPolicies
- 更新命名空間
- 識別適當的 Pod 安全層級
- 驗證 Pod 安全層級
- 強制執行 Pod 安全層級
- 繞過 PodSecurityPolicy
- 審閱命名空間建立程序
- 停用 PodSecurityPolicy
0. 決定 Pod 安全許可是否適合您
Pod 安全許可旨在滿足開箱即用最常見的安全性需求,並在叢集之間提供一組標準的安全性層級。但是,它不如 PodSecurityPolicy 靈活。值得注意的是,PodSecurityPolicy 支援但 Pod 安全許可不支援以下功能
- 設定預設安全性約束 - Pod 安全許可是非變更許可控制器,表示它不會在驗證 Pod 之前修改 Pod。如果您依賴 PSP 的這一方面,您將需要修改您的工作負載以符合 Pod 安全約束,或使用 Mutating Admission Webhook 進行這些變更。請參閱下方的 簡化與標準化 PodSecurityPolicies 以取得更多詳細資訊。
- 精細控制策略定義 - Pod 安全許可僅支援 3 個標準層級。如果您需要更多控制特定約束,那麼您將需要使用 Validating Admission Webhook 來強制執行這些策略。
- 子命名空間策略細微性 - PodSecurityPolicy 允許您將不同的策略繫結至不同的服務帳戶或使用者,即使在單一命名空間內也是如此。這種方法有許多缺點且不建議使用,但如果您無論如何都需要此功能,您將需要使用第三方 webhook 來代替。但如果您的需求只是完全豁免特定使用者或 RuntimeClasses,則 Pod 安全許可確實公開了一些 豁免的靜態組態。
即使 Pod 安全許可不符合您的所有需求,它的設計也是為了補充其他策略強制執行機制,並且可以與其他許可 webhook 一起提供有用的後備方案。
1. 審閱命名空間權限
Pod 安全許可由 命名空間上的標籤 控制。這表示任何可以更新(或修補或建立)命名空間的人也可以修改該命名空間的 Pod 安全層級,這可用於繞過更嚴格的策略。在繼續之前,請確保只有受信任的特權使用者才擁有這些命名空間權限。不建議將這些強大權限授予不應擁有提升權限的使用者,但如果您必須這樣做,您將需要使用 許可 webhook 對在命名空間物件上設定 Pod 安全標籤施加額外限制。
2. 簡化與標準化 PodSecurityPolicies
在本節中,您將減少 mutating PodSecurityPolicies,並移除 Pod 安全標準範圍之外的選項。您應該對正在修改的原始 PodSecurityPolicy 的離線副本進行此處建議的變更。複製的 PSP 應具有與原始 PSP 不同的名稱,且在字母順序上位於原始 PSP 之前(例如,在其前面加上 0
)。請勿在 Kubernetes 中建立新策略 - 這將在下方的 推出更新的策略 章節中介紹。
2.a. 消除純粹的 mutating 欄位
如果 PodSecurityPolicy 正在變更 Pod,那麼當您最終關閉 PodSecurityPolicy 時,最終可能會導致 Pod 不符合 Pod 安全層級要求。為了避免這種情況,您應該在切換之前消除所有 PSP 變更。不幸的是,PSP 無法清楚地分隔變更和驗證欄位,因此這不是一個簡單的遷移。
您可以從消除純粹變更的欄位開始,這些欄位與驗證策略無關。這些欄位(也列在將 PodSecurityPolicy 對應到 Pod 安全標準 參考文件中)包括
.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 安全標準未涵蓋的選項
PodSecurityPolicy 中有幾個欄位未被 Pod 安全標準涵蓋。如果您必須強制執行這些選項,您將需要使用准入 webhook 來補充 Pod 安全准入,這不在本指南的範圍內。
首先,您可以移除 Pod 安全標準未涵蓋的純粹驗證欄位。這些欄位(也列在將 PodSecurityPolicy 對應到 Pod 安全標準 參考文件中,標示為「無意見」)包括
.spec.allowedHostPaths
.spec.allowedFlexVolumes
.spec.allowedCSIDrivers
.spec.forbiddenSysctls
.spec.runtimeClass
您也可以移除以下與 POSIX / UNIX 群組控制相關的欄位。
.spec.runAsGroup
.spec.supplementalGroups
.spec.fsGroup
剩餘的變更欄位是正確支援 Pod 安全標準所必需的,稍後需要根據具體情況逐一處理
.spec.requiredDropCapabilities
- 必須刪除ALL
以符合 Restricted 設定檔。.spec.seLinux
- (僅在使用MustRunAs
規則時變更)必須強制執行 Baseline 和 Restricted 設定檔的 SELinux 要求。.spec.runAsUser
- (使用RunAsAny
規則時不變更)必須強制執行 Restricted 設定檔的RunAsNonRoot
。.spec.allowPrivilegeEscalation
- (僅在設定為false
時變更)Restricted 設定檔的要求。
2.c. 部署更新後的 PSP
接下來,您可以將更新後的策略部署到您的叢集。您應該謹慎操作,因為移除變更選項可能會導致工作負載缺少必要的配置。
針對每個更新後的 PodSecurityPolicy
- 找出在原始 PSP 下執行的 Pod。這可以使用
kubernetes.io/psp
註釋來完成。例如,使用 kubectlPSP_NAME="original" # Set the name of the PSP you're checking for kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}"
- 將這些正在執行的 Pod 與原始 Pod 規格進行比較,以確定 PodSecurityPolicy 是否已修改 Pod。對於由工作負載資源建立的 Pod,您可以將 Pod 與控制器資源中的 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。如果任何 Roles 或 ClusterRoles 授予對所有 PSP 的
use
權限,這可能會導致使用新的 PSP 而不是其變更對應物。 - 更新您的授權,以授予對新 PSP 的訪問權限。在 RBAC 中,這表示更新任何授予對原始 PSP 的
use
權限的 Roles 或 ClusterRoles,以同時授予對更新後 PSP 的權限。 - 驗證:經過一段時間的浸泡期後,重新執行步驟 1 中的命令,以查看是否仍有任何 Pod 正在使用原始 PSP。請注意,Pod 需要在新策略部署後重新建立,才能完全驗證。
- (可選)一旦您驗證原始 PSP 不再使用,您可以刪除它們。
3. 更新命名空間
以下步驟需要在叢集中的每個命名空間上執行。這些步驟中引用的命令使用 $NAMESPACE
變數來指代正在更新的命名空間。
3.a. 識別合適的 Pod 安全層級
開始檢閱Pod 安全標準,並熟悉 3 個不同的層級。
有幾種方法可以為您的命名空間選擇 Pod 安全層級
- 依據命名空間的安全需求 - 如果您熟悉命名空間的預期存取層級,您可以根據這些需求選擇合適的層級,類似於在新叢集上處理此問題的方式。
- 依據現有的 PodSecurityPolicy - 使用將 PodSecurityPolicy 對應到 Pod 安全標準 參考文件,您可以將每個 PSP 對應到一個 Pod 安全標準層級。如果您的 PSP 不是基於 Pod 安全標準,您可能需要在選擇至少與 PSP 一樣寬鬆的層級,以及至少與其一樣嚴格的層級之間做出決定。您可以使用此命令查看給定命名空間中 Pod 正在使用的 PSP
kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u
- 依據現有的 Pod - 使用驗證 Pod 安全層級下的策略,您可以測試 Baseline 和 Restricted 層級,以查看它們是否對現有的工作負載足夠寬鬆,並選擇權限最小的有效層級。
注意
上述選項 2 和 3 是基於現有的 Pod,並且可能會遺漏目前未執行的工作負載,例如 CronJob、scale-to-zero 工作負載或其他尚未部署的工作負載。3.b. 驗證 Pod 安全層級
一旦您為命名空間選擇了 Pod 安全層級(或者如果您正在嘗試多個層級),最好先進行測試(如果使用 Privileged 層級,您可以跳過此步驟)。Pod 安全性包含多種工具,可協助測試和安全地部署設定檔。
首先,您可以對策略進行 dry-run,這將根據已套用的策略評估目前在命名空間中執行的 Pod,而不會使新策略生效
# $LEVEL is the level to dry-run, either "baseline" or "restricted".
kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
此命令將針對任何在建議層級下無效的現有 Pod 返回警告。
第二個選項更適合捕捉目前未執行的工作負載:稽核模式。當在稽核模式下執行(而不是強制執行)時,違反策略層級的 Pod 會記錄在稽核日誌中,可以在浸泡一段時間後稍後查看,但不會被禁止。警告模式的工作方式類似,但會立即向使用者返回警告。您可以使用此命令在命名空間上設定稽核層級
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL
如果這些方法中的任何一種產生意外的違規,您將需要更新違規的工作負載以符合策略要求,或放寬命名空間 Pod 安全層級。
3.c. 強制執行 Pod 安全層級
當您確信所選層級可以在命名空間上安全地強制執行時,您可以更新命名空間以強制執行所需的層級
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
3.d. 繞過 PodSecurityPolicy
最後,您可以透過將完全特權 PSP 繫結到命名空間中的所有服務帳戶,從而在命名空間層級有效地繞過 PodSecurityPolicy。
# The following cluster-scoped commands are only needed once.
kubectl apply -f privileged-psp.yaml
kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged
# Per-namespace disable
kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE
由於特權 PSP 是非變更性的,並且 PSP 准入控制器始終偏好非變更性的 PSP,因此這將確保此命名空間中的 Pod 不再受到 PodSecurityPolicy 的修改或限制。
像這樣在每個命名空間的基礎上停用 PodSecurityPolicy 的優點是,如果出現問題,您可以透過刪除 RoleBinding 輕鬆地回滾變更。只需確保預先存在的 PodSecurityPolicy 仍然存在!
# Undo PodSecurityPolicy disablement.
kubectl delete -n $NAMESPACE rolebinding disable-psp
4. 檢閱命名空間建立流程
既然現有的命名空間已更新為強制執行 Pod 安全准入,您應該確保更新您建立新命名空間的流程和/或策略,以確保將適當的 Pod 安全設定檔套用到新的命名空間。
您也可以靜態配置 Pod 安全准入控制器,為未標記的命名空間設定預設的強制執行、稽核和/或警告層級。有關更多資訊,請參閱配置准入控制器。
5. 停用 PodSecurityPolicy
最後,您已準備好停用 PodSecurityPolicy。為此,您需要修改 API 伺服器的准入配置:如何關閉准入控制器?。
為了驗證 PodSecurityPolicy 准入控制器不再啟用,您可以手動執行測試,方法是模擬一個無法存取任何 PodSecurityPolicy 的使用者(請參閱PodSecurityPolicy 範例),或透過在 API 伺服器日誌中驗證。啟動時,API 伺服器會輸出日誌行,列出已載入的准入控制器外掛程式
I0218 00:59:44.903329 13 plugins.go:158] Loaded 16 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,ServiceAccount,NodeRestriction,TaintNodesByCondition,Priority,DefaultTolerationSeconds,ExtendedResourceToleration,PersistentVolumeLabel,DefaultStorageClass,StorageObjectInUseProtection,RuntimeClass,DefaultIngressClass,MutatingAdmissionWebhook.
I0218 00:59:44.903350 13 plugins.go:161] Loaded 14 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,DenyServiceExternalIPs,ValidatingAdmissionWebhook,ResourceQuota.
您應該會看到 PodSecurity
(在驗證准入控制器中),並且兩個列表都不應包含 PodSecurityPolicy
。
一旦您確定 PSP 准入控制器已停用(並且經過足夠的浸泡時間以確信您不需要回滾),您可以自由刪除您的 PodSecurityPolicy 以及任何相關聯的 Roles、ClusterRoles、RoleBindings 和 ClusterRoleBindings(只需確保它們沒有授予任何其他不相關的權限)。