在 Security Command Center 中报告 Policy Controller 审核违规行为

Last reviewed 2023-04-17 UTC

本教程向平台安全管理员介绍了如何在 Security Command Center 中查看和管理 Kubernetes 资源违反政策行为以及其他漏洞和安全性发现结果。在本教程中,您可以使用 Policy ControllerOpen Policy Agent (OPA) Gatekeeper

架构

Policy Controller 用于检查、审核并强制您的 Kubernetes 集群资源遵守与安全性、法规或业务规则相关的政策。Policy Controller 是基于 OPA Gatekeeper 开源项目构建的。

借助 Policy Controller 和 OPA Gatekeeper 中的审核功能,您可以实现检测控制以根据政策定期评估资源。如果检测到问题,检测控制会针对不符合政策的资源创建违规行为。这些违规行为存储在集群中,您可以使用 kubectl 等 Kubernetes 工具进行查询。

为显示这些违规行为并帮助您采取措施,您可以使用 Security Command Center。Security Command Center 提供了信息中心和 API,可显示、了解和修复整个组织内 Google Cloud 资源、Kubernetes 资源以及混合或多云端资源的安全和数据风险。

Security Command Center 会显示可能的安全风险和违反政策行为(称为发现结果)。发现结果来自来源,这些来源是可以检测和报告风险与违规的机制。Security Command Center 包含内置服务,您可以添加第三方来源和您自己的来源。

本教程和关联的源代码介绍了如何在 Security Command Center 中为 Policy Controller 和 OPA Gatekeeper 违反政策行为创建来源和发现结果。

下图显示了本教程中实现的架构:

包含来源、控制器和同步的架构。

如上图所示,在本教程中您将使用命令行工具在 Security Command Center 中创建来源。将控制器部署到 Google Kubernetes Engine (GKE) 集群,以便将 Policy Controller 和 OPA Gatekeeper 限制条件违规行为同步到 Security Command Center 中的发现结果。

如需了解如何同步 Google Cloud 资源违反政策行为,请试用我们关于如何使用 Config Connector 和 Policy Controller 创建符合政策的 Google Cloud 资源的教程。

目标

  • 创建政策和违反该政策的资源。
  • 在 Security Command Center 中创建来源。
  • 使用命令行工具,根据 OPA Gatekeeper 违反政策行为在 Security Command Center 中创建发现结果。
  • 将控制器部署到 GKE 集群,以根据 OPA Gatekeeper 违反政策行为定期同步 Security Command Center 中的发现结果。
  • 在终端和 Google Cloud 控制台中查看发现结果。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 如需完成本教程,您必须在组织级层对 Security Command Center 拥有适当的编辑者角色,例如 Security Center Admin Editor。您的组织管理员可以为您授予此角色
  4. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

准备环境

  1. 在 Cloud Shell 中,设置要用于本教程的 Google Cloud 项目:

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您的 Google Cloud 项目 ID。 运行此命令时,Cloud Shell 会创建一个名为 GOOGLE_CLOUD_PROJECT 的已导出环境变量,其中包含您的项目 ID。

  2. 启用 Resource Manager、GKE、Security Command Center 和 Service Usage API:

    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        container.googleapis.com \
        securitycenter.googleapis.com \
        serviceusage.googleapis.com
    

创建 GKE 集群

  1. 在 Cloud Shell 中,创建一个启用了 Workload Identity 的 GKE 集群:

    gcloud container clusters create gatekeeper-securitycenter-tutorial \
        --enable-ip-alias \
        --release-channel regular \
        --workload-pool $GOOGLE_CLOUD_PROJECT.svc.id.goog \
        --zone us-central1-f
    

    此命令会在 us-central1-f 可用区中创建集群。您可以使用其他可用区或区域

  2. 为您自己授予 cluster-admin 集群角色

    kubectl create clusterrolebinding cluster-admin-binding \
        --clusterrole cluster-admin \
        --user $(gcloud config get-value core/account)
    

    您稍后需要此角色来创建控制器使用的一些 Kubernetes 资源。如果安装开源 OPA Gatekeeper 发行版,则也需要此角色。

安装政策工具

如果您有代管式 GKE 集群,请按照相关说明安装 Policy Controller,否则安装 OPA Gatekeeper 发行版。

政策控制器

按照安装说明安装 Policy Controller。

使用 60 秒的审核间隔。

OPA Gatekeeper

  1. 在 Cloud Shell 中,定义要安装的 OPA Gatekeeper 版本:

    GATEKEEPER_VERSION=v3.10.0
    
  2. 安装 OPA Gatekeeper:

    kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/$GATEKEEPER_VERSION/deploy/gatekeeper.yaml
    
  3. 验证是否安装了 OPA Gatekeeper:

    kubectl rollout status deploy gatekeeper-controller-manager \
        -n gatekeeper-system
    

    安装完成后,输出会显示 deployment "gatekeeper-controller-manager" successfully rolled out

创建政策

Policy Controller 和 OPA Gatekeeper 中的政策由限制条件模板限制条件组成。限制条件模板包含政策逻辑。限制条件指定了政策适用的位置以及政策逻辑的输入参数。

在本部分中,您将为 Kubernetes Pod 创建政策并创建违反该政策的 Pod。

  1. 在 Cloud Shell 中,克隆 OPA Gatekeeper 库代码库,转到该代码库目录,然后查看已知的提交:

    git clone https://github.com/open-policy-agent/gatekeeper-library.git \
        ~/gatekeeper-library
    
    cd ~/gatekeeper-library
    
    git checkout 1da0facae99658accb73c291cb79f497fcddf641
    
  2. default 命名空间中创建一个名为 nginx-disallowed 的 Pod:

    kubectl apply -f library/general/allowedrepos/samples/repo-must-be-openpolicyagent/example_disallowed.yaml
    

    以下是您用于创建 Pod 的清单:

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-disallowed
    spec:
      containers:
        - name: nginx
          image: nginx
          resources:
            limits:
              cpu: "100m"
              memory: "30Mi"
    

    此 Pod 使用未经政策批准的代码库中的容器映像。

  3. 创建一个名为 k8sallowedrepos 的限制条件模板:

    kubectl apply -f library/general/allowedrepos/template.yaml
    

    以下是限制条件模板清单:

    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8sallowedrepos
      annotations:
        description: >-
          Requires container images to begin with a string from the specified list.
    spec:
      crd:
        spec:
          names:
            kind: K8sAllowedRepos
          validation:
            # Schema for the `parameters` field
            openAPIV3Schema:
              type: object
              properties:
                repos:
                  description: The list of prefixes a container image is allowed to have.
                  type: array
                  items:
                    type: string
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8sallowedrepos
    
            violation[{"msg": msg}] {
              container := input.review.object.spec.containers[_]
              satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
              not any(satisfied)
              msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
            }
    
            violation[{"msg": msg}] {
              container := input.review.object.spec.initContainers[_]
              satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
              not any(satisfied)
              msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos])
            }
    
  4. 创建一个名为 repo-is-openpolicyagent 的限制条件:

    kubectl apply -f library/general/allowedrepos/samples/repo-must-be-openpolicyagent/constraint.yaml
    

    以下是限制条件清单:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sAllowedRepos
    metadata:
      name: repo-is-openpolicyagent
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
        namespaces:
          - "default"
      parameters:
        repos:
          - "openpolicyagent/"
    

审核限制条件

Policy Controller 和 OPA Gatekeeper 中的审核控制器会定期根据限制条件评估资源。通过审核,您可以检测在创建限制条件之前创建的违反政策的资源。

  1. 在 Cloud Shell 中,通过使用 constraint 类别查询来查看所有限制条件的违规行为:

    kubectl get constraint -o json | jq '.items[].status.violations'
    

    输出如下所示:

    [
      {
        "enforcementAction": "deny",
        "kind": "Pod",
        "message": "container <nginx> has an invalid image repo <nginx>, allowed repos are [\"openpolicyagent\"]",
        "name": "nginx-disallowed",
        "namespace": "default"
      }
    ]
    

    您在创建限制条件之前创建的 Pod 存在违规行为。如果看到 null 而不是上面的输出,则 Policy Controller 或 OPA Gatekeeper 审核自创建限制条件以来一直未运行。默认情况下,该审核每分钟运行一次。请稍等片刻,然后重试。

创建 Security Command Center 来源

Security Command Center 会根据来源记录发现结果。请按照以下步骤为 Policy Controller 和 OPA Gatekeeper 中的发现结果创建来源:

  1. 在 Cloud Shell 中,创建一个 Google 服务账号并将服务账号名称存储在环境变量中:

    SOURCES_ADMIN_SA=$(gcloud iam service-accounts create \
        securitycenter-sources-admin \
        --display-name "Security Command Center sources admin" \
        --format 'value(email)')
    

    您可以使用此 Google 服务账号管理 Security Command Center 来源。

  2. 定义包含您的 Google Cloud 组织 ID 的环境变量:

    ORGANIZATION_ID=$(gcloud projects get-ancestors $GOOGLE_CLOUD_PROJECT \
        --format json | jq -r '.[] | select (.type=="organization") | .id')
    
  3. 在组织级层向来源管理员的 Google 服务账号授予 Security Center Sources Admin 角色:

    gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:$SOURCES_ADMIN_SA" \
        --role roles/securitycenter.sourcesAdmin
    

    此角色可提供管理来源所需的 securitycenter.sources.* 权限。

  4. 在组织级层向来源管理员的 Google 服务账号授予 Service Usage Consumer 角色:

    gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:$SOURCES_ADMIN_SA" \
        --role roles/serviceusage.serviceUsageConsumer
    

    此角色提供在组织中使用项目进行配额计算和结算的 serviceusage.services.use 权限。

  5. 为您自己授予来源管理员的 Google 服务账号的 Service Account Token Creator 角色

    gcloud iam service-accounts add-iam-policy-binding \
        $SOURCES_ADMIN_SA \
        --member "user:$(gcloud config get-value account)" \
        --role roles/iam.serviceAccountTokenCreator
    

    此角色可让您的用户身份模拟或充当 Google 服务账号

  6. 下载适用于您的平台的最新版本的 gatekeeper-securitycenter 命令行工具,并使其可执行:

    VERSION=v0.4.0
    
    curl -Lo gatekeeper-securitycenter "https://github.com/GoogleCloudPlatform/gatekeeper-securitycenter/releases/download/${VERSION}/gatekeeper-securitycenter_$(uname -s)_$(uname -m)"
    
    chmod +x gatekeeper-securitycenter
    
  7. 使用 gatekeeper-securitycenter 工具为您的组织创建 Security Command Center 来源。在环境变量中捕获完整的来源名称。

    export SOURCE_NAME=$(./gatekeeper-securitycenter sources create \
        --organization $ORGANIZATION_ID \
        --display-name "Gatekeeper" \
        --description "Reports violations from Policy Controller audits" \
        --impersonate-service-account $SOURCES_ADMIN_SA | jq -r '.name')
    

    此命令会创建一个显示名为 Gatekeeper 的来源。此显示名显示在 Security Command Center 中。您可以使用其他显示名称和说明。

    如果您收到包含错误消息 The caller does not have permission 的响应,请稍等片刻再重试。如果 Identity and Access Management (IAM) 绑定 尚未生效,则可能会发生此错误。

使用命令行创建发现结果

您可以在构建流水线或计划任务中使用 gatekeeper-securitycenter 工具,根据 Policy Controller 和 OPA Gatekeeper 限制条件违规行为创建 Security Command Center 发现结果。

  1. 在 Cloud Shell 中,创建一个 Google 服务账号并将服务账号名称存储在环境变量中:

    FINDINGS_EDITOR_SA=$(gcloud iam service-accounts create \
        gatekeeper-securitycenter \
        --display-name "Security Command Center Gatekeeper findings editor" \
        --format 'value(email)')
    

    您可以使用此 Google 服务账号为 Security Command Center 来源创建发现结果。

  2. 向来源的 Google 服务账号授予 Security Center Findings Editor 角色:

    ./gatekeeper-securitycenter sources add-iam-policy-binding \
        --source $SOURCE_NAME \
        --member "serviceAccount:$FINDINGS_EDITOR_SA" \
        --role roles/securitycenter.findingsEditor \
        --impersonate-service-account $SOURCES_ADMIN_SA
    

    此角色提供创建和修改发现结果所需的 securitycenter.findings.* 权限。运行此命令时,模拟来源管理员的 Google 服务账号。

  3. 在组织级层向发现结果编辑者的 Google 服务账号授予 Service Usage Consumer 角色:

    gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:$FINDINGS_EDITOR_SA" \
        --role roles/serviceusage.serviceUsageConsumer
    
  4. 为您的用户身份授予发现结果编辑者 Google 服务账号的 Service Account Token Creator 角色

    gcloud iam service-accounts add-iam-policy-binding \
        $FINDINGS_EDITOR_SA \
        --member "user:$(gcloud config get-value account)" \
        --role roles/iam.serviceAccountTokenCreator
    
  5. 将发现结果输出到终端,而不是在 Security Command Center 中创建发现结果:

    ./gatekeeper-securitycenter findings sync --dry-run=true
    

    默认情况下,此命令会使用您当前的 kubeconfig 上下文。如果要使用其他 kubeconfig 文件,请使用 --kubeconfig 标志。

    输出类似于以下内容:

    [
      {
        "finding_id": "0be44bcf181ef03162eed40126a500a0",
        "finding": {
          "resource_name": "https://API_SERVER/api/v1/namespaces/default/pods/nginx-disallowed",
          "state": 1,
          "category": "K8sAllowedRepos",
          "external_uri": "https://API_SERVER/apis/constraints.gatekeeper.sh/v1beta1/k8sallowedrepos/repo-is-openpolicyagent",
          "source_properties": {
            "Cluster": "",
            "ConstraintName": "repo-is-openpolicyagent",
            "ConstraintSelfLink": "https://API_SERVER/apis/constraints.gatekeeper.sh/v1beta1/k8sallowedrepos/repo-is-openpolicyagent",
            "ConstraintTemplateSelfLink": "https://API_SERVER/apis/templates.gatekeeper.sh/v1beta1/constrainttemplates/k8sallowedrepos",
            "ConstraintTemplateUID": "e35b1c39-15f7-4a7a-afae-1637b44e81b2",
            "ConstraintUID": "b904dddb-0a23-4f4f-81bb-0103de838d3e",
            "Explanation": "container \u003cnginx\u003e has an invalid image repo \u003cnginx\u003e, allowed repos are [\"openpolicyagent\"]",
            "ProjectId": "",
            "ResourceAPIGroup": "",
            "ResourceAPIVersion": "v1",
            "ResourceKind": "Pod",
            "ResourceName": "nginx-disallowed",
            "ResourceNamespace": "default",
            "ResourceSelfLink": "https://API_SERVER/api/v1/namespaces/default/pods/nginx-disallowed",
            "ResourceStatusSelfLink": "",
            "ResourceUID": "8ddd752f-e620-43ea-b966-4ae2ae507c67",
            "ScannerName": "GATEKEEPER"
          },
          "event_time": {
            "seconds": 1606287680
          }
        }
      }
    ]
    

    在上面的输出中,API_SERVER 是 GKE 集群 API 服务器的 IP 地址或主机名。

    如需了解这些字段的含义,请参阅 Security Command Center API 的查找资源页面。

  6. 在 Security Command Center 中创建发现结果:

    ./gatekeeper-securitycenter findings sync \
        --source $SOURCE_NAME \
        --impersonate-service-account $FINDINGS_EDITOR_SA
    

    运行此命令时,模拟发现结果编辑者的 Google 服务账号。

    输出包含 create finding,这意味着 gatekeeper-securitycenter 命令行工具已创建发现结果。该输出的 findingID 特性包含发现结果的完整名称,格式为:

    organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID
    

    在此输出中:

    • ORGANIZATION_ID 是您的 Google Cloud 组织 ID
    • SOURCE_ID 是您的 Security Command Center 来源 ID
    • FINDING_ID 是发现结果 ID

    如需查看发现结果,请参阅查看发现结果部分。

    如果您收到包含错误消息 The caller does not have permission 的响应,请稍等片刻再重试。如果 Identity and Access Management (IAM) 绑定 尚未生效,则可能会发生此错误。

使用 Kubernetes 控制器创建发现结果

您可以将 gatekeeper-securitycenter 部署为 GKE 集群中的控制器。此控制器会定期检查是否存在约束违规行为,并在 Security Command Center 中为每个违规行为创建发现结果。

如果资源符合政策,则控制器会将现有发现结果的状态设置为 INACTIVE

  1. 在 Cloud Shell 中,创建 Workload Identity IAM 政策绑定,以允许 gatekeeper-securitycenter 命名空间中的 gatekeeper-securitycenter-controller Kubernetes 服务账号模拟发现结果编辑者的 Google 服务账号:

    gcloud iam service-accounts add-iam-policy-binding \
        $FINDINGS_EDITOR_SA \
        --member "serviceAccount:$GOOGLE_CLOUD_PROJECT.svc.id.goog[gatekeeper-securitycenter/gatekeeper-securitycenter-controller]" \
        --role roles/iam.workloadIdentityUser
    

    在部署控制器时创建 Kubernetes 服务账号和命名空间。

  2. 提取 gatekeeper-securitycenter 控制器的 kpt 软件包:

    VERSION=v0.4.0
    
    kpt pkg get https://github.com/GoogleCloudPlatform/gatekeeper-securitycenter.git/manifests@$VERSION manifests
    

    此命令会创建一个名为 manifests 的目录,该目录包含控制器的资源清单文件。

    kpt 是一个命令行工具,您可以用它来管理、操作、自定义和应用 Kubernetes 资源。在本教程中,您将使用 kpt 来自定义环境的资源清单。

  3. 设置 Security Command Center 来源名称:

    kpt fn eval manifests \
        --image gcr.io/kpt-fn/apply-setters:v0.2 -- \
        "source=$SOURCE_NAME"
    
  4. 设置集群名称:

    kpt fn eval manifests \
        --image gcr.io/kpt-fn/apply-setters:v0.2 -- \
        "cluster=$(kubectl config current-context)"
    

    控制器将集群名称作为来源属性添加到在 Security Command Center 中创建的发现结果中。如果您有多个集群,则此名称可帮助您确定发现结果属于哪个集群。

  5. 如需将控制器 Kubernetes 服务账号绑定到发现结果编辑者的 Google 服务账号,请添加 Workload Identity 注解:

    kpt fn eval manifests \
        --image gcr.io/kpt-fn/set-annotations:v0.1.4 \
        --match-kind ServiceAccount \
        --match-name gatekeeper-securitycenter-controller \
        --match-namespace gatekeeper-securitycenter -- \
        "iam.gke.io/gcp-service-account=$FINDINGS_EDITOR_SA"
    
  6. 初始化控制器软件包:

    kpt live init manifests
    
  7. 将控制器资源应用到您的集群:

    kpt live apply manifests --reconcile-timeout 3m --output table
    

    此命令会在您的集群中创建以下资源:

    • 名为 gatekeeper-securitycenter 的命名空间。
    • 名为 gatekeeper-securitycenter-controller 的服务账号。
    • 可提供对所有 API 群组中所有资源的 getlist 权限的集群角色。该角色是必需的,因为控制器会检索导致违反政策的资源。
    • 向集群账号授予集群角色的集群角色绑定。
    • 名为 gatekeeper-securitycenter-controller-manager 的部署。
    • 名为 gatekeeper-securitycenter-config 的配置映射,其中包含用于部署的配置值。

    该命令还会等待资源准备就绪。

  8. 验证控制器是否可以读取限制条件违规行为,并按照控制器日志与 Security Command Center API 进行通信:

    kubectl logs deployment/gatekeeper-securitycenter-controller-manager \
        --namespace gatekeeper-securitycenter --follow --all-containers
    

    您会看到包含消息 syncing findings 的日志条目。

    如需停止按照日志操作,请按 Ctrl+C

  9. 如需验证控制器是否可以创建新发现结果,请创建政策和一项违反该政策的资源。Pod 使用映像摘要来引用容器映像。

    转到 OPA Gatekeeper 库代码库目录:

    cd ~/gatekeeper-library
    
  10. default 命名空间中创建一个名为 opa-disallowed 的 Pod:

    kubectl apply --namespace default -f \
        library/general/imagedigests/samples/container-image-must-have-digest/example_disallowed.yaml
    

    以下是您用于创建 Pod 的清单:

    apiVersion: v1
    kind: Pod
    metadata:
      name: opa-disallowed
    spec:
      containers:
        - name: opa
          image: openpolicyagent/opa:0.9.2
          args:
            - "run"
            - "--server"
            - "--addr=localhost:8080"
    

    此 Pod 规范通过标记(而非摘要)引用容器映像。

  11. 创建一个名为 k8simagedigests 的限制条件模板:

    kubectl apply -f library/general/imagedigests/template.yaml
    

    以下是限制条件模板清单:

    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8simagedigests
      annotations:
        description: >-
          Requires container images to contain a digest.
    
          https://kubernetes.io/docs/concepts/containers/images/
    spec:
      crd:
        spec:
          names:
            kind: K8sImageDigests
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8simagedigests
    
            violation[{"msg": msg}] {
              container := input.review.object.spec.containers[_]
              satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)]
              not all(satisfied)
              msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image])
            }
    
            violation[{"msg": msg}] {
              container := input.review.object.spec.initContainers[_]
              satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)]
              not all(satisfied)
              msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image])
            }
    
  12. 创建一个名为 container-image-must-have-digest 的限制条件:

    kubectl apply -f library/general/imagedigests/samples/container-image-must-have-digest/constraint.yaml
    

    以下是限制条件清单:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sImageDigests
    metadata:
      name: container-image-must-have-digest
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
        namespaces:
          - "default"
    

    此限制条件仅适用于 default 命名空间。

  13. 按照控制器日志操作:

    kubectl logs deployment/gatekeeper-securitycenter-controller-manager \
        --namespace gatekeeper-securitycenter --follow --all-containers
    

    几分钟后,您将看到包含消息 create finding 的日志条目。此消息表示 gatekeeper-securitycenter 控制器创建了一个发现结果。

    如需停止按照日志操作,请按 Ctrl+C

  14. 如需验证在 Policy Controller 或 OPA Gatekeeper 不再报告违规行为时,控制器是否可以将发现结果状态设置为 INACTIVE,请删除 default 命名空间中名为 opa-disallowed 的 Pod:

    kubectl delete pod opa-disallowed --namespace default
    
  15. 按照控制器日志操作:

    kubectl logs deployment/gatekeeper-securitycenter-controller-manager \
        --namespace gatekeeper-securitycenter --follow --all-containers
    

    几分钟后,您将看到包含消息 updating finding state 和特性 "state":"INACTIVE" 的日志条目。此消息表示控制器将发现结果状态设置为无效。

    如需停止按照日志操作,请按 Ctrl+C

查看发现结果

您可以在终端和 Google Cloud 控制台中查看 Security Command Center 发现结果。

  1. 在 Cloud Shell 中,使用 gcloud CLI 列出组织和来源的发现结果:

    gcloud scc findings list $ORGANIZATION_ID \
        --source $(basename $SOURCE_NAME) \
        --format json
    

    您可以使用 basename 命令从完整的来源名称获取来源数字 ID。

    输出类似于以下内容:

    [
      {
        "finding": {
          "category": "K8sAllowedRepos",
          "createTime": "2020-11-25T06:58:47.213Z",
          "eventTime": "2020-11-25T06:58:20Z",
          "externalUri": "https://API_SERVER/apis/constraints.gatekeeper.sh/v1beta1/k8sallowedrepos/repo-is-openpolicyagent",
          "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID",
          "parent": "organizations/ORGANIZATION_ID/sources/SOURCE_ID",
          "resourceName": "https://API_SERVER/api/v1/namespaces/default/pods/nginx-disallowed",
          "securityMarks": {
            "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID/securityMarks"
          },
          "sourceProperties": {
            "Cluster": "cluster-name",
            "ConstraintName": "repo-is-openpolicyagent",
            "ConstraintSelfLink": "https://API_SERVER/apis/constraints.gatekeeper.sh/v1beta1/k8sallowedrepos/repo-is-openpolicyagent",
            "ConstraintTemplateSelfLink": "https://API_SERVER/apis/templates.gatekeeper.sh/v1beta1/constrainttemplates/k8sallowedrepos",
            "ConstraintTemplateUID": "e35b1c39-15f7-4a7a-afae-1637b44e81b2",
            "ConstraintUID": "b904dddb-0a23-4f4f-81bb-0103de838d3e",
            "Explanation": "container <nginx> has an invalid image repo <nginx>, allowed repos are [\"openpolicyagent\"]",
            "ProjectId": "",
            "ResourceAPIGroup": "",
            "ResourceAPIVersion": "v1",
            "ResourceKind": "Pod",
            "ResourceName": "nginx-disallowed",
            "ResourceNamespace": "default",
            "ResourceSelfLink": "https://API_SERVER/api/v1/namespaces/default/pods/nginx-disallowed",
            "ResourceStatusSelfLink": "",
            "ResourceUID": "8ddd752f-e620-43ea-b966-4ae2ae507c67",
            "ScannerName": "GATEKEEPER"
          },
          "state": "ACTIVE"
        },
        "resource": {
          "name": "https://API_SERVER/api/v1/namespaces/default/pods/nginx-disallowed"
        }
      },
      {
        "finding": {
          "category": "K8sImageDigests",
          [...]
      }
    ]
    

    在此输出中:

    • API_SERVER 是您的 GKE 集群 API 服务器的 IP 地址或主机名
    • ORGANIZATION_ID 是您的 Google Cloud 组织 ID
    • SOURCE_ID 是您的 Security Command Center 来源 ID
    • FINDING_ID 是发现结果 ID

    如需了解发现结果特性的含义,请参阅 Security Command Center API 中的发现结果资源

  2. 如需在 Google Cloud 控制台中查看发现结果,请转到 Security Command Center 中的发现结果标签页。

    转至“发现结果”

  3. 选择您的组织,然后点击选择

  4. 点击查看方式来源类型.

  5. 来源类型列表中,点击 Gatekeeper。如果 Gatekeeper 不在来源类型列表中,请清除发现结果列表中的过滤条件。

  6. 在发现结果列表中,点击相应发现结果以查看发现结果特性和来源属性。

    如果资源由于资源或政策更改而不再导致违规行为,则控制器会将发现结果状态设置为无效。此更改可能需要几分钟才能显示在 Security Command Center 中。

    默认情况下,Security Command Center 会显示有效发现结果。要查看无效的发现结果,请点击更多选项,选择包含无效的发现结果,然后点击确定

问题排查

  • 如果 Policy Controller 或 OPA Gatekeeper 未在限制条件对象的 status 字段中报告违规行为,请使用 Cloud Shell 查看审核控制器的日志:

    kubectl logs deployment/gatekeeper-audit --namespace gatekeeper-system \
        --all-containers
    
  • 如果 gatekeeper-securitycenter 控制器未在 Security Command Center 中创建发现结果,您可以查看控制器管理器的日志:

    kubectl logs deployment/gatekeeper-securitycenter-controller-manager \
        --namespace gatekeeper-securitycenter --all-containers
    
  • 如果 gatekeeper-securitycenter 命令行工具报告错误,您可以在运行 gatekeeper-securitycenter 命令之前通过将 DEBUG 环境变量设置为 true 来提升日志输出的详细程度。

    export DEBUG=true
    
  • 使用 gatekeeper-securitycenter 命令行工具在 Security Command Center 中创建来源时,您可能会收到一条以下面的文本结尾的错误消息:

    oauth2: cannot fetch token: 400 Bad Request
    Response: {
      "error": "invalid_grant",
      "error_description": "Bad Request"
    }
    

    在这种情况下,请获取新凭据以用于应用默认凭据

    gcloud auth application-default login
    

    使用新凭据尝试重新创建来源。

如果您在使用本教程时遇到其他问题,我们建议您查看以下文档:

自动执行设置

对于未来部署,您可以按照 gatekeeper-securitycenter GitHub 代码库中的说明自动执行本教程中的步骤。

清除数据

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生进一步费用,请逐个删除资源。

逐个删除资源

  1. 在 Cloud Shell 中,删除 GKE 集群:

    gcloud container clusters delete gatekeeper-securitycenter-tutorial \
        --zone us-central1-f --async --quiet
    
  2. 删除 gatekeeper-library 文件:

    rm -rf ~/gatekeeper-library
    
  3. 删除 IAM 政策绑定:

    GOOGLE_CLOUD_PROJECT=$(gcloud config get-value core/project)
    
    ORGANIZATION_ID=$(gcloud projects get-ancestors $GOOGLE_CLOUD_PROJECT \
        --format json | jq -r '.[] | select (.type=="organization") | .id')
    
    SOURCE_NAME=$(./gatekeeper-securitycenter sources list \
        --organization "$ORGANIZATION_ID" \
        --impersonate-service-account "securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        | jq -r ".[] | select (.display_name==\"Gatekeeper\") | .name")
    
    ./gatekeeper-securitycenter sources remove-iam-policy-binding \
        --source $SOURCE_NAME \
        --member "serviceAccount:gatekeeper-securitycenter@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role roles/securitycenter.findingsEditor \
        --impersonate-service-account securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    
    gcloud iam service-accounts remove-iam-policy-binding \
        gatekeeper-securitycenter@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --member "serviceAccount:$GOOGLE_CLOUD_PROJECT.svc.id.goog[gatekeeper-securitycenter/gatekeeper-securitycenter-controller]" \
        --role roles/iam.workloadIdentityUser
    
    gcloud iam service-accounts remove-iam-policy-binding \
        gatekeeper-securitycenter@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --member "user:$(gcloud config get-value account)" \
        --role roles/iam.serviceAccountTokenCreator
    
    gcloud organizations remove-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:gatekeeper-securitycenter@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role roles/serviceusage.serviceUsageConsumer
    
    gcloud iam service-accounts remove-iam-policy-binding \
        securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --member "user:$(gcloud config get-value account)" \
        --role roles/iam.serviceAccountTokenCreator
    
    gcloud organizations remove-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role roles/serviceusage.serviceUsageConsumer
    
    gcloud organizations remove-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role roles/securitycenter.sourcesAdmin
    
  4. 删除 Google 服务账号:

    gcloud iam service-accounts delete --quiet \
        gatekeeper-securitycenter@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    
    gcloud iam service-accounts delete --quiet \
        securitycenter-sources-admin@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
    

后续步骤