你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Azure Kubernetes 服务 (AKS) 中使用 Pod 安全策略保护群集(预览)

重要

Pod 安全策略功能已于 2023 年 8 月 1 日弃用,并从 AKS 1.25 及更高版本中删除。

建议在弃用截止时间之前迁移到 Pod 安全许可控制器Azure 策略,以继续获得 Azure 支持。 Pod 安全许可是单个群集实现的内置策略解决方案。 如果要查找企业级策略,那么 Azure 策略是更好的选择。

开始之前

  • 本文假设你有现有 AKS 群集。 如果需要 AKS 群集,请使用 Azure CLIAzure PowerShellAzure 门户创建一个。
  • 需要安装并配置 Azure CLI 2.0.61 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

安装 Azure CLI aks-preview 扩展

重要

AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

  1. 使用 az extension add 命令安装 aks-preview 扩展。

    az extension add --name aks-preview
    
  2. 使用 az extension update 命令更新到扩展的最新版本。

    az extension update --name aks-preview
    

注册 PodSecurityPolicyPreview 功能标志

  1. 使用 az feature register 命令注册 PodSecurityPolicyPreview 功能标志。

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

    状态显示为“已注册”需要几分钟时间

  2. 使用 az feature show 命令验证注册状态。

    az feature show --namespace "Microsoft.ContainerService" --name "PodSecurityPolicyPreview"
    
  3. 当状态反映为已注册时,使用 az provider register 命令刷新 Microsoft.ContainerService 资源提供程序的注册。

    az provider register --namespace Microsoft.ContainerService
    

Pod 安全策略概述

在要创建资源时,Kubernetes 群集会使用许可控制器截获对 API 服务器的请求。 许可控制器随后可以根据一组规则验证资源请求,或转变资源以更改部署参数。

PodSecurityPolicy 是一种许可控制器,用于验证 Pod 规范是否满足定义的要求。 这些要求可能会限制特权容器的使用、对特定类型存储的访问或是容器运行时可以采用的用户或组。 当尝试部署的资源的 Pod 规范不满足 Pod 安全策略中概述的要求时,会拒绝请求。 这种控制可在 AKS 群集中计划的 Pod 的功能可防止出现一些可能的安全漏洞或特权提升。

在 AKS 群集中启用 Pod 安全策略时,会应用一些默认策略。 这些默认策略提供现成体验,用于定义可以计划的 Pod。 但在定义自己的策略之前,可能会在部署 Pod 时遇到问题。 推荐方法是:

  1. 创建 AKS 群集。
  2. 定义自己的 Pod 安全策略。
  3. 启用 Pod 安全策略功能。

Pod 安全策略与 Azure Policy 之间的行为变更

方案 Pod 安全策略 Azure Policy
安装 启用 Pod 安全策略功能 启用 Azure Policy 加载项
部署策略 部署 Pod 安全策略资源 在订阅或资源组范围分配 Azure 策略。 Azure Policy 加载项是 Kubernetes 资源应用程序所必需的。
默认策略 在 AKS 中启用 Pod 安全策略时,将应用默认的“特权”和“无限制”策略。 启用 Azure Policy 加载项不会应用任何默认策略。 必须在 Azure Policy 中显式启用策略。
谁可以创建和分配策略 群集管理员可创建 Pod 安全策略资源 用户必须在 AKS 群集资源组上至少具有“所有者”角色或“资源策略参与者”权限。 - 通过 API,用户可以在 AKS 群集资源范围分配策略。 用户应在 AKS 群集资源上至少具有“所有者”或“资源策略参与者”权限。 - 在 Azure 门户中,可以在管理组/订阅/资源组级别分配策略。
授权策略 用户和服务帐户需要具有显式权限才能使用 Pod 安全策略。 无需执行其他分配,即可授权策略。 在 Azure 中分配策略后,所有群集用户都可以使用这些策略。
策略适用性 管理员用户不能执行 Pod 安全策略。 所有用户(管理员和非管理员)都会看到相同的策略。 不存在基于用户的特殊用例。 可在命名空间级别排除策略应用。
策略范围 Pod 安全策略不指定命名空间 Azure Policy 使用的约束模板不指定命名空间。
拒绝/审核/变更操作 Pod 安全策略仅支持拒绝操作。 可以变更创建请求上的默认值。 可以在执行更新请求期间进行验证。 Azure Policy 支持审核和拒绝操作。 目前尚不支持突变。
Pod 安全策略符合性 不会显示启用 Pod 安全策略之前已存在的 Pod 的符合性。 启用 Pod 安全策略之后创建的不符合策略的 Pod 将遭到拒绝。 应用 Azure 策略之前已存在的不符合策略的 Pod 将显示在策略冲突中。 如果策略设置了“拒绝”效果,则会拒绝启用 Azure 策略后创建的不符合策略的 Pod。
如何查看群集上的策略 kubectl get psp kubectl get constrainttemplate - 将返回所有策略。
Pod 安全策略标准版 - 特权 启用此功能时,默认情况下会创建特权 Pod安全策略资源。 特权模式意味着无限制,因此它等效于没有任何 Azure Policy 分配。
Pod 安全策略标准版 - 基线/默认值 用户安装 Pod 安全策略基线资源。 Azure Policy 提供了一个映射到基线 Pod 安全策略的内置基线计划
Pod 安全策略标准版 - 受限 用户安装受限 Pod 安全策略资源。 Azure Policy 提供了一个映射到受限 Pod 安全策略的内置限制计划

对 AKS 群集启用 Pod 安全策略

注意

实际使用时,在定义自己的自定义策略之前,请勿启用 Pod 安全策略。 在本文中,我们将首先启用 Pod 安全策略,以查看默认策略如何限制 Pod 部署。

  • 使用 az aks update 命令启用 Pod 安全策略。

    az aks update \
        --resource-group myResourceGroup \
        --name myAKSCluster \
        --enable-pod-security-policy
    

默认 AKS 策略

启用 Pod 安全策略时,AKS 会创建一个名为 privileged 的默认策略。 请勿编辑或删除默认策略。 而是应创建自己的策略来定义要控制的设置。 我们首先看一下这些默认策略是什么以及它们如何影响 Pod 部署。

  1. 使用 kubectl get psp 命令查看可用的策略。

    kubectl get psp
    

    输出的外观将与以下示例输出类似:

    NAME         PRIV    CAPS   SELINUX    RUNASUSER          FSGROUP     SUPGROUP    READONLYROOTFS   VOLUMES
    privileged   true    *      RunAsAny   RunAsAny           RunAsAny    RunAsAny    false            *     configMap,emptyDir,projected,secret,downwardAPI,persistentVolumeClaim
    

    privileged Pod 安全策略会应用于 AKS 群集中任何经过身份验证的用户。 此分配由 ClusterRolesClusterRoleBindings 控制。

  2. 使用 kubectl get rolebindings 命令在 kube-system 中搜索 default:privileged: 绑定。

    kubectl get rolebindings default:privileged -n kube-system -o yaml
    

    以下简洁输出显示已将 psp:privilegedClusterRole 分配给任何 system:authenticated 用户。 此功能可在不定义自己的策略的情况下,提供基本级别的特权。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      [...]
      name: default:privileged
      [...]
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: psp:privileged
    subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: Group
      name: system:masters
    

在开始创建自己的 Pod 安全策略之前,请务必了解这些默认策略如何与用户请求进行交互以计划 Pod。 在接下来的几个部分中,我们将计划一些 Pod 以查看这些默认策略的运行情况。

在 AKS 群集中创建测试用户

默认情况下,在使用 az aks get-credentials 命令时,会将 AKS 群集的管理员凭据添加到 kubectl 配置中。 管理员用户不能执行 Pod 安全策略。 如果将 Microsoft Entra 集成用于 AKS 群集,则可以使用非管理员用户的凭据登录,以查看策略的强制实施情况。

  1. 使用 kubectl create namespacekubectl create namespace 命令为测试资源创建名为 psp-aks 的示例命名空间。

    kubectl create namespace psp-aks
    
  2. 使用 kubectl create serviceaccount 命令创建名为 nonadmin-user 的服务帐户。

    kubectl create serviceaccount --namespace psp-aks nonadmin-user
    
  3. 使用 kubectl create rolebinding 命令为 nonadmin-user 创建 RoleBinding,以在命名空间中执行基本操作。

    kubectl create rolebinding \
        --namespace psp-aks \
        psp-aks-editor \
        --clusterrole=edit \
        --serviceaccount=psp-aks:nonadmin-user
    

为管理员和非管理员用户创建别名命令

在使用 kubectl 时,可以通过创建两个命令行别名来突出显示常规管理员用户和非管理员用户之间的差异:

  1. kubectl-admin 别名用于常规管理员用户,其范围限定为 psp-aks 命名空间。
  2. kubectl-nonadminuser 别名用于在前面步骤中创建的 nonadmin-user 用户,其范围限定为 psp-aks 命名空间。
  • 使用以下命令创建两个别名。

    alias kubectl-admin='kubectl --namespace psp-aks'
    alias kubectl-nonadminuser='kubectl --as=system:serviceaccount:psp-aks:nonadmin-user --namespace psp-aks'
    

测试特权 Pod 的创建

我们来测试一下在使用 privileged: true 安全性上下文计划 Pod 时会发生什么。 此安全性上下文会提升 Pod 的特权。 默认特权 AKS 安全策略应拒绝此请求。

  1. 创建名为 nginx-privileged.yaml 的文件并粘贴到以下 YAML 清单的内容中。

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-privileged
    spec:
      containers:
        - name: nginx-privileged
          image: mcr.microsoft.com/oss/nginx/nginx:1.14.2-alpine
          securityContext:
            privileged: true
    
  2. 使用 kubectl apply 命令创建 Pod,并指定 YAML 清单的名称。

    kubectl-nonadminuser apply -f nginx-privileged.yaml
    

    以下示例输出显示未能计划 Pod:

    Error from server (Forbidden): error when creating "nginx-privileged.yaml": pods "nginx-privileged" is forbidden: unable to validate against any pod security policy: []
    

    由于 Pod 未到达计划阶段,因此在继续之前,不存在要删除的资源。

测试非特权 Pod 的创建

在上面的示例中,Pod 规范请求特权提升。 此请求被默认 privilege Pod 安全策略所拒绝,因此 Pod 未能进行计划。 我们尝试在没有特权提升请求的情况下运行相同的 NGINX Pod。

  1. 创建名为 nginx-unprivileged.yaml 的文件并粘贴到以下 YAML 清单的内容中。

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-unprivileged
    spec:
      containers:
        - name: nginx-unprivileged
          image: mcr.microsoft.com/oss/nginx/nginx:1.14.2-alpine
    
  2. 使用 kubectl apply 命令创建 Pod,并指定 YAML 清单的名称。

    kubectl-nonadminuser apply -f nginx-unprivileged.yaml
    

    以下示例输出显示未能计划 Pod:

    Error from server (Forbidden): error when creating "nginx-unprivileged.yaml": pods "nginx-unprivileged" is forbidden: unable to validate against any pod security policy: []
    

    由于 Pod 未到达计划阶段,因此在继续之前,不存在要删除的资源。

使用特定用户上下文测试 Pod 的创建

在上面的示例中,容器映像自动尝试使用根将 NGINX 绑定到端口 80。 此请求被默认 privilege Pod 安全策略所拒绝,因此 Pod 未能启动。 我们尝试使用特定用户上下文(如 runAsUser: 2000)运行相同的 NGINX Pod。

  1. 创建名为 nginx-unprivileged-nonroot.yaml 的文件并粘贴到以下 YAML 清单中。

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-unprivileged-nonroot
    spec:
      containers:
        - name: nginx-unprivileged
          image: mcr.microsoft.com/oss/nginx/nginx:1.14.2-alpine
          securityContext:
            runAsUser: 2000
    
  2. 使用 kubectl apply 命令创建 Pod,并指定 YAML 清单的名称。

    kubectl-nonadminuser apply -f nginx-unprivileged-nonroot.yaml
    

    以下示例输出显示未能计划 Pod:

    Error from server (Forbidden): error when creating "nginx-unprivileged-nonroot.yaml": pods "nginx-unprivileged-nonroot" is forbidden: unable to validate against any pod security policy: []
    

    由于 Pod 未到达计划阶段,因此在继续之前,不存在要删除的资源。

创建自定义 Pod 安全策略

现在你已了解默认 Pod 安全策略的行为,接下来我们提供一种方式使 nonadmin-user 可成功计划 Pod。

我们将创建一个策略,用于拒绝请求特权访问的 Pod。 未显式限制其他选项(如 runAsUser 或允许的卷)。 此类型的策略会拒绝特权访问请求,但允许群集运行请求的 Pod。

  1. 创建名为 psp-deny-privileged.yaml 的文件并粘贴到以下 YAML 清单中。

    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: psp-deny-privileged
    spec:
      privileged: false
      seLinux:
        rule: RunAsAny
      supplementalGroups:
        rule: RunAsAny
      runAsUser:
        rule: RunAsAny
      fsGroup:
        rule: RunAsAny
      volumes:
     - '*'
    
  2. 使用 kubectl apply 命令创建策略,并指定 YAML 清单的名称。

    kubectl apply -f psp-deny-privileged.yaml
    
  3. 使用 kubectl get psp 命令查看可用的策略。

    kubectl get psp
    

    在以下示例输出中,将 psp-deny-privileged 策略与在前面示例中强制实施以创建 Pod 的默认特权策略进行比较。 你的策略仅拒绝使用 PRIV 提升。 psp-deny-privileged 策略对用户或组没有任何限制。

    NAME                  PRIV    CAPS   SELINUX    RUNASUSER          FSGROUP     SUPGROUP    READONLYROOTFS   VOLUMES
    privileged            true    *      RunAsAny   RunAsAny           RunAsAny    RunAsAny    false            *
    psp-deny-privileged   false          RunAsAny   RunAsAny           RunAsAny    RunAsAny    false            *          
    

允许用户帐户使用自定义 Pod 安全策略

在上一步中,创建了一个 Pod 安全策略以拒绝请求特权访问的 Pod。 若要允许使用该策略,请创建 Role 或 ClusterRole。 然后,使用 RoleBinding 或 ClusterRoleBinding 关联这些角色之一。 对于此示例,我们将创建一个 ClusterRole,以允许使用在上一步中创建的 psp-deny-privileged 策略。

  1. 创建名为 psp-deny-privileged-clusterrole.yaml 的文件并粘贴到以下 YAML 清单中。

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: psp-deny-privileged-clusterrole
    rules:
    - apiGroups:
      - extensions
       resources:
      - podsecuritypolicies
       resourceNames:
      - psp-deny-privileged
       verbs:
      - use
    
  2. 使用 kubectl apply 命令创建 ClusterRole,并指定 YAML 清单的名称。

    kubectl apply -f psp-deny-privileged-clusterrole.yaml
    
  3. 创建名为 psp-deny-privileged-clusterrolebinding.yaml 的文件并粘贴到以下 YAML 清单中。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: psp-deny-privileged-clusterrolebinding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: psp-deny-privileged-clusterrole
    subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: Group
      name: system:serviceaccounts
    
  4. 使用 kubectl apply 命令创建 ClusterRoleBinding,并指定 YAML 清单的名称。

    kubectl apply -f psp-deny-privileged-clusterrolebinding.yaml
    

注意

在本文的第一步中,对 AKS 群集启用了 Pod 安全策略功能。 建议做法是仅在定义了自己的策略之后,才启用 Pod 安全策略功能。 这是启用 Pod 安全策略功能的阶段。 已定义了一个或多个自定义策略,并且用户帐户已与这些策略关联。 现在,可以安全地启用 Pod 安全策略功能,并最大程度地减少默认策略导致的问题。

再次测试非特权 Pod 的创建

应用了自定义 Pod 安全策略,并绑定用户帐户以使用策略后,我们再次尝试创建非特权 Pod。

此示例演示如何创建自定义 Pod 安全策略,以便为不同用户或组定义对 AKS 群集的访问权限。 默认 AKS 策略会对 Pod 可以运行的内容提供严格控制,因此创建自己的自定义策略,以便正确定义所需限制。

  1. 通过 kubectl apply 命令,使用 nginx-privileged.yaml 清单创建 Pod。

    kubectl-nonadminuser apply -f nginx-unprivileged.yaml
    
  2. 使用 kubectl get pods 命令检查 Pod 的状态。

    kubectl-nonadminuser get pods
    

    以下示例输出显示 Pod 已成功计划并且正在运行

    NAME                 READY   STATUS    RESTARTS   AGE
    nginx-unprivileged   1/1     Running   0          7m14s
    
  3. 使用 kubectl delete 命令删除 NGINX 非特权 Pod,并指定 YAML 清单的名称。

    kubectl-nonadminuser delete -f nginx-unprivileged.yaml
    

清理资源

  1. 使用 az aks update 命令禁用 Pod 安全策略。

    az aks update \
        --resource-group myResourceGroup \
        --name myAKSCluster \
        --disable-pod-security-policy
    
  2. 使用 kubectl delete 命令删除 ClusterRole 和 ClusterRoleBinding。

    kubectl delete -f psp-deny-privileged-clusterrole.yaml
    
  3. 使用 kubectl delete 命令删除 ClusterRoleBinding。

    kubectl delete -f psp-deny-privileged-clusterrolebinding.yaml
    
  4. 使用 kubectl delete 命令删除安全策略,并指定 YAML 清单的名称。

    kubectl delete -f psp-deny-privileged.yaml
    
  5. 使用 kubectl delete 命令删除 psp-aks 命名空间。

    kubectl delete namespace psp-aks
    

后续步骤

本文演示了如何创建 Pod 安全策略以阻止使用特权访问。 策略可以强制实施许多功能,例如卷类型或 RunAs 用户。 有关可用选项的详细信息,请参阅 Kubernetes Pod 安全策略参考文档

有关限制 Pod 网络流量的详细信息,请参阅在 AKS 中使用网络策略保护 Pod 之间的流量