使用 Gatekeeper 应用 pod 安全政策


本页面介绍了将 Pod 级层安全控机制应用于 Google Kubernetes Engine (GKE) 集群的推荐方法。

概览

Gatekeeper 是一个准入控制器,使用开放政策代理 (OPA) 验证在 Kubernetes 集群上创建和更新 Pod 的请求。

借助 Gatekeeper,管理员可以使用“限制条件”来定义政策,这是一组允许或拒绝 Kubernetes 中的部署行为的条件。然后,您可以使用 ConstraintTemplate 在集群上强制执行这些政策。本文档提供了有关如何限制工作负载安全功能以确保使用 Gatekeeper 强制执行、测试和审核安全政策的示例。

除了实施与 Kubernetes PodSecurityPolicy 相同的功能之外,Gatekeeper 还可以执行以下操作:

  • 发布政策:以循序渐进的方式逐步执行政策,以限制中断工作负载的风险。
  • 试运行政策更改:提供在强制执行之前测试政策影响和范围的机制。
  • 审核现有政策:确保将安全控制机制应用于新的和现有的工作负载(审核控制)。

Kubernetes 开源软件 (OSS) 正在弃用 Kubernetes PodSecurityPolicy,并且不再推荐使用 Kubernetes Pod。

概念

Gatekeeper 引入了两个概念,以便为管理员提供强大、灵活控制其集群的控制方法:限制条件约束模板,它们都是从开放式政策代理限制条件框架继承的概念。

限制条件是您的安全政策的表示形式,它们定义了强制执行的要求和范围。限制条件模板是可重复使用的语句(使用 Rego 编写),这些语句根据限制条件中定义的要求应用逻辑,以评估 Kubernetes 对象中的特定字段。

例如,您可能有一个限制条件,用于声明可应用于特定命名空间中 Pod 的允许 seccomp 配置文件,以及一个提供限制条件以提取这些值和处理强制执行情况的逻辑模板。

Gatekeeper 代码库中的以下限制条件模板会检查 Pod 规范中是否存在 securityContext.privileged

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8spspprivileged

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            c.securityContext.privileged
            msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
        }
        input_containers[c] {
            c := input.review.object.spec.containers[_]
        }
        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
        }

为扩展上述限制条件模板,以下限制定义了此 dryrun 模式下此限制条件模板的具体执行范围 (kinds):

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

借助 Gatekeeper,您可以创建自己的限制条件和限制条件模板来满足特定需求。您还可以在 Gatekeeper 代码库中使用一组标准限制条件和限制条件模板,以实现快速采用并强制执行安全机制。每个限制条件还附带示例 Pod 配置。

准备工作

在开始之前,请确保您已执行以下任务:

  • 确保您已启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 确保您已安装 Cloud SDK
  • 使用以下方法之一为您的项目设置默认 gcloud 命令行工具设置:
    • 使用 gcloud init(如果您想要在系统引导下完成项目默认设置)。
    • 使用 gcloud config(如果您想要单独设置项目 ID、可用区和区域。

    gcloud init

    1. 运行 gcloud init 并按照说明操作:

      gcloud init

      如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

      gcloud init --console-only
    2. 按照说明授权 gcloud 工具使用您的 Google Cloud 帐号。
    3. 创建新配置或选择现有配置。
    4. 选择 Google Cloud 项目。
    5. 选择默认的 Compute Engine 可用区
    6. 选择默认的 Compute Engine 区域

    gcloud config

    1. 设置默认项目 ID
      gcloud config set project PROJECT_ID
    2. 设置默认的 Compute Engine 区域(例如 us-central1):
      gcloud config set compute/region COMPUTE_REGION
    3. 设置默认的 Compute Engine 可用区(例如 us-central1-c):
      gcloud config set compute/zone COMPUTE_ZONE
    4. gcloud 更新到最新版本:
      gcloud components update

    通过设置默认位置,您可以避免 gcloud 工具中出现以下错误:One of [--zone, --region] must be supplied: Please specify location

在使用 Anthos Config Management 的集群上启用 Gatekeeper

Anthos Config Management 提供了 Policy Controller,这是一个基于 Gatekeeper 开源项目构建的政策引擎。Google 建议使用 Anthos Config Management,因为它可以解决与大规模强制执行政策相关的常见问题,包括政策即代码、多集群支持、与 Cloud Logging 的集成以及同步配置的功能。

如需在集群上启用 Policy Controller,请按照 Anthos Config Management 安装指南操作。

启用限制条件和限制条件模板

与 PodSecurityPolicy 不同,安装并启用 Gatekeeper 及其限制条件模板不会对现有或新的工作负载产生负面影响。因此,建议将所有适用的 Pod 安全限制条件模板应用于集群。

此外,还可以实现 Gatekeeper 限制条件,以强制对特定对象(例如命名空间和 Pod)的控制。

请观看下面的示例,该示例范围限制为位于生产命名空间中的 Pod,方法是在限制条件匹配语句中定一它们:

...
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"

如需详细了解 ConstraintConstraintTemplate 对象的可用选项,请参阅如何使用 Gatekeeper

测试政策

向现有集群引入新政策可能会产生不利行为,例如限制现有工作负载。使用 Gatekeeper 实现 Pod 安全性的一个优势在于,可以使用试运行模式测试政策的有效性和可能产生的影响,而不必作出实际更改。这样,您就可以针对正在运行的集群对政策配置进行测试,而无需强制执行。系统会记录并识别政策违规,而不会造成干扰。

以下步骤演示了开发者、运营商或管理员如何应用限制条件模板和限制条件来确定其有效性或潜在影响:

  1. 应用 Gatekeeper 配置以复制数据,进行审核和试运行功能:

    kubectl create -f- <<EOF
    apiVersion: config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
      name: config
      namespace: "gatekeeper-system"
    spec:
      sync:
        syncOnly:
          - group: ""
            version: "v1"
            kind: "Namespace"
          - group: ""
            version: "v1"
            kind: "Pod"
    EOF
    
  2. 在未应用任何限制条件的情况下,我们运行具有提升权限的工作负载:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    
  3. 加载前面所述的 k8spspprivilegedcontainer 限制条件模板:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  4. 现在,让我们来创建一个新限制条件来扩展此限制条件模板。这次,我们将 enforcementAction 设置为 dryrun

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  5. 通过 Gatekeeper 同步运行的对象数据并被动地检查是否存在违规,我们可以检查限制的 status,确认是否有任何违规行为:

    kubectl get k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container -o yaml
    
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
    ...
     name: psp-privileged-container
    ...
    spec:
     enforcementAction: dryrun
     match:
       kinds:
       - apiGroups:
         - ""
         kinds:
         - Pod
    status:
     auditTimestamp: "2019-12-15T22:19:54Z"
     byPod:
     - enforced: true
       id: gatekeeper-controller-manager-0
     violations:
     - enforcementAction: dryrun
       kind: Pod
       message: 'Privileged container is not allowed: nginx, securityContext: {"privileged":
         true}'
       name: nginx
       namespace: default
    
  6. 让我们运行另一个特权 Pod,以确认该政策不会干扰部署:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: privpod
      labels:
        app: privpod
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    这个新 Pod 将成功部署。

  7. 如需清理本部分中创建的资源,请运行以下命令:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    kubectl delete pod/nginx
    kubectl delete pod/privpod
    

强制执行政策

现在,我们可以在不影响现有工作负载或新工作负载的情况下确认政策的有效性和影响,下面我们实施全面强制执行的政策。

基于用于验证上述政策的示例,以下步骤演示了开发者、运维人员或管理员如何应用限制条件模板和限制条件来强制执行政策:

  1. 加载前面所述的 k8spspprivilegedcontainer 限制条件模板:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  2. 现在,让我们来创建一个新限制条件来扩展此限制条件模板。这次,我们不会设置 enforcementAction 键。默认情况下,enforcementAction 键设置为 deny

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  3. 尝试部署用于声明特许权限的容器:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    您应该会收到以下错误消息:

    Error from server ([denied by psp-privileged-container] Privileged container is not allowed:
    nginx, securityContext: {"privileged": true}): error when creating "STDIN": admission webhook "validation.gatekeeper.sh" denied the request: [denied by psp-privileged-container]
    Privileged container is not allowed: nginx, securityContext: {"privileged": true}
    
  4. 如需清理,请运行以下命令:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    

后续步骤

Gatekeeper 提供了一种极其强大的方法,可以使用声明式政策来在 GKE 集群上强制执行和验证安全性。但是,Gatekeeper 的使用超出了安全范围,可用于管理和操作的其他方面。