K8S Security Context


概述

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 的文件

為容器設置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 或容器定義的 securityContextseLinuxOptions 字段是一個 SELinuxOptions 對象,該字段可用於為容器指定 SELinux 標簽。如下所示:

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

為容器指定 SELinux 標簽時,宿主節點的 SELinux 模塊必須加載。

關於數據卷

Pod 的 securityContext 作用於 Pod 中所有的容器,同時對 Pod 的數據卷也同樣生效。具體來說,fsGroupseLinuxOptions 將被按照如下方式應用到 Pod 中的數據卷:

  • fsGroup:對於支持 ownership 管理的數據卷,通過 fsGroup 指定的 GID 將被設置為該數據卷的 owner,並且可被 fsGroup 寫入。更多細節請參考 Ownership Management design document
  • seLinuxOptions:對於支持 SELinux 標簽的數據卷,將按照 seLinuxOptions 的設定重新打標簽,以使 Pod 可以訪問數據卷內容。通常您只需要設置 seLinuxOptionslevel 這一部分內容。該設定為 Pod 中所有容器及數據卷設置 Multi-Category Security (MCS) 標簽。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM