概述
Security Context(安全上下文)用來限制容器對宿主節點的可訪問范圍,以避免容器非法操作宿主節點的系統級別的內容,使得節點的系統或者節點上其他容器組受到影響。
Security Context可以按照如下幾種方式設定:
- 訪問權限控制:是否可以訪問某個對象(例如文件)是基於 userID(UID)和 groupID(GID) 的
- Security Enhanced Linux (SELinux):為對象分配Security標簽
- 以 privileged(特權)模式運行
- Linux Capabilities:為容器組(或容器)分配一部分特權,而不是 root 用戶的所有特權
- AppArmor:自 Kubernetes v1.4 以來,一直處於 beta 狀態
- Seccomp:過濾容器中進程的系統調用(system call)
- AllowPrivilegeEscalation(允許特權擴大):此項配置是一個布爾值,定義了一個進程是否可以比其父進程獲得更多的特權,直接效果是,容器的進程上是否被設置 no_new_privs 標記。當出現如下情況時,AllowPrivilegeEscalation 的值始終為 true:
- 容器以 privileged 模式運行
- 容器擁有 CAP_SYS_ADMIN 的 Linux Capability
如需要了解更多關於 Linux 安全機制方面的信息,請參考 Overview Of Linux Kernel Security Features
本文從以下幾個方面介紹如何在 Kubernetes 中配置 Security Context
為Pod設置Security Context
在 Pod 的定義中增加 securityContext
字段,即可為 Pod 指定 Security 相關的設定。 securityContext
字段是一個 PodSecurityContext 對象。通過該字段指定的內容將對該 Pod 中所有的容器生效。
Pod示例
以下面的 Pod 為例:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
在上面的例子中:
spec.securityContext.runAsUser
字段指定了該 Pod 中所有容器的進程都以UserID 1000 的身份運行
spec.securityContext.runAsGroup
字段指定了該 Pod 中所有容器的進程都以GroupID 3000 的身份運行,如果該字段被省略,容器進程的GroupID為 root(0)
容器中創建的文件,其所有者為 userID 1000,groupID 3000
spec.securityContext.fsGroup
字段指定了該 Pod 的 fsGroup 為 2000
數據卷 (本例中,對應掛載點 /data/demo
的數據卷為 sec-ctx-demo
) 的所有者以及在該數據卷下創建的任何文件,其 GroupID 為 2000
執行Pod示例
-
創建 Pod
kubectl apply -f https://kuboard.cn/statics/learning/sec-ctx/security-context-1.yaml
-
驗證 Pod 已運行
kubectl get pod security-context-demo
-
進入容器的命令行界面
kubectl exec -it security-context-demo -- sh
-
在該命令行界面中,查看正在運行的進程
ps
請注意,所有的進程都以 user 1000 的身份運行(由 runAsUser 指定),輸出結果如下所示:
PID USER TIME COMMAND 1 1000 0:00 sleep 1h 6 1000 0:00 sh ...
-
在命令行界面中,切換到目錄
/data
,並查看目錄中的文件列表cd /data ls -l
請注意,
/data/demo
目錄的 groupID 為 2000(由 fsGroup 指定),輸出結果如下所示:drwxrwsrwx 2 root 2000 4096 Oct 4 05:08 demo
-
在命令行界面中,切換到目錄
/data/demo
,並創建一個文件cd /data/demo echo hello > testfile ls -l
請注意,
testfile
的 groupID 為 2000 (由 FSGroup 指定),輸出結果如下所示:-rw-r--r-- 1 1000 2000 6 Oct 4 05:09 testfile
-
在命令行界面中執行
id
命令,輸出結果如下所示:$ id uid=1000 gid=3000 groups=2000
請注意:
- gid 為 3000,與
runAsGroup
字段所指定的一致 - 如果
runAsGroup
字段被省略,則 gid 取值為 0(即 root),此時容器中的進程將可以操作 root Group 的文件
- gid 為 3000,與
為容器設置Security Context
容器的定義中包含 securityContext
字段,該字段接受 SecurityContext 對象。通過指定該字段,可以為容器設定安全相關的配置,當該字段的配置與 Pod 級別的 securityContext
配置相沖突時,容器級別的配置將覆蓋 Pod 級別的配置。容器級別的 securityContext
不影響 Pod 中的數據卷。
下面的示例中的 Pod 包含一個 Container,且 Pod 和 Container 都有定義 securityContext
字段:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo-2
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
-
執行命令以創建 Pod
kubectl apply -f https://kuboard.cn/statics/learning/sec-ctx/security-context-2.yaml
-
執行命令以驗證容器已運行
kubectl get pod security-context-demo-2
-
執行命令進入容器的命令行界面:
kubectl exec -it security-context-demo-2 -- sh
-
在命令行界面中查看所有的進程
ps aux
請注意,容器的進程以 userID 2000 的身份運行。該取值由
spec.containers[*].securityContext.runAsUser
容器組中的字段定義。Pod 中定義的spec.securityContext.runAsUser
取值 1000 被覆蓋。輸出結果如下所示:PID USER TIME COMMAND 1 2000 0:00 sleep 1h 6 2000 0:00 sh 11 2000 0:00 ps aux ...
為容器設置Linux Capabilities
使用 Linux Capabilities 可以為容器內的進程授予某些特定的權限(而不是 root 用戶的所有權限)。在容器定義的 securityContext 中添加 capabilities 字段,可以向容器添加或刪除 Linux Capability。
本文后續章節中,先運行一個不包含 capabilities 字段的容器,觀察容器內進程的 linux capabilities 位圖的情況;然后在運行一個包含 capabilities 字段的容器,比較其 linux capabilities 位圖與前者的不同。
無capabilities字段時
我們先確認在沒有 capabilities 字段時,容器的行為是怎樣的。下面的例子中包含一個容器,我們沒有為其添加或刪除任何 Linux capability。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-3
spec:
containers:
- name: sec-ctx-3
image: gcr.io/google-samples/node-hello:1.0
-
執行命令以創建 Pod
kubectl apply -f https://kuboard.cn/statics/learning/sec-ctx/security-context-3.yaml
-
執行命令以驗證容器正在運行
kubectl get pod security-context-demo-3
-
執行命令以進入容器的命令行界面
kubectl exec -it security-context-demo-3 -- sh
-
在容器的命令行界面中查看正在運行的進程
ps aux
輸出結果中展示了容器中進程的 process ID(PID),如下所示:
PID USER TIME COMMAND 1 root 0:00 sleep 1h 6 root 0:00 sh 11 root 0:00 ps aux
-
在容器的命令行界面中查看 process 1 的狀態
cd /proc/1 cat status
輸出結果中展示了該進程 Linux Capabilities 的位圖,如下所示:
... CapPrm: 00000000a80425fb CapEff: 00000000a80425fb ...
有capabilities字段時
接下來,我們運行同樣的一個容器,不同的是,這次為其設置了 capabilities 字段。下面是 yaml 配置文件,該配置中為進程添加了兩個 Linux Capability: CAP_NET_ADMIN 和 CAP_SYS_TIME:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-4
image: gcr.io/google-samples/node-hello:1.0
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
-
執行命令以創建 Pod
kubectl apply -f https://kuboard.cn/statics/learning/sec-ctx/security-context-4.yaml
-
執行命令以驗證容器正在運行
kubectl get pod security-context-demo-4
-
執行命令以進入容器的命令行界面
kubectl exec -it security-context-demo-4 -- sh
-
在容器的命令行界面中查看正在運行的進程
ps aux
輸出結果中展示了容器中進程的 process ID(PID),如下所示:
PID USER TIME COMMAND 1 root 0:00 sleep 1h 6 root 0:00 sh 11 root 0:00 ps aux
-
在容器的命令行界面中查看 process 1 的狀態
cd /proc/1 cat status
輸出結果中展示了該進程 Linux Capabilities 的位圖,如下所示:
... CapPrm: 00000000aa0435fb CapEff: 00000000aa0435fb ...
-
比較兩次運行,進程的 Linux Capabilities 位圖的差異:
第一次運行:00000000a80425fb 第二次運行:00000000aa0435fb
-
第一次運行時,位圖的 12 位和 25 為是 0。第二次運行時,12 位和 25 位是 1.查看 Linux Capabilities 的常量定義文件 capability.h 可知:12 位代表
CAP_NET_ADMIN
,25 位代表CAP_SYS_TIME
。
Linux Capability 常量
Linux Capabilities 常量格式為CAP_XXX
。然而,在容器定義中添加或刪除 Linux Capabilities 時,必須去除常量的前綴CAP_
。例如:向容器中添加CAP_SYS_TIME
時,只需要填寫SYS_TIME
。
為容器設置SELinux標簽
Pod 或容器定義的 securityContext
中 seLinuxOptions
字段是一個 SELinuxOptions 對象,該字段可用於為容器指定 SELinux 標簽。如下所示:
...
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
為容器指定 SELinux 標簽時,宿主節點的 SELinux 模塊必須加載。
關於數據卷
Pod 的 securityContext 作用於 Pod 中所有的容器,同時對 Pod 的數據卷也同樣生效。具體來說,fsGroup
和 seLinuxOptions
將被按照如下方式應用到 Pod 中的數據卷:
fsGroup
:對於支持 ownership 管理的數據卷,通過fsGroup
指定的 GID 將被設置為該數據卷的 owner,並且可被fsGroup
寫入。更多細節請參考 Ownership Management design documentseLinuxOptions
:對於支持 SELinux 標簽的數據卷,將按照seLinuxOptions
的設定重新打標簽,以使 Pod 可以訪問數據卷內容。通常您只需要設置seLinuxOptions
中level
這一部分內容。該設定為 Pod 中所有容器及數據卷設置 Multi-Category Security (MCS) 標簽。