Kubernetes 1.31:細緻化的 SupplementalGroups 控制

本網誌討論 Kubernetes 1.31 中的一項新功能,旨在改善 Pod 內容器中補充群組的處理方式。

動機:在容器映像的 /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 命令的結果是什麼?

# Create the Pod:
$ kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/implicit-groups.yaml

# Verify that the Pod's Container is running:
$ kubectl get pod implicit-groups

# Check the id command
$ kubectl exec implicit-groups -- id

然後,輸出應與此類似

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

即使 50000 完全未在 Pod 的 manifest 中定義,補充群組 (groups 欄位) 中的群組 ID 50000 從何而來?答案是容器映像中的 /etc/group 檔案。

檢查容器映像中 /etc/group 的內容應顯示如下

$ kubectl exec implicit-groups -- cat /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隱含地合併群組資訊可能會引起一些疑慮,尤其是在存取卷時 (有關詳細資訊,請參閱 kubernetes/kubernetes#112879),因為檔案權限由 Linux 中的 uid/gid 控制。更糟的是,來自 /etc/group 的隱含 gid 無法被任何策略引擎偵測/驗證,因為 manifest 中沒有關於隱含群組資訊的線索。這也可能成為 Kubernetes 安全性的隱憂。

Pod 中細緻的 SupplementalGroups 控制:SupplementaryGroupsPolicy

為了解決上述問題,Kubernetes 1.31 在 Pod 的 .spec.securityContext 中引入了新欄位 supplementalGroupsPolicy

此欄位提供了一種控制如何計算 Pod 中容器進程的補充群組的方式。可用的策略如下

  • 合併:將合併為容器主要使用者定義的 /etc/group 中的群組成員資格。如果未指定,將套用此策略 (即,為了向後相容性的現狀行為)。

  • 嚴格:它僅將 fsGroupsupplementalGroupsrunAsGroup 欄位中指定的群組 ID 作為容器進程的補充群組附加。這表示不會合併為容器主要使用者定義的 /etc/group 中的任何群組成員資格。

讓我們看看 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
# Create the Pod:
$ kubectl apply -f https://k8s.io/blog/2024-08-22-Fine-grained-SupplementalGroups-control/strict-supplementalgroups-policy.yaml

# Verify that the Pod's Container is running:
$ kubectl get pod strict-supplementalgroups-policy

# Check the process identity:
kubectl exec -it strict-supplementalgroups-policy -- 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
...

功能可用性

若要啟用 supplementalGroupsPolicy 欄位,必須使用以下元件

  • Kubernetes:v1.31 或更新版本,並啟用 SupplementalGroupsPolicy 功能閘道。截至 v1.31,此閘道標記為 alpha。
  • CRI 執行階段
    • containerd:v2.0 或更新版本
    • CRI-O:v1.31 或更新版本

您可以查看節點的 .status.features.supplementalGroupsPolicy 欄位中是否支援此功能。

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

下一步是什麼?

Kubernetes SIG Node 希望 - 並期望 - 此功能將在未來 Kubernetes 版本中升級為 beta 版,並最終全面發布 (GA),以便使用者不再需要手動啟用功能閘道。

當未指定 supplementalGroupsPolicy 時,會套用 Merge 策略,以實現向後相容性。

如何瞭解更多資訊?

如何參與?

此功能由 SIG Node 社群推動。請加入我們,與社群聯繫,並分享您關於上述功能及其他功能的想法和意見回饋。我們期待收到您的來信!