利用內建的 Linux 安全功能,為 Azure Kubernetes Service(AKS)工作負載中的容器提供資源的安全存取

在本文中,您將了解如何利用 使用者命名空間、 AppArmor 及 seccomp 內建的 Linux 安全功能,保護 Azure Kubernetes Service(AKS)工作負載的容器存取權。

容器存取安全概述

就如同您應授與使用者或群組所需的最低權限一樣,也應限制容器只能執行必要動作和流程。 為了將攻擊風險降到最低,請避免設定需要提升權限或根存取的應用程式和容器。

您可以使用內建的 Kubernetes Pod 安全性內容來定義更多的權限,例如要以其身分執行的使用者或群組、要公開的 Linux 功能,或在 Pod 資訊清單中設定 allowPrivilegeEscalation: false。 如需最佳做法詳細資訊,請參閱保護 Pod 對資源的存取。

為了提升主機隔離並減少 Linux 上的橫向移動,你可以使用 使用者命名空間。 若要針對容器動作進行更細微的控制,您可以使用內建的 Linux 安全性功能,例如 AppArmor 和 seccomp。 這些功能透過在節點層級定義 Linux 安全特性,並透過 pod manifest 實作,限制容器可執行的動作。

內建 Linux 安全性功能僅適用於 Linux 節點和 Pod。

附註

目前,如果惡意使用多租用戶,則 Kubernetes 環境不安全。 其他安全功能,如 Microsoft Defender for Containers、 AppArmor、 seccomp、 使用者命名空間、 Pod Security Admission,或 節點的 Kubernetes Role-Based 存取控制(RBAC),都能有效阻擋漏洞利用。

執行惡意多租用戶工作負載時,若要真正確保安全性,應該只信任 Hypervisor。 Kubernetes 的安全性網域會成為整個叢集,而非個別節點。

對於這些類型的惡意多租用戶工作負載,您應使用實際隔離的叢集。

使用者命名空間的前提條件

使用者命名空間的限制

使用者命名空間概述

Linux Pod 預設會使用複數個命名空間來執行:一個命名空間用來隔離網路身分識別,一個 PID 命名空間則用來隔離處理序。 使用者命名空間(user_namespace)將容器內的使用者與主機上的使用者隔離。 它也會限制功能的範圍及 Pod 與系統其餘部分的互動。

容器內的 UID 和 GID 會對應主機的無特殊權限使用者,因此所有與主機其餘部分的互動都會以這些不具特殊權限的 UID 和 GID 形式來發生。 舉例來說,容器 (UID 0) 內的根目錄可以對應主機的使用者 65536。 Kubernetes 會建立對應,使用系統上的使用者命名空間保證不與其他 Pod 重疊。

Kubernetes 實作有一些關鍵優勢。 欲了解更多,請參閱 Kubernetes 使用者命名空間文件。

啟用使用者命名空間

  1. 建立名為 mypod.yaml 的檔案,然後將下列資訊清單複製進來。 要使用使用者命名空間,YAML 需要包含欄位 hostUsers: false。

    apiVersion: v1
    kind: Pod
    metadata:
      name: userns
    spec:
      hostUsers: false
      containers:
      - name: shell
        command: ["sleep", "infinity"]
        image: debian
    
  2. 使用 kubectl apply 命令來部署應用程式,並指定 YAML 資訊清單的名稱。

    kubectl apply -f mypod.yaml
    
  3. 使用 kubectl get pods 命令檢視已部署 Pod 的狀態。

    kubectl get pods
    
  4. 使用 kubectl exec 命令以執行進入 Pod 的操作。

    kubectl exec -ti userns -- bash
    
  5. 在艙內,請使用以下指令檢查 /proc/self/uid_map :

    cat /proc/self/uid_map
    

    輸出的最後一欄應該有 65536 。 例如:

    0  833617920      65536
    

    此輸出表示容器 (UID 0) 內的根目錄對應到主機的使用者 65536。

使用者命名空間所緩解的常見漏洞與暴露(CVE)

下表列出一些常見的漏洞與暴露(CVE),可透過使用 user_namespaces 來部分或全部緩解:

CVE 嚴重度分數 嚴重性等級
CVE-2019-5736 8.6 High
CVE 2024-21262 8.6 High
CVE 2022-0492 7.8 High
CVE-2021-25741 8.1 / 8.8 高/高
CVE-2017-1002101 9.6 / 8.8 關鍵/高

請記住,這份清單並非完整無遺。 欲了解更多,請參閱 Kubernetes v1.33:預設啟用的使用者命名空間。

AppArmor 的先決條件

附註

自 2025 年 11 月 7 日 VHD 版本起,Azure Linux 3.0 支援 AppArmor。

AppArmor 概述

若要限制容器動作,您可以使用 AppArmor Linux 核心安全性模組。 AppArmor 作為底層 AKS 節點作業系統(OS)的一部分提供,並預設啟用。 你可以建立 AppArmor 設定檔,限制讀取、寫入或執行動作,或系統功能如掛載檔案系統。 預設的 AppArmor 設定檔會限制存取各種 /proc 和 /sys 位置,並提供方法以邏輯方式從基礎節點隔離容器。 AppArmor 適用於任何在 Linux 上執行的應用程式,而不只是 Kubernetes Pod。

附註

在 Kubernetes v1.30 之前,AppArmor 是透過註解來規範的。 從 v1.30 起,AppArmor 透過 pod 規範中的securityContext欄位來指定。 欲了解更多資訊,請參閱 Kubernetes AppArmor 文件。

在 AKS 叢集中使用 AppArmor 設定檔限制容器動作

使用 AppArmor 來保護 Pod

你可以在 pod 或容器層次設定 AppArmor 設定檔。 容器中的 AppArmor 設定檔優先於 pod 的 AppArmor 配置檔。 若兩者皆未指定,容器即為無限制運行。 欲瞭解更多 AppArmor 設定檔資訊,請參閱 Securing a Pod with AppArmor Kubernetes 文件。

設定自訂 AppArmor 設定檔

以下範例建立一個配置文件,以防止從容器內向檔案進行寫入操作。

  1. AKS 節點的 SSH。

  2. 建立一個名為 deny-write.profile 的檔案,並貼上以下內容:

    #include <tunables/global>
    
    profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
    
      file,
    
      # Deny all file writes.
      deny /** w,
    }
    
  3. 將 AppArmor 設定檔載入節點。

    # This example assumes that node names match host names, and are reachable via SSH.
    NODES=($( kubectl get node -o jsonpath='{.items[*].status.addresses[?(.type == "Hostname")].address}' ))
    
    for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
    #include <tunables/global>
    
    profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
    
      file,
    
      # Deny all file writes.
      deny /** w,
    }
    EOF'
    done
    

部署帶有自訂 AppArmor 設定檔的 pod

  1. 部署一個使用拒絕寫入設定檔的「Hello AppArmor」pod。

    apiVersion: v1
    kind: Pod
    metadata:
      name: hello-apparmor
    spec:
      securityContext:
        appArmorProfile:
          type: Localhost
          localhostProfile: k8s-apparmor-example-deny-write
      containers:
      - name: hello
        image: busybox:1.28
        command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
    
  2. 用指令 kubectl apply 套用 Pod 清單。

    kubectl apply -f hello-apparmor.yaml
    
  3. 用執行器進入 Pod,確認容器是否使用 AppArmor 設定檔在運行。

    kubectl exec hello-apparmor -- cat /proc/1/attr/current
    

    輸出應顯示使用中的 AppArmor 設定檔。 例如:

    k8s-apparmor-example-deny-write (enforce)
    

Seccomp 先決條件

註冊 KubeletDefaultSeccompProfilePreview 功能旗標

重要事項

AKS 預覽功能可透過自助服務,以加入方式使用。 預覽會以「現狀」和「可供使用時」提供,其其不受服務等級協定和有限瑕疵擔保所保護。 客戶支援部門會盡最大努力,部分支援 AKS 預覽。 因此,這些功能不適合實際執行用途。 如需詳細資訊,請參閱下列支援文章:

  1. 使用 KubeletDefaultSeccompProfilePreview 命令註冊 az feature register 功能旗標。

    az feature register --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    

    狀態需要幾分鐘的時間才會顯示「已註冊」。

  2. 使用 az feature show 命令驗證註冊狀態。

    az feature show --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    
  3. 當狀態反映「已註冊」時,使用 (部分機器翻譯) 命令,重新整理 az provider register 資源提供者的註冊。

    az provider register --namespace Microsoft.ContainerService
    

Seccomp 限制

  • AKS 只支援預設的 seccomp 設定檔(RuntimeDefault 和 Unconfined)。 不支援自訂的 seccomp 配置檔。
  • SeccompDefault 是 Windows 節點池不支援的參數。

預設 seccomp 設定檔概述(預覽)

AppArmor 適用於任何 Linux 應用程式,但 seccomp(或 安全運算)則是在 程序層級運作。 Seccomp 同時也是 Linux 核心的安全模組。 AKS 節點使用的 containerd 執行階段提供 seccomp 的原生支援。 使用 seccomp,您可以限制容器的系統呼叫。 seccomp 會針對惡意執行者進行的常見系統呼叫弱點建立額外的保護層,並可讓您為節點中的所有工作負載指定預設設定檔。

您可以在建立新的 Linux 節點集區時,使用自訂節點設定來套用預設 seccomp 設定檔。 AKS 支持 RuntimeDefault 與 Unconfined 價值觀。 某些工作負載可能需要比其他工作負載少一些的系統呼叫限制。 這表示它們可能會在使用 RuntimeDefault 設定檔的執行階段中失敗。 若要緩解這類失敗,您可以指定 Unconfined 設定檔。 如果您的工作負載需要自訂設定檔,請參閱設定自訂 seccomp 設定檔。

用 seccomp 限制容器系統呼叫

  1. 請依照步驟在你的 kubelet 配置中套用 seccomp 設定檔 ,指定 "seccompDefault": "RuntimeDefault"。
  2. 連線到主機。
  3. 確認設定是否套用到節點上。

用 seccomp 解決工作負載故障

啟用 SeccompDefault 時,容器執行階段預設的 seccomp 設定檔會依預設使用於節點上所有已排程的工作負載,這可能會因為 syscalls 遭封鎖而導致工作負載失敗。 如果發生工作負載故障,你可能會看到以下錯誤:

  • 啟用此功能後,工作負載會意外退出,並出現「permission denied」錯誤。
  • 您也可以在 auditd 或 syslog 中看到 seccomp 錯誤訊息,方法是將預設設定檔中的 SCMP_ACT_ERRNO 取代為 SCMP_ACT_LOG。

如果您遇到這些錯誤,建議您將 seccomp 設定檔變更為 Unconfined。 Unconfined 對系統呼叫沒有任何限制,允許所有系統呼叫被執行。

自訂 seccomp 設定檔概述

有了自訂的 seccomp 設定檔,你可以更細緻地控制容器的受限系統呼叫。 您可以透過以下方式建立自己的 seccomp 配置檔:

  • 利用篩選器來指定允許或拒絕的行動。
  • 在 Pod YAML 資訊清單內標註,以與 seccomp 篩選建立關聯。

附註

如需協助排除 seccomp profile 的故障,請參閱 Troubleshoot seccomp profile configuration in Azure Kubernetes Service(AKS)。

設定自訂 seccomp 設定檔

若要看 Seccomp 實際運作,請建立一個防止變更檔案權限的篩選。

  1. AKS 節點的 SSH。

  2. 建立名為 /var/lib/kubelet/seccomp/prevent-chmod 的 seccomp 篩選。

  3. 複製並貼上下列內容:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "name": "chmod",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "fchmodat",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "chmodat",
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    

    在版本 1.19 和更新版本中,您需要設定:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "names": ["chmod","fchmodat","chmodat"],
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    
  4. 在本機電腦上建立名為 aks-seccomp.yaml 的 Pod 資訊清單,然後貼上下列內容。 此清單定義seccomp.security.alpha.kubernetes.io的註解,並參考現有的prevent-chmod過濾器。

    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: localhost/prevent-chmod
    spec:
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    

    在版本 1.19 和更新版本中,您需要設定:

    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
    spec:
      securityContext:
        seccompProfile:
          type: Localhost
          localhostProfile: prevent-chmod
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    
  5. 請使用 kubectl apply 以下指令部署樣本莢艙:

    kubectl apply -f ./aks-seccomp.yaml
    
  6. 請使用指令 kubectl get pods 查看艙體狀態。

    kubectl get pods
    

    在輸出中,你應會看到 pod 回報錯誤。 seccomp 篩選會防止執行 chmod 命令,如範例輸出所示:

    NAME                      READY     STATUS    RESTARTS   AGE
    chmod-prevented           0/1       Error     0          7s
    

Seccomp 安全性設定檔選項

seccomp 安全性設定檔是允許或限制的一組已定義的系統呼叫。 大多數容器執行環境都有預設的 seccomp 設定檔,和 Docker 使用的設定檔很相似甚至相同。 欲了解更多可用設定檔資訊,請參閱 Docker 或 容器化 預設的 seccomp 設定檔。

AKS 在使用自訂節點設定配置 seccomp 時,會使用 containerd 預設的 seccomp 設定檔RuntimeDefault。

預設設定檔封鎖的重要系統呼叫

Docker 和 containerd 都維護安全系統呼叫的允許清單。 當 Docker 和 containerd 有變動時,AKS 會更新預設設定以匹配。 更新此清單可能導致作業負載失敗。 如需版本更新,請參閱 AKS 版本資訊。

下表列出了因不在允許清單中而被有效封鎖的重要系統呼叫。 這份清單並不完整。 如果你的工作負載需要任何被封鎖的系統呼叫,就不要使用 RuntimeDefault seccomp 設定檔。

已封鎖的系統呼叫 描述
acct 計量 syscall,它可讓容器停用自己的資源上限或處理序計量。 也受到 CAP_SYS_PACCT 的限制。
add_key 防止容器使用沒有命名空間的核心金鑰環。
bpf 拒絕將可能持續存在的 bpf 程式載入到核心中,已經受到 CAP_SYS_ADMIN 的限制。
clock_adjtime 時間/日期沒有命名空間。 也受到 CAP_SYS_TIME 的限制。
clock_settime 時間/日期沒有命名空間。 也受到 CAP_SYS_TIME 的限制。
clone 拒絕複製新的命名空間。 也受到 CAP_SYS_ADMIN for CLONE_* 旗標的限制 (除了 CLONE_NEWUSER 之外)。
create_module 拒絕核心模組上的操作和函式。 已過時。 也受到 CAP_SYS_MODULE 的限制。
delete_module 拒絕核心模組上的操作和函式。 也受到 CAP_SYS_MODULE 的限制。
finit_module 拒絕核心模組上的操作和函式。 也受到 CAP_SYS_MODULE 的限制。
get_kernel_syms 拒絕擷取匯出的核心和模組符號。 已過時。
get_mempolicy 修改核心記憶體和 NUMA 設定的系統呼叫。 已經也受到 CAP_SYS_NICE 的限制。
init_module 拒絕核心模組上的操作和函式。 也受到 CAP_SYS_MODULE 的限制。
ioperm 防止容器修改核心 I/O 權限等級。 已經也受到 CAP_SYS_RAWIO 的限制。
iopl 防止容器修改核心 I/O 權限等級。 已經也受到 CAP_SYS_RAWIO 的限制。
kcmp 限制處理程序檢查功能,已透過捨棄 CAP_SYS_PTRACE 而被封鎖。
kexec_file_load kexec_load 的同等系統呼叫,執行相同的動作,稍微不同的引數。 也受到 CAP_SYS_BOOT 的限制。
kexec_load 拒絕載入新的核心供稍後執行。 也受到 CAP_SYS_BOOT 的限制。
keyctl 防止容器使用沒有命名空間的核心金鑰環。
lookup_dcookie 追蹤/分析系統呼叫,其可能洩漏主機上的資訊。 也受到 CAP_SYS_ADMIN 的限制。
mbind 修改核心記憶體和 NUMA 設定的系統呼叫。 已經也受到 CAP_SYS_NICE 的限制。
mount 拒絕掛接,已經也受到 CAP_SYS_ADMIN 的限制。
move_pages 修改核心記憶體和 NUMA 設定的系統呼叫。
nfsservctl 拒絕與核心 NFS 精靈的互動。 自 Linux 3.1 起已過時。
open_by_handle_at 舊容器突破的原因。 也受到 CAP_DAC_READ_SEARCH 的限制。
perf_event_open 追蹤/分析系統呼叫,其可能洩漏主機上的資訊。
personality 防止容器啟用 BSD 模擬。 本質上並非危險,但若測試不佳,則可能是核心漏洞。
pivot_root 拒絕 pivot_root,應該是特殊權限作業。
process_vm_readv 限制處理程序檢查功能,已透過捨棄 CAP_SYS_PTRACE 而被封鎖。
process_vm_writev 限制處理程序檢查功能,已透過捨棄 CAP_SYS_PTRACE 而被封鎖。
ptrace 追蹤/分析系統呼叫。 在 4.8 之前的 Linux 核心版本中封鎖,以避免 seccomp 略過。 追蹤/剖析任意處理序已經因捨棄 CAP_SYS_PTRACE 而遭封鎖,原因是它可能會洩漏主機資訊。
query_module 拒絕核心模組上的操作和函式。 已過時。
quotactl 配額 syscall,它可讓容器停用自己的資源上限或處理序計量。 也受到 CAP_SYS_ADMIN 的限制。
reboot 不要讓容器重新啟動主機。 也受到 CAP_SYS_BOOT 的限制。
request_key 防止容器使用沒有命名空間的核心金鑰環。
set_mempolicy 修改核心記憶體和 NUMA 設定的系統呼叫。 已經也受到 CAP_SYS_NICE 的限制。
setns 拒絕將執行緒與命名空間產生關聯。 也受到 CAP_SYS_ADMIN 的限制。
settimeofday 時間/日期沒有命名空間。 也受到 CAP_SYS_TIME 的限制。
stime 時間/日期沒有命名空間。 也受到 CAP_SYS_TIME 的限制。
swapon 拒絕啟動/停止交換到檔案/裝置。 也受到 CAP_SYS_ADMIN 的限制。
swapoff 拒絕啟動/停止交換到檔案/裝置。 也受到 CAP_SYS_ADMIN 的限制。
sysfs 已過時的系統呼叫。
_sysctl 已過時,被 /proc/sys取代。
umount 應是特殊權限的作業。 也受到 CAP_SYS_ADMIN 的限制。
umount2 應是特殊權限的作業。 也受到 CAP_SYS_ADMIN 的限制。
unshare 拒絕複製程序的新命名空間。 同樣由 CAP_SYS_ADMIN(除 unshare --user外)控制。
uselib 與共用程式庫相關的舊版系統呼叫,一段時間未使用。
userfaultfd 使用者空間頁面錯誤處理,主要需用於處理程序移轉。
ustat 已過時的系統呼叫。
vm86 在核心 x86 真實模式虛擬機器中。 也受到 CAP_SYS_ADMIN 的限制。
vm86old 在核心 x86 真實模式虛擬機器中。 也受到 CAP_SYS_ADMIN 的限制。

想了解更多如何保護你的 AKS 叢集,請參閱以下文章: