使用 Gatekeeper 以应用自定义 Pod 级层安全政策


本页面介绍如何使用 Gatekeeper 准入控制器将 Pod 级层的安全控制机制应用于 Google Kubernetes Engine (GKE) 集群。

概览

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

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

Gatekeeper 还具有以下功能:

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

概念

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 Cloud 提供官方支持的代管式开源 Gatekeeper 版本,名为 Policy Controller。Google 并不正式支持开源 Gatekeeper 项目。

准备工作

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

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

在使用 Policy Controller 的集群上启用 Gatekeeper

Policy Controller 是一个基于 Gatekeeper 开源项目构建的政策引擎。Google 建议使用 Policy Controller,因为它包含额外的功能,有助于大规模强制执行政策,包括政策即代码、多集群支持、与 Cloud Logging 的集成以及查看 Google Cloud 控制台中的政策状态的功能。Policy Controller 可通过 Google Kubernetes Engine (GKE) Enterprise 版本许可使用,但您也可以改为在集群上安装 Gatekeeper

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

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

安装并启用 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 的替代方案

借助 Gatekeeper,您可以声明和应用自定义 Pod 级层安全政策。您还可以使用 Kubernetes 的内置 PodSecurity 准入控制器来应用预定义的 Pod 级层安全政策。这些预定义政策与 Pod 安全标准定义的级层一致。

后续步骤

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