使用 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 配置。

准备工作

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

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

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

    gcloud init

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

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

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project PROJECT_ID
  • 如果您使用的是可用区级集群,请设置默认计算可用区
    gcloud config set compute/zone COMPUTE_ZONE
  • 如果您使用的是 Autopilot 集群或区域级集群,请设置默认计算区域
    gcloud config set compute/region COMPUTE_REGION
  • gcloud 更新到最新版本:
    gcloud components update

在集群上启用 Gatekeeper

您可以使用以下某种方法在 GKE 集群上启用 Gatekeeper。这些方法不能在同一个集群上共存,因此请确保仅选择一个方法。

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

如需在集群上启用政策控制器,请按照 Anthos Config Management 安装指南操作。

使用 Google Cloud Marketplace

Gatekeeper 作为 Google Cloud Marketplace 中的 Kubernetes 应用提供。Gatekeeper 可以安装到现有集群上,也可以安装到新创建的集群上。

如需从 Cloud Marketplace 部署 Gatekeeper,请参阅从 Google Cloud Marketplace 部署应用

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

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

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

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

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

测试政策

为现有集群引入新政策可能会有负面行为,例如限制现有工作负载。使用 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 的使用不仅仅是安全性,并且可用于管理和运营的其他方面。