從 PodSecurityPolicy 遷移至內建 PodSecurity 許可控制器

本頁說明從 PodSecurityPolicies 遷移至內建 PodSecurity 許可控制器的程序。這可以使用乾式執行與 auditwarn 模式的組合有效地完成,但如果使用 mutating PSPs,則會變得更加困難。

開始之前

您的 Kubernetes 伺服器必須為 v1.22 或更新版本。若要檢查版本,請輸入 kubectl version

如果您目前執行的 Kubernetes 版本不是 1.32,您可能需要切換到您實際執行的 Kubernetes 版本的文件中檢視此頁面。

本頁假設您已熟悉基本的 Pod 安全許可 概念。

整體方法

您可以採取多種策略從 PodSecurityPolicy 遷移至 Pod 安全許可。以下步驟是一種可能的遷移路徑,目標是盡可能減少生產中斷和安全性漏洞的風險。

  1. 決定 Pod 安全許可是否適合您的使用案例。
  2. 審閱命名空間權限
  3. 簡化與標準化 PodSecurityPolicies
  4. 更新命名空間
    1. 識別適當的 Pod 安全層級
    2. 驗證 Pod 安全層級
    3. 強制執行 Pod 安全層級
    4. 繞過 PodSecurityPolicy
  5. 審閱命名空間建立程序
  6. 停用 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

  1. 找出在原始 PSP 下執行的 Pod。這可以使用 kubernetes.io/psp 註釋來完成。例如,使用 kubectl
    PSP_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}"
    
  2. 將這些正在執行的 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
  3. 建立新的 PodSecurityPolicy。如果任何 Roles 或 ClusterRoles 授予對所有 PSP 的 use 權限,這可能會導致使用新的 PSP 而不是其變更對應物。
  4. 更新您的授權,以授予對新 PSP 的訪問權限。在 RBAC 中,這表示更新任何授予對原始 PSP 的 use 權限的 Roles 或 ClusterRoles,以同時授予對更新後 PSP 的權限。
  5. 驗證:經過一段時間的浸泡期後,重新執行步驟 1 中的命令,以查看是否仍有任何 Pod 正在使用原始 PSP。請注意,Pod 需要在新策略部署後重新建立,才能完全驗證。
  6. (可選)一旦您驗證原始 PSP 不再使用,您可以刪除它們。

3. 更新命名空間

以下步驟需要在叢集中的每個命名空間上執行。這些步驟中引用的命令使用 $NAMESPACE 變數來指代正在更新的命名空間。

3.a. 識別合適的 Pod 安全層級

開始檢閱Pod 安全標準,並熟悉 3 個不同的層級。

有幾種方法可以為您的命名空間選擇 Pod 安全層級

  1. 依據命名空間的安全需求 - 如果您熟悉命名空間的預期存取層級,您可以根據這些需求選擇合適的層級,類似於在新叢集上處理此問題的方式。
  2. 依據現有的 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
    
  3. 依據現有的 Pod - 使用驗證 Pod 安全層級下的策略,您可以測試 Baseline 和 Restricted 層級,以查看它們是否對現有的工作負載足夠寬鬆,並選擇權限最小的有效層級。

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(只需確保它們沒有授予任何其他不相關的權限)。

最後修改於 2023 年 4 月 15 日下午 6:38 PST:修正小錯誤 permision -> permission (5ed63def8a)