Kubernetes v1.33:細粒度 SupplementalGroups 控制功能進入 Beta 階段

新欄位 supplementalGroupsPolicy 在 Kubernetes v1.31 中作為可選的 Alpha 特性引入,並已在 v1.33 中升級為 Beta;相應的功能門控(SupplementalGroupsPolicy)現已預設啟用。此功能可以對容器中的附加組(supplemental groups)進行更精確的控制,從而加強安全態勢,尤其是在訪問卷時。此外,它還提高了容器中 UID/GID 詳細資訊的透明度,從而提供更好的安全監督。

請注意,此 Beta 版本包含一些行為上的破壞性變更。詳情請參閱Beta 版本中引入的行為變更升級注意事項部分。

動機:容器映象中 /etc/group 定義的隱式組成員關係

儘管大多數 Kubernetes 叢集管理員/使用者可能沒有意識到,但 Kubernetes 預設情況下會*合併*來自 Pod 的組資訊與容器映象中 /etc/group 定義的資訊。

讓我們看一個例子,下面的 Pod 清單在 Pod 的安全上下文中指定了 runAsUser=1000runAsGroup=3000supplementalGroups=4000

apiVersion: v1
kind: Pod
metadata:
  name: implicit-groups
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
  containers:
  - name: ctr
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

ctr 容器中執行 id 命令的結果是什麼?輸出應類似於:

uid=1000 gid=3000 groups=3000,4000,50000

附加組(groups 欄位)中的組 ID 50000 是從哪裡來的,儘管 50000 根本沒有在 Pod 的清單中定義?答案是容器映象中的 /etc/group 檔案。

檢查容器映象中 /etc/group 的內容,應該會顯示如下內容:

user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image

這表明容器的主使用者 1000 在最後一條目中屬於組 50000

因此,在容器映象中為容器主使用者在 /etc/group 中定義的組成員關係會*隱式地*與 Pod 的資訊合併。請注意,這是當前 CRI 實現從 Docker 繼承的設計決策,社群至今從未真正重新考慮過它。

這有什麼問題?

從容器映象中的 /etc/group 中*隱式*合併的組資訊存在安全風險。這些隱式 GID 無法被策略引擎檢測或驗證,因為它們在 Pod 清單中沒有任何記錄。這可能導致意外的訪問控制問題,尤其是在訪問卷時(詳見 kubernetes/kubernetes#112879),因為檔案許可權在 Linux 中由 UID/GID 控制。

Pod 中細粒度的附加組控制:supplementaryGroupsPolicy

為了解決上述問題,Pod 的 .spec.securityContext 現在包含了 supplementalGroupsPolicy 欄位。

此欄位允許你控制 Kubernetes 如何計算 Pod 內容器程序的附加組。可用的策略有:

  • Merge:將合併容器主使用者在 /etc/group 中定義的組成員關係。如果未指定,將應用此策略(即為了向後相容而保持現有行為)。

  • Strict:只有在 fsGroupsupplementalGroupsrunAsGroup 中指定的組 ID 會作為附加組附加到容器程序中。容器主使用者在 /etc/group 中定義的組成員關係將被忽略。

讓我們看看 Strict 策略是如何工作的。下面的 Pod 清單指定了 supplementalGroupsPolicy: Strict

apiVersion: v1
kind: Pod
metadata:
  name: strict-supplementalgroups-policy
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
    supplementalGroupsPolicy: Strict
  containers:
  - name: ctr
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

ctr 容器中執行 id 命令的結果應類似於:

uid=1000 gid=3000 groups=3000,4000

你可以看到 Strict 策略能夠從 groups 中排除組 50000

因此,確保 supplementalGroupsPolicy: Strict(透過某種策略機制強制執行)有助於防止 Pod 中出現隱式的附加組。

Pod 狀態中附加的程序身份

此功能還透過 .status.containerStatuses[].user.linux 欄位公開了附加到容器首個程序的程序身份。這有助於檢視是否附加了隱式組 ID。

...
status:
  containerStatuses:
  - name: ctr
    user:
      linux:
        gid: 3000
        supplementalGroups:
        - 3000
        - 4000
        uid: 1000
...

Strict 策略需要較新的 CRI 版本

實際上,CRI 執行時(例如 containerd、CRI-O)在計算要附加到容器的附加組 ID 方面扮演著核心角色。因此,SupplementalGroupsPolicy=Strict 需要支援此功能的 CRI 執行時(SupplementalGroupsPolicy: Merge 可以與不支援此功能的 CRI 執行時一起工作,因為該策略是完全向後相容的)。

以下是一些支援此功能的 CRI 執行時及其所需的版本:

  • containerd:v2.0 或更高版本
  • CRI-O:v1.31 或更高版本

並且,你可以在節點的 .status.features.supplementalGroupsPolicy 欄位中檢視是否支援該功能。

apiVersion: v1
kind: Node
...
status:
  features:
    supplementalGroupsPolicy: true

Beta 版本中引入的行為變更

在 Alpha 版本中,當一個帶有 supplementalGroupsPolicy: Strict 的 Pod 被排程到一個不支援該功能的節點上時(即 .status.features.supplementalGroupsPolicy=false),該 Pod 的附加組策略會靜默地回退到 Merge

在 v1.33 中,此功能已進入 Beta 階段,以更嚴格地執行策略,即 kubelet 會拒絕其節點無法確保指定策略的 Pod。如果你的 Pod 被拒絕,你將看到帶有 reason=SupplementalGroupsPolicyNotSupported 的警告事件,如下所示:

apiVersion: v1
kind: Event
...
type: Warning
reason: SupplementalGroupsPolicyNotSupported
message: "SupplementalGroupsPolicy=Strict is not supported in this node"
involvedObject:
  apiVersion: v1
  kind: Pod
  ...

升級注意事項

如果你已經在使用此功能,特別是 supplementalGroupsPolicy: Strict 策略,我們假設你叢集的 CRI 執行時已經支援此功能。在這種情況下,你無需擔心上述的 Pod 拒絕問題。

但是,如果你的叢集:

  • 使用了 supplementalGroupsPolicy: Strict 策略,但是
  • 其 CRI 執行時尚不支援該功能(即 .status.features.supplementalGroupsPolicy=false),

你需要在升級叢集時為行為變更(Pod 拒絕)做好準備。

我們推薦幾種方法來避免意外的 Pod 拒絕:

  • 在升級 Kubernetes 的同時或之前升級你叢集的 CRI 執行時
  • 為你的節點新增一些標籤,描述 CRI 執行時是否支援此功能,併為帶有 Strict 策略的 Pod 新增標籤選擇器以選擇此類節點(但是,在這種情況下,你需要監控 Pending 狀態的 Pod 數量,而不是 Pod 拒絕)。

參與進來

此功能由 SIG Node 社群推動。請加入我們,與社群聯絡,分享你關於上述功能及其他方面的想法和反饋。我們期待你的迴音!

我如何瞭解更多資訊?