Como denunciar violações de auditoria do Policy Controller no Security Command Center

Last reviewed 2023-04-17 UTC

Este tutorial mostra aos administradores de segurança da plataforma como visualizar e gerenciar violações de política para recursos do Kubernetes, além de outras vulnerabilidades e descobertas de segurança no Security Command Center. Neste tutorial, use o Policy Controller ou Open Policy Agent (OPA, na silga em inglês) Gatekeeper.

Arquitetura

O Policy Controller verifica, audita e aplica a conformidade dos recursos do cluster do Kubernetes com políticas relacionadas a segurança, regulamentos ou regras de negócios. O Policy Controller foi desenvolvido com base no projeto de código aberto OPA Gatekeeper.

Com a funcionalidade de auditoria no Policy Controller e no OPA Gatekeeper, é possível implementar controles de detecção que avaliam periodicamente os recursos em relação às políticas. Se um problema for detectado, os controles criarão violações dos recursos que não estão em conformidade com as políticas. Essas violações são armazenadas no cluster e é possível consultá-las usando ferramentas do Kubernetes, como kubectl.

Para tornar essas violações visíveis e ajudar você a tomar providências, use o Security Command Center. O Security Command Center fornece um painel e APIs para mostrar, entender e corrigir riscos de segurança e dados em uma organização para recursos do Google Cloud, recursos do Kubernetes e recursos híbridos ou de várias nuvens.

O Security Command Center mostra possíveis riscos de segurança e violações de políticas, chamadas de descobertas. As descobertas são provenientes de origens, que são mecanismos capazes de detectar e denunciar riscos e violações. O Security Command Center inclui serviços integrados e é possível adicionar origens de terceiros e as suas próprias.

Neste tutorial e no código-origem associado, mostramos como criar uma origem e descobertas no Security Command Center para violações de políticas do Policy Controller e OPA Gatekeeper.

O diagrama a seguir mostra a arquitetura implementada neste tutorial:

Arquitetura com uma origem, um controlador e uma sincronização.

Como mostrado no diagrama anterior, neste tutorial, você criará uma origem no Security Command Center usando uma ferramenta de linha de comando. Você implantará um controlador em um cluster do Google Kubernetes Engine (GKE) para sincronizar as violações de restrição do Policy Controller e do OPA Gatekeeper com as descobertas no Security Command Center.

Se quiser ver como sincronizar violações da política para recursos do Google Cloud, acesse nosso tutorial sobre como criar recursos do Google Cloud em conformidade com a política usando o Config Connector e o OPA Gatekeeper.

Objetivos

  • Criar uma política e um recurso que viole a política.
  • Criar uma origem no Security Command Center.
  • Criar uma descoberta no Security Command Center a partir de uma violação da política do OPA Gatekeeper usando uma ferramenta de linha de comando.
  • Implantar um controlador no cluster do GKE para sincronizar periodicamente as descobertas no Security Command Center a partir de violações da política do OPA Gatekeeper.
  • Visualize as descobertas no seu terminal e no Console do Google Cloud.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

  1. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  2. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  3. Para concluir este tutorial, você precisa ter um papel de editor apropriado para o Security Command Center no nível da organização, como editor administrador da Central de Segurança. O administrador da organização pode conceder esse papel a você.
  4. No Console do Google Cloud, ative o Cloud Shell.

    Ativar o Cloud Shell

Como preparar o ambiente

  1. No Cloud Shell, defina o projeto do Google Cloud que você quer usar neste tutorial:

    gcloud config set project PROJECT_ID
    

    Substitua PROJECT_ID pelo ID do projeto do Google Cloud. Quando você executa esse comando, o Cloud Shell cria uma variável de ambiente exportada chamada GOOGLE_CLOUD_PROJECT que contém o ID do projeto.

  2. Ative as APIs Resource Manager, GKE, Security Command Center e Service Usage:

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

crie um cluster do GKE;

  1. No Cloud Shell, crie um cluster do GKE com a Identidade da carga de trabalho ativada:

    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
    

    Esse comando cria o cluster na zona us-central1-f. É possível usar uma zona ou região diferente.

  2. Conceda a si mesmo o cluster-admin papel de cluster:

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

    Esse papel será necessário para posteriormente criar alguns dos recursos do Kubernetes usados pelo controlador. Ele também será necessário se você instalar a distribuição de código aberto do OPA Gatekeeper.

Como instalar a ferramenta de política

Se você tiver um cluster do GKE gerenciado, siga as instruções para instalar o Controlador de Políticas. Caso contrário, instale a distribuição do OPA Gatekeeper.

Policy Controller

Instale o Policy Controller seguindo as instruções de instalação.

Use um intervalo de auditoria de 60 segundos.

OPA Gatekeeper

  1. No Cloud Shell, defina a versão do OPA Gatekeeper que você quer instalar:

    GATEKEEPER_VERSION=v3.10.0
    
  2. Instale o OPA Gatekeeper:

    kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/$GATEKEEPER_VERSION/deploy/gatekeeper.yaml
    
  3. Verifique se o OPA Gatekeeper está instalado:

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

    Quando a instalação for concluída, a saída exibirá deployment "gatekeeper-controller-manager" successfully rolled out.

Como criar uma política

Uma política no Policy Controller e no OPA Gatekeeper consiste em um modelo de restrição e uma restrição. O modelo de restrição contém a lógica da política. A restrição especifica onde a política se aplica e especifica parâmetros de entrada para a lógica da política.

Nesta seção, você criará uma política para pods do Kubernetes e um que viola a política.

  1. No Cloud Shell, clone o repositório da biblioteca do OPA Gatekeeper, acesse o diretório do repositório e confira uma confirmação conhecida:

    git clone https://github.com/open-policy-agent/gatekeeper-library.git \
        ~/gatekeeper-library
    
    cd ~/gatekeeper-library
    
    git checkout 1da0facae99658accb73c291cb79f497fcddf641
    
  2. Crie um pod chamado nginx-disallowed no namespace default:

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

    Veja a seguir o manifesto que você aplica para criar o pod:

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

    Esse pod usa uma imagem de contêiner de um repositório que não é aprovado pela política.

  3. Crie um modelo de restrição chamado k8sallowedrepos:

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

    Veja a seguir o manifesto do modelo de restrição:

    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. Crie uma restrição chamada repo-is-openpolicyagent:

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

    Veja a seguir o manifesto de restrição:

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

Restrições de auditoria

O controlador de auditoria no Policy Controller e no OPA Gatekeeper avalia periodicamente os recursos em relação às restrições. Essa auditoria permite detectar recursos que violam as políticas que foram criados antes da criação da restrição.

  1. No Cloud Shell, veja violações de todas as restrições consultando através da constraint categoria:

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

    A saída é esta:

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

    Há uma violação para o pod que você criou antes de criar a restrição. Se você vir null em vez da saída anterior, a auditoria do Policy Controller ou do OPA Gatekeeper não foi executada desde a criação da restrição. Por padrão, a auditoria é executada a cada minuto. Aguarde um minuto e tente novamente.

Como criar uma origem do Security Command Center

O Security Command Center registra descobertas em relação a origens. Siga as etapas abaixo para criar uma origem para as descobertas do Policy Controller e do OPA Gatekeeper:

  1. No Cloud Shell, crie uma conta de serviço do Google e armazene o nome da conta de serviço em uma variável de ambiente:

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

    Use essa conta de serviço do Google para administrar as origens do Security Command Center.

  2. Defina uma variável de ambiente que contenha seu ID da organização do Google Cloud:

    ORGANIZATION_ID=$(gcloud projects get-ancestors $GOOGLE_CLOUD_PROJECT \
        --format json | jq -r '.[] | select (.type=="organization") | .id')
    
  3. Conceda o papel de administrador de origems da Central de segurança à conta de serviço do Google do administrador de origens no nível da organização:

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

    Esse papel fornece as permissões securitycenter.sources.* que são necessárias para administrar as origens.

  4. Conceda o papel de consumidor de Service Usage à conta de serviço do Google do administrador de origens no nível da organização:

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

    Esse papel fornece a permissão serviceusage.services.use para usar projetos na organização para fins de cota e faturamento.

  5. Conceda a si mesmo o papel de criador de token da conta de serviço para a conta de serviço do Google do administrador de origens:

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

    Esse papel permite que sua identidade de usuário represente ou atue como a conta de serviço do Google.

  6. Faça o download da versão mais recente da ferramenta de linha de comando gatekeeper-securitycenter para sua plataforma e torne-a executável:

    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. Use a ferramenta gatekeeper-securitycenter para criar uma origem do Security Command Center para sua organização. Capture o nome da origem completo em uma variável de ambiente.

    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')
    

    Esse comando cria uma origem com o nome de exibição Gatekeeper. Esse nome de exibição fica visível no Security Command Center. É possível usar um nome de exibição e uma descrição diferentes.

    Se você receber uma resposta com a mensagem de erro The caller does not have permission, aguarde um minuto e tente novamente. Este erro poderá ocorrer se as vinculações do Identity and Access Management (IAM) ainda não tiverem entrado em vigor.

Como criar descobertas usando a linha de comando

É possível criar descobertas do Security Command Center a partir de violações de restrição do Policy Controller and OPA Gatekeeper usando a ferramenta gatekeeper-securitycenter como parte de um pipeline de criação ou tarefa programada.

  1. No Cloud Shell, crie uma conta de serviço do Google e armazene o nome da conta de serviço em uma variável de ambiente:

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

    Use essa conta de serviço do Google para criar descobertas para sua origem de Security Command Center.

  2. Conceda o papel de editor de descobertas da Central de segurança à conta de serviço do Google para a origem:

    ./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
    

    Este papel fornece as permissões securitycenter.findings.* necessárias para criar e editar descobertas. Ao executar esse comando, você representará a conta de serviço do Google do administrador de origens.

  3. Conceda o papel de consumidor do Service Usage à conta de serviço do Google do editor de descobertas no nível da organização:

    gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \
        --member "serviceAccount:$FINDINGS_EDITOR_SA" \
        --role roles/serviceusage.serviceUsageConsumer
    
  4. Conceda à sua identidade de usuário o papel de criador de token da conta de serviço para a conta de serviço do Google do editor de descobertas:

    gcloud iam service-accounts add-iam-policy-binding \
        $FINDINGS_EDITOR_SA \
        --member "user:$(gcloud config get-value account)" \
        --role roles/iam.serviceAccountTokenCreator
    
  5. Imprima as descobertas no terminal em vez de criá-las no Security Command Center:

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

    Esse comando usa seu contexto kubeconfig atual por padrão. Se você quiser usar um arquivo kubeconfig diferente, use a sinalização --kubeconfig.

    A resposta será semelhante a:

    [
      {
        "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
          }
        }
      }
    ]
    

    Na saída anterior, API_SERVER é o endereço IP ou o nome do host do servidor API de cluster do GKE.

    Para saber o que os campos significam, consulte a página Como encontrar recursos da API Security Command Center.

  6. Criar descobertas no Security Command Center:

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

    Ao executar esse comando, você representa a conta de serviço do Google do editor de descobertas.

    A saída inclui create finding, o que significa que a ferramenta de linha de comando gatekeeper-securitycenter criou uma descoberta. O atributo findingID dessa saída contém o nome completo da descoberta no formato:

    organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID
    

    Nesta saída:

    • ORGANIZATION_ID é o ID da organização no Google Cloud
    • SOURCE_ID é o ID da origem do Security Command Center.
    • FINDING_ID é o ID da descoberta.

    Para ver a descoberta, consulte a seção Como visualizar descobertas.

    Se você receber uma resposta com a mensagem de erro The caller does not have permission, aguarde um minuto e tente novamente. Este erro poderá ocorrer se as vinculações do Identity and Access Management (IAM) ainda não tiverem entrado em vigor.

Como criar descobertas usando um controlador do Kubernetes

É possível implantar gatekeeper-securitycenter como um controlador no cluster do GKE. Este controlador verifica periodicamente se há violações de restrições e cria uma descoberta no Security Command Center para cada violação.

Se o recurso entra em conformidade, o controlador definirá o estado da descoberta existente para INACTIVE.

  1. No Cloud Shell, crie uma vinculação de política do IAM de Identidade da carga de trabalho para permitir que a conta de serviço do Kubernetes gatekeeper-securitycenter-controller no namespace gatekeeper-securitycenter represente o editor de descobertas da conta de serviço do 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
    

    Você cria a conta de serviço e o namespace do Kubernetes ao implantar o controlador.

  2. Busque o pacote kpt para o controlador gatekeeper-securitycenter:

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

    Esse comando cria um diretório chamado manifests que contém os arquivos de manifestos de recursos para o controlador.

    O kpt é uma ferramenta de linha de comando que permite gerenciar, manipular, personalizar e aplicar recursos do Kubernetes. Neste tutorial, você usará o kpt para personalizar os manifestos de recursos para seu ambiente.

  3. Defina o nome da origem do Security Command Center:

    kpt fn eval manifests \
        --image gcr.io/kpt-fn/apply-setters:v0.2 -- \
        "source=$SOURCE_NAME"
    
  4. Defina o nome do cluster:

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

    O controlador adiciona o nome do cluster como uma propriedade de origem às descobertas criadas no Security Command Center. Se você tiver vários clusters, esse nome ajudará a encontrar a que cluster uma descoberta pertence.

  5. Para vincular a conta de serviço do Kubernetes de controlador à conta de serviço do editor de descobertas do Google, adicione a anotação de Identidade da carga de trabalho:

    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. Inicialize o pacote do controlador:

    kpt live init manifests
    
  7. Aplique os recursos do controlador ao cluster:

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

    Esse comando cria os seguintes recursos no cluster:

    • Um namespace chamado gatekeeper-securitycenter.
    • Uma conta de serviço chamada gatekeeper-securitycenter-controller.
    • Um papel de cluster que fornece acesso get e list a todos os recursos em todos os grupos de API. Esse papel é necessário porque o controlador recupera os recursos que causaram violações da política.
    • Uma vinculação de papel de cluster que concede o papel do cluster à conta de serviço.
    • Uma implantação chamada gatekeeper-securitycenter-controller-manager.
    • Um mapa de configuração chamado gatekeeper-securitycenter-config, que contém valores de configuração para a implantação.

    O comando também aguarda os recursos estarem prontos.

  8. Verifique se o controlador pode ler violações de restrição e se comunicar com a API Security Command Center seguindo o registro do controlador:

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

    Você verá entradas de registro com a mensagem syncing findings.

    Para parar de seguir o registro, pressione Ctrl+C.

  9. Para verificar se o controlador pode criar novas descobertas, crie uma política e um recurso que a viole. O pod usa resumos de imagens para consultar imagens de contêiner.

    Acesse o diretório do repositório da biblioteca do OPA Gatekeeper:

    cd ~/gatekeeper-library
    
  10. Crie um pod chamado opa-disallowed no namespace default:

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

    Veja a seguir o manifesto que você aplica para criar o 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"
    

    Essa especificação de pod consulta uma imagem de contêiner por tag em vez de por resumo.

  11. Crie um modelo de restrição chamado k8simagedigests:

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

    Veja a seguir o manifesto do modelo de restrição:

    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. Crie uma restrição chamada container-image-must-have-digest:

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

    Veja a seguir o manifesto de restrição:

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

    Essa restrição só se aplica ao namespace default.

  13. Siga o registro do controlador:

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

    Após alguns minutos, você verá uma entrada de registro com a mensagem create finding. Essa mensagem significa que o controlador gatekeeper-securitycenter criou uma descoberta.

    Para parar de seguir o registro, pressione Ctrl+C.

  14. Para verificar se o controlador pode definir o estado de descoberta como INACTIVE quando uma violação não é mais relatada pelo Policy Controller ou pelo OPA Gatekeeper, exclua o pod chamadoopa-disallowed no namespace default:

    kubectl delete pod opa-disallowed --namespace default
    
  15. Siga o registro do controlador:

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

    Após alguns minutos, você verá uma entrada de registro com a mensagem updating finding state e o atributo "state":"INACTIVE". Essa mensagem significa que o controlador definiu o estado de descoberta como inativo.

    Para parar de seguir o registro, pressione Ctrl+C.

Como visualizar descobertas

É possível visualizar as descobertas do Security Command Center no terminal e no Console do Google Cloud.

  1. No Cloud Shell, use a CLI gcloud para listar descobertas para sua organização e origem:

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

    Use o comando basename para ver o ID numérico de origem do nome completo da origem.

    A resposta será semelhante a:

    [
      {
        "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",
          [...]
      }
    ]
    

    Nesta saída:

    • API_SERVER é o endereço IP ou nome do host do servidor da API do cluster do GKE
    • ORGANIZATION_ID é o ID da organização no Google Cloud
    • SOURCE_ID é o ID da origem do Security Command Center.
    • FINDING_ID é o ID da descoberta.

    Para saber o que os atributos de descoberta significam, consulte o recurso de Descoberta na API Security Command Center.

  2. Para ver as descobertas no Console do Google Cloud, acesse a guia Descobertas do Security Command Center.

    Acesse Descobertas

  3. Selecione sua organização e clique em Selecionar.

  4. Clique em Visualizar por e selecione Tipo de origem.

  5. Na lista Tipo de origem, clique em Gatekeeper. Se Gatekeeper não estiver na lista de Tipo de origem, limpe todos os filtros na lista de descobertas.

  6. Na lista de descobertas, clique em uma descoberta para ver seus atributos e as propriedades da origem.

    Se um recurso não causar mais uma violação por causa de uma alteração no recurso ou na política, o controlador definirá o estado de descoberta como inativo. Pode levar alguns minutos para que essa alteração esteja visível no Security Command Center.

    Por padrão, o Security Command Center mostra as descobertas ativas. Para ver as descobertas inativas, clique em Mais opções, selecione Incluir descobertas inativas e clique em OK.

Solução de problemas

  • Se o Policy Controller ou OPA Gatekeeper não informar violações no campo statusdos objetos de restrição, use o Cloud Shell para visualizar os registros do controlador de auditoria:

    kubectl logs deployment/gatekeeper-audit --namespace gatekeeper-system \
        --all-containers
    
  • Se o controlador gatekeeper-securitycenter não criar descobertas no Security Command Center, não será possível ver os registros do gerenciador do controlador:

    kubectl logs deployment/gatekeeper-securitycenter-controller-manager \
        --namespace gatekeeper-securitycenter --all-containers
    
  • Se a ferramenta de linha de comando gatekeeper-securitycenter relatar erros, será possível aumentar o nível de detalhes da saída de registro definindo a variável de ambienteDEBUG como true antes de executar o comando gatekeeper-securitycenter:

    export DEBUG=true
    
  • Ao usar a ferramenta de linha de comando gatekeeper-securitycenter para criar uma origem no Security Command Center, você pode receber uma mensagem de erro que termina com este texto:

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

    Nesse caso, consiga novas credenciais para usar com o Application Default Credentials:

    gcloud auth application-default login
    

    Use as novas credenciais para tentar criar a origem novamente.

Se você tiver outros problemas com este tutorial, recomendamos que consulte estes documentos:

Como automatizar a configuração

Para implantações futuras, é possível automatizar as etapas deste tutorial seguindo as instruções no repositório gatekeeper-securitycenter do GitHub.

Limpeza

Para evitar mais cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua os recursos individuais.

Excluir recursos individuais

  1. No Cloud Shell, exclua o cluster do GKE:

    gcloud container clusters delete gatekeeper-securitycenter-tutorial \
        --zone us-central1-f --async --quiet
    
  2. Exclua os arquivos gatekeeper-library:

    rm -rf ~/gatekeeper-library
    
  3. Exclua as vinculações da política do 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. Exclua as contas de serviço do 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
    

A seguir