1. 程式人生 > 其它 >為 Pod 或容器配置安全性上下文

為 Pod 或容器配置安全性上下文

安全上下文(Security Context)定義 Pod 或 Container 的特權與訪問控制設定。 安全上下文包括但不限於:

  • AppArmor:使用程式框架來限制個別程式的權能。
  • Seccomp:過濾程序的系統呼叫。
  • AllowPrivilegeEscalation:控制程序是否可以獲得超出其父程序的特權。 此布林值直接控制是否為容器程序設定
    no_new_privs
    標誌。 當容器以特權模式執行或者具有 CAP_SYS_ADMIN 權能時,AllowPrivilegeEscalation 總是為 true。
  • readOnlyRootFilesystem:以只讀方式載入容器的根檔案系統。

以上條目不是安全上下文設定的完整列表 -- 請參閱 SecurityContext 瞭解其完整列表。

關於在 Linux 系統中的安全機制的更多資訊,可參閱 Linux 核心安全效能力概述

安全上下文(Security Context)定義 Pod 或 Container 的特權與訪問控制設定。 安全上下文包括但不限於:

  • AppArmor:使用程式框架來限制個別程式的權能。
  • Seccomp:過濾程序的系統呼叫。
  • AllowPrivilegeEscalation:控制程序是否可以獲得超出其父程序的特權。 此布林值直接控制是否為容器程序設定 no_new_privs標誌。 當容器以特權模式執行或者具有 CAP_SYS_ADMIN 權能時,AllowPrivilegeEscalation 總是為 true。
  • readOnlyRootFilesystem:以只讀方式載入容器的根檔案系統。

以上條目不是安全上下文設定的完整列表 -- 請參閱 SecurityContext 瞭解其完整列表。

關於在 Linux 系統中的安全機制的更多資訊,可參閱 Linux 核心安全效能力概述

為 Pod 設定安全性上下文

要為 Pod 設定安全性設定,可在 Pod 規約中包含 securityContext 欄位。securityContext 欄位值是一個 PodSecurityContext 物件。你為 Pod 所設定的安全性配置會應用到 Pod 中所有 Container 上。 下面是一個 Pod 的配置檔案,該 Pod 定義了 securityContext 和一個 emptyDir 卷:

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

在配置檔案中,runAsUser 欄位指定 Pod 中的所有容器內的程序都使用使用者 ID 1000 來執行。runAsGroup 欄位指定所有容器中的程序都以主組 ID 3000 來執行。 如果忽略此欄位,則容器的主組 ID 將是 root(0)。 當 runAsGroup 被設定時,所有建立的檔案也會劃歸使用者 1000 和組 3000。 由於 fsGroup 被設定,容器中所有程序也會是附組 ID 2000 的一部分。 卷 /data/demo 及在該卷中建立的任何檔案的屬主都會是組 ID 2000。

建立該 Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml

檢查結果

kubectl exec -it security-context-demo -- ps aux
PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 1h
    6 1000      0:00 sh

在你的 Shell 中,進入 /data建立目錄檢視詳細資訊

cd /data
ls -l
drwxrwsrwx 2 root 2000 4096 Jun  6 20:08 demo
cd demo
echo hello > testfile
ls -l
-rw-r--r-- 1 1000 2000 6 Jun  6 20:08 testfile

執行下面的命令輸出結果:

id
uid=1000 gid=3000 groups=2000

你會看到 gid 值為 3000,也就是 runAsGroup 欄位的值。 如果 runAsGroup 被忽略,則 gid 會取值 0(root),而程序就能夠與 root 使用者組所擁有以及要求 root 使用者組訪問許可權的檔案互動。

為 Pod 配置卷訪問許可權和屬主變更策略

FEATURE STATE: Kubernetes v1.20 [beta]

預設情況下,Kubernetes 在掛載一個卷時,會遞迴地更改每個卷中的內容的屬主和訪問許可權,使之與 Pod 的 securityContext 中指定的 fsGroup 匹配。 對於較大的資料卷,檢查和變更屬主與訪問許可權可能會花費很長時間,降低 Pod 啟動速度。 你可以在 securityContext 中使用 fsGroupChangePolicy 欄位來控制 Kubernetes 檢查和管理卷屬主和訪問許可權的方式。

fsGroupChangePolicy - fsGroupChangePolicy 定義在卷被暴露給 Pod 內部之前對其 內容的屬主和訪問許可進行變更的行為。此欄位僅適用於那些支援使用 fsGroup 來 控制屬主與訪問許可權的卷型別。此欄位的取值可以是:

  • OnRootMismatch:只有根目錄的屬主與訪問許可權與卷所期望的許可權不一致時, 才改變其中內容的屬主和訪問許可權。這一設定有助於縮短更改卷的屬主與訪問 許可權所需要的時間。
  • Always:在掛載卷時總是更改卷中內容的屬主和訪問許可權。

例如:

securityContext:
  runAsUser: 1000
  runAsGroup: 3000
  fsGroup: 2000
  fsGroupChangePolicy: "OnRootMismatch"
說明: 此欄位對於secretconfigMapemptydir 這類臨時性儲存無效。

為 Container 設定安全性上下文

若要為 Container 設定安全性配置,可以在 Container 清單中包含 securityContext 欄位。securityContext 欄位的取值是一個 SecurityContext 物件。你為 Container 設定的安全性配置僅適用於該容器本身,並且所指定的設定 在與 Pod 層面設定的內容發生重疊時,會過載後者。Container 層面的設定不會影響 到 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://k8s.io/examples/pods/security/security-context-2.yaml

檢查結果

kubectl exec -it security-context-demo-2 -- ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2000         1  0.0  0.0   4336   764 ?        Ss   20:36   0:00 /bin/sh -c node server.js
2000         8  0.1  0.5 772124 22604 ?        Sl   20:36   0:00 node server.js
...

為 Container 設定權能

使用 Linux 權能,你可以 賦予程序 root 使用者所擁有的某些特權,但不必賦予其全部特權。 要為 Container 新增或移除 Linux 權能,可以在 Container 清單的 securityContext 節 包含 capabilities 欄位。

首先,檢視不包含 capabilities 欄位時候會發生什麼。 下面是一個配置檔案,其中沒有新增或移除容器的權能:

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://k8s.io/examples/pods/security/security-context-3.yaml

輸出結果

kubectl exec -it security-context-demo-3 -- ps aux
USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js

在你的 Shell 中,檢視程序 1 的狀態:

cd /proc/1
cat status

輸出顯示程序的權能點陣圖:

...
CapPrm:    00000000a80425fb
CapEff:    00000000a80425fb
...

接下來執行一個與前例中容器相同的容器,只是這個容器有一些額外的權能設定。

下面是一個 Pod 的配置,其中執行一個容器。配置為容器新增 CAP_NET_ADMINCAP_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://k8s.io/examples/pods/security/security-context-4.yaml

啟動一個 Shell,進入到執行中的容器:

kubectl exec -it security-context-demo-4 -- sh
cd /proc/1
cat status

輸出顯示的是程序的權能點陣圖:

...
CapPrm:    00000000aa0435fb
CapEff:    00000000aa0435fb
...

比較兩個容器的權能點陣圖:

00000000a80425fb
00000000aa0435fb

在第一個容器的權能點陣圖中,位 12 和 25 是沒有設定的。在第二個容器中,位 12 和 25 是設定了的。位 12 是 CAP_NET_ADMIN 而位 25 則是 CAP_SYS_TIME。 參見 capability.h 瞭解權能常數的定義。

說明: Linux 權能常數定義的形式為 CAP_XXX。但是你在 Container 清單中列舉權能時, 要將權能名稱中的 CAP_ 部分去掉。例如,要新增 CAP_SYS_TIME,可在權能 列表中新增 SYS_TIME。

為容器設定 Seccomp 樣板

若要為容器設定 Seccomp 樣板(Profile),可在你的 Pod 或 Container 清單的 securityContext 節中包含 seccompProfile 欄位。該欄位是一個 SeccompProfile 物件,包含 typelocalhostProfile 屬性。 type 的合法選項包括 RuntimeDefaultUnconfinedLocalhostlocalhostProfile 只能在 type: Localhost 配置下才需要設定。 該欄位標明節點上預先配置的樣板的路徑,路徑是相對於 kubelet 所配置的 Seccomp 樣板路徑(使用 --root-dir 配置)而言的。

下面是一個例子,設定容器使用節點上容器執行時的預設樣板作為 Seccomp 樣板:

...
securityContext:
  seccompProfile:
    type: RuntimeDefault

下面是另一個例子,將 Seccomp 的樣板設定為位於 <kubelet-根目錄>/seccomp/my-profiles/profile-allow.json 的一個預先配置的檔案。

...
securityContext:
  seccompProfile:
    type: Localhost
    localhostProfile: my-profiles/profile-allow.json

為 Container 賦予 SELinux 標籤

若要給 Container 設定 SELinux 標籤,可以在 Pod 或 Container 清單的 securityContext 節包含 seLinuxOptions 欄位。 seLinuxOptions 欄位的取值是一個 SELinuxOptions 物件。下面是一個應用 SELinux 標籤的例子:

...
securityContext:
  seLinuxOptions:
    level: "s0:c123,c456"

說明: 要指定 SELinux,需要在宿主作業系統中裝載 SELinux 安全性模組。

討論

Pod 的安全上下文適用於 Pod 中的容器,也適用於 Pod 所掛載的卷(如果有的話)。 尤其是,fsGroupseLinuxOptions 按下面的方式應用到掛載捲上:

  • fsGroup:支援屬主管理的卷會被修改,將其屬主變更為 fsGroup 所指定的 GID, 並且對該 GID 可寫。進一步的細節可參閱 屬主變更設計文件

  • seLinuxOptions:支援 SELinux 標籤的卷會被重新打標籤,以便可被 seLinuxOptions 下所設定的標籤訪問。通常你只需要設定 level 部分。 該部分設定的是賦予 Pod 中所有容器及卷的 多類別安全性(Multi-Category Security,MCS)標籤。

警告: 在為 Pod 設定 MCS 標籤之後,所有帶有相同標籤的 Pod 可以訪問該卷。 如果你需要跨 Pod 的保護,你必須為每個 Pod 賦予獨特的 MCS 標籤。

轉載自:https://kubernetes.io/zh/docs/tasks/configure-pod-container/security-context/