從 PodSecurityPolicy 遷移到內建 PodSecurity 准入控制器

本頁面描述了從 PodSecurityPolicy 遷移到內建 PodSecurity 准入控制器的過程。這可以透過結合使用模擬執行、auditwarn 模式有效地完成,儘管如果使用可修改的 PSP,這會變得更加困難。

準備工作

你的 Kubernetes 伺服器版本必須是 v1.22 或更高。

要檢查版本,請輸入 kubectl version

如果你當前執行的 Kubernetes 版本不是 1.34,你可能希望切換到檢視該頁面的 Kubernetes 文件版本,該版本與你實際執行的版本相符。

本頁面假設你已經熟悉基本的 Pod 安全准入 概念。

總體方法

從 PodSecurityPolicy 遷移到 Pod 安全准入有多種策略。以下步驟是其中一種可能的遷移路徑,目標是最大限度地降低生產中斷和安全漏洞的風險。

  1. 決定 Pod 安全准入是否適合你的使用場景。
  2. 審查名稱空間許可權
  3. 簡化和標準化 PodSecurityPolicy
  4. 更新名稱空間
    1. 識別適當的 Pod 安全級別
    2. 驗證 Pod 安全級別
    3. 強制執行 Pod 安全級別
    4. 繞過 PodSecurityPolicy
  5. 審查名稱空間建立過程
  6. 停用 PodSecurityPolicy

0. 決定 Pod 安全准入是否適合你

Pod 安全准入旨在開箱即用地滿足最常見的安全需求,並在叢集中提供一套標準的安全級別。然而,它的靈活性不如 PodSecurityPolicy。值得注意的是,以下功能由 PodSecurityPolicy 支援,但 Pod 安全准入不支援:

  • 設定預設安全限制 - Pod 安全准入是一個非修改性准入控制器,這意味著它在驗證 Pod 之前不會修改它們。如果你依賴 PSP 的這個方面,你需要修改你的工作負載以滿足 Pod 安全限制,或者使用 修改准入 Webhook 來進行這些更改。有關更多詳細資訊,請參閱下面的 簡化和標準化 PodSecurityPolicy
  • 對策略定義的細粒度控制 - Pod 安全准入只支援 3 個標準級別。如果你需要對特定限制進行更多控制,那麼你需要使用 驗證准入 Webhook 來強制執行這些策略。
  • 子名稱空間策略粒度 - PodSecurityPolicy 允許你將不同的策略繫結到不同的 ServiceAccount 或使用者,即使在單個名稱空間內也是如此。這種方法存在許多陷阱,不建議使用,但如果你確實需要此功能,則需要使用第三方 webhook。例外情況是,如果你只需要完全豁免特定使用者或 RuntimeClass,在這種情況下,Pod 安全准入會暴露一些 豁免的靜態配置

即使 Pod 安全准入不能滿足你的所有需求,它也被設計成與其他策略強制機制**互補**,並且可以作為其他准入 Webhook 的有用備用機制執行。

1. 審查名稱空間許可權

Pod 安全准入由名稱空間上的標籤控制。這意味著任何可以更新(或修補或建立)名稱空間的人都可以修改該名稱空間的 Pod 安全級別,這可能被用來繞過更嚴格的策略。在繼續之前,請確保只有受信任的特權使用者擁有這些名稱空間許可權。不建議向不應擁有提升許可權的使用者授予這些強大許可權,但如果必須這樣做,則需要使用准入 Webhook 對在 Namespace 物件上設定 Pod 安全標籤施加額外限制。

2. 簡化和標準化 PodSecurityPolicy

在本節中,你將減少可修改的 PodSecurityPolicy 並刪除超出 Pod 安全標準範圍的選項。你應該對所修改的原始 PodSecurityPolicy 的離線副本進行此處推薦的更改。克隆的 PSP 應該有一個不同的名稱,並且在字母順序上位於原始名稱之前(例如,在其前面加上 0)。暫時不要在 Kubernetes 中建立新的策略 - 這將在下面的 推出更新的策略 部分介紹。

2.a. 消除純粹修改欄位

如果 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 - 對於 Restricted 配置檔案,需要丟棄 ALL
  • .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。如果任何 Role 或 ClusterRole 授予所有 PSP 的 use 許可權,這可能會導致使用新的 PSP 而不是其可變對應項。
  4. 更新你的授權以授予對新 PSP 的訪問許可權。在 RBAC 中,這意味著更新任何授予原始 PSP 的 use 許可權的 Role 或 ClusterRole,使其也授予對更新後的 PSP 的許可權。
  5. 驗證:經過一段時間的穩定執行後,重新執行步驟 1 中的命令,檢視是否有任何 Pod 仍在使用原始 PSP。請注意,Pod 需要在新策略推出後重新建立才能完全驗證。
  6. (可選) 確認原始 PSP 不再使用後,可以刪除它們。

3. 更新名稱空間

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

3.a. 識別適當的 Pod 安全級別

開始審查Pod 安全標準,並熟悉 3 種不同級別。

有幾種方法可以選擇名稱空間的 Pod 安全級別

  1. 根據名稱空間的安全要求 - 如果你熟悉名稱空間的預期訪問級別,則可以根據這些要求選擇適當的級別,類似於在新叢集上處理此問題的方式。
  2. 透過現有的 PodSecurityPolicies - 使用將 PodSecurityPolicies 對映到 Pod 安全標準參考,你可以將每個 PSP 對映到 Pod 安全標準級別。如果你的 PSP 不是基於 Pod 安全標準的,你可能需要決定是選擇一個至少與 PSP 一樣寬鬆的級別,還是選擇一個至少與 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 安全級別(或者如果你正在嘗試多個級別),最好先對其進行測試(如果使用特權級別,可以跳過此步驟)。Pod 安全包含幾個工具,可幫助測試和安全推出配置檔案。

首先,你可以模擬執行策略,這將根據應用的策略評估當前在名稱空間中執行的 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 以及任何相關的 Role、ClusterRole、RoleBinding 和 ClusterRoleBinding(只需確保它們沒有授予任何其他不相關的許可權)。

上次修改時間:2023 年 4 月 15 日太平洋標準時間下午 6:38:修正小拼寫錯誤 permision -> permission (5ed63def8a)