Kubernetes 1.31:細緻化的 SupplementalGroups 控制
本網誌討論 Kubernetes 1.31 中的一項新功能,旨在改善 Pod 內容器中補充群組的處理方式。
動機:在容器映像的 /etc/group
中定義的隱含群組成員資格
儘管此行為可能不受許多 Kubernetes 叢集使用者/管理員歡迎,但預設情況下,kubernetes 會合併來自 Pod 的群組資訊以及容器映像中 /etc/group
中定義的資訊。
讓我們看一個範例,以下 Pod 在 Pod 的安全性內容中指定 runAsUser=1000
、runAsGroup=3000
和 supplementalGroups=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
中的群組成員資格。如果未指定,將套用此策略 (即,為了向後相容性的現狀行為)。嚴格:它僅將
fsGroup
、supplementalGroups
或runAsGroup
欄位中指定的群組 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
...
注意
請注意,status.containerStatuses[].user.linux
欄位中的值是首先附加到容器中第一個容器進程的進程身分。如果容器具有足夠的權限來呼叫與進程身分相關的系統呼叫 (例如 setuid(2)
、setgid(2)
或 setgroups(2)
等),則容器進程可以變更其身分。因此,實際進程身分將是動態的。功能可用性
若要啟用 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
策略,以實現向後相容性。
如何瞭解更多資訊?
- 為 Pod 或容器設定安全性內容,以瞭解
supplementalGroupsPolicy
的更多詳細資訊 - KEP-3619:細緻的 SupplementalGroups 控制
如何參與?
此功能由 SIG Node 社群推動。請加入我們,與社群聯繫,並分享您關於上述功能及其他功能的想法和意見回饋。我們期待收到您的來信!