Criação segura e Implantar com o Cloud Build, o Artifact Registry e o GKE

1. Introdução

O Container Analysis fornece verificação de vulnerabilidades e armazenamento de metadados para contêineres. Esse serviço executa verificações de vulnerabilidades em imagens no Artifact Registry e no Container Registry, armazena os metadados resultantes e os disponibiliza para consumo com uma API. Com o armazenamento de metadados, é possível armazenar informações de diferentes fontes, incluindo verificação de vulnerabilidades, serviços do Google Cloud e provedores terceirizados.

A verificação de vulnerabilidades pode ocorrer automaticamente ou sob demanda:

  • Quando a verificação automática está ativada, ela é acionada automaticamente sempre que você envia uma nova imagem para o Artifact Registry ou o Container Registry. As informações sobre vulnerabilidades são atualizadas continuamente quando novas vulnerabilidades são descobertas.
  • Quando a Verificação sob demanda estiver ativada, será preciso executar um comando para verificar uma imagem local ou no Artifact Registry ou no Container Registry. A verificação sob demanda oferece flexibilidade para verificar contêineres. Por exemplo, é possível verificar uma imagem criada localmente e corrigir vulnerabilidades antes de armazená-la em um registro. Os resultados da verificação ficam disponíveis por até 48 horas após a conclusão da verificação e as informações de vulnerabilidade não são atualizadas após ela.

Com o Container Analysis integrado ao pipeline de CI/CD, é possível tomar decisões com base nesses metadados. Por exemplo, é possível usar a autorização binária para criar políticas de implantação que permitam apenas implantações de imagens em conformidade de registros confiáveis.

O que você vai aprender

  • Como ativar a verificação automática
  • Como realizar uma verificação sob demanda
  • Como integrar a verificação a um pipeline de build
  • Como assinar imagens aprovadas
  • Como usar os controladores de admissão do GKE para bloquear imagens
  • Como configurar o GKE para permitir apenas imagens aprovadas e assinadas

2. Configuração e requisitos

Configuração de ambiente personalizada

  1. Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • O Nome do projeto é o nome de exibição para os participantes do projeto. É uma string de caracteres não usada pelas APIs do Google Você pode atualizar a qualquer momento.
  • O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser mudado após a definição. O console do Cloud gera automaticamente uma string exclusiva. normalmente você não se importa com o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, que normalmente é identificado como PROJECT_ID. Se você não gostar do ID gerado, poderá gerar outro ID aleatório. Como alternativa, você pode tentar o seu próprio e ver se ele está disponível. Ela não pode ser alterada após essa etapa e permanecerá durante a duração do projeto.
  • Para sua informação, há um terceiro valor, um Número de projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
  1. Em seguida, ative o faturamento no console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não será muito cara, se tiver algum custo. Para encerrar os recursos e não gerar faturamento além deste tutorial, exclua os recursos criados ou exclua o projeto inteiro. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

Inicie o editor do Cloud Shell

Este laboratório foi elaborado e testado para uso com o Editor do Google Cloud Shell. Para acessar o editor,

  1. acesse seu projeto do Google em https://console.cloud.google.com.
  2. No canto superior direito, clique no ícone do editor do Cloud Shell

8560cc8d45e8c112.png

  1. Um novo painel será aberto na parte inferior da janela.

Configuração do ambiente

No Cloud Shell, defina o ID e o número do projeto. Salve-as como variáveis PROJECT_ID e PROJECT_ID.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

Ativar serviços

Ative todos os serviços necessários:

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

Criar repositório do Artifact Registry

Neste laboratório, você vai usar o Artifact Registry para armazenar e verificar imagens. Crie o repositório com o comando a seguir.

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

Configure o Docker para utilizar suas credenciais da gcloud ao acessar o Artifact Registry.

gcloud auth configure-docker us-central1-docker.pkg.dev

3. Varredura automática

A verificação de artefatos é acionada automaticamente toda vez que você envia uma nova imagem para o Artifact Registry ou o Container Registry. As informações sobre vulnerabilidades são atualizadas continuamente quando novas vulnerabilidades são descobertas. Nesta seção, você vai enviar uma imagem para o Artifact Registry e analisar os resultados.

Criar e mudar para um diretório de trabalho

mkdir vuln-scan && cd vuln-scan

Definir uma imagem de amostra

Crie um arquivo chamado Dockerfile com o conteúdo abaixo.

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

EOF

Crie um arquivo chamado main.py com o conteúdo a seguir

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

Criar e enviar a imagem para RA

Use o Cloud Build para criar e enviar automaticamente seu contêiner para o Artifact Registry. Observe a tag bad na imagem. Isso o ajudará a identificá-lo nas etapas posteriores.

gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad

Revisar detalhes da imagem

Quando o processo de build terminar a revisão da imagem e dos resultados de vulnerabilidade no painel do Artifact Registry.

  1. Abra o Artifact Registry no Console do Cloud
  2. Clique em artifact-scanning-repo para ver o conteúdo
  3. Clique nos detalhes da imagem
  4. Clique no resumo mais recente da sua imagem.
  5. Quando a verificação terminar, clique na guia "Vulnerabilidades" da imagem.

Na guia "Vulnerabilidades", você verá os resultados da verificação automática da imagem que acabou de criar.

361be7b3bf293fca.png

A verificação automática está ativada por padrão. Explore as configurações do Artifact Registry para saber como ativar ou desativar a verificação automática.

4. Verificação sob demanda

Existem vários cenários em que pode ser necessário executar uma verificação antes de enviar a imagem para um repositório. Por exemplo, um desenvolvedor de contêiner pode verificar uma imagem e corrigir os problemas antes de enviar o código ao controle de origem. No exemplo abaixo, você vai criar e analisar a imagem localmente antes de agir com base nos resultados.

Criar uma imagem

Nesta etapa, você vai usar o Docker local para criar a imagem no cache local.

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

Digitalize a imagem

Depois que a imagem for criada, solicite uma verificação dela. Os resultados da verificação são armazenados em um servidor de metadados. O job é concluído com um local dos resultados no servidor de metadados.

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

Analisar o arquivo de saída

Reserve um momento para rever a saída da etapa anterior, que foi armazenada no arquivo scan_id.txt. Observe o local do relatório dos resultados da verificação no servidor de metadados.

cat scan_id.txt

Analisar os resultados detalhados da verificação

Para ver os resultados reais da verificação, use o comando list-vulnerabilities no local do relatório indicado no arquivo de saída.

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

A saída contém uma quantidade significativa de dados sobre todas as vulnerabilidades da imagem.

Sinalizar problemas críticos

Os humanos raramente usam os dados armazenados diretamente no relatório. Normalmente, os resultados são usados por um processo automatizado. Use os comandos abaixo para ler os detalhes do relatório e registrar se foram encontradas vulnerabilidades CRÍTICAS

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

A saída desse comando será

Failed vulnerability check for CRITICAL level

5. Verificação do pipeline de criação

Nesta seção, você vai criar um pipeline de build automatizado que vai gerar sua imagem de contêiner, fazer a verificação dela e avaliar os resultados. Se nenhuma vulnerabilidade CRÍTICA for encontrada, a imagem será enviada ao repositório. Se forem encontradas vulnerabilidades CRÍTICAS, o build falhará e será encerrado.

Conceder acesso à conta de serviço do Cloud Build

O Cloud Build vai precisar de direitos para acessar a API de verificação sob demanda. Forneça acesso com os comandos a seguir.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

Criar o pipeline do Cloud Build

O comando a seguir cria um arquivo cloudbuild.yaml no seu diretório que será usado no processo automatizado. Neste exemplo, as etapas são limitadas ao processo de criação do contêiner. No entanto, na prática, você incluiria instruções e testes específicos do aplicativo, além das etapas do contêiner.

Crie o arquivo com o comando a seguir.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

execute o pipeline de CI

Envie o build para processamento a fim de verificar as falhas de build quando uma vulnerabilidade de gravidade CRÍTICA for encontrada.

gcloud builds submit

Analisar falhas no build

A versão que você acabou de enviar falhará porque a imagem contém vulnerabilidades CRÍTICAS.

Revise a falha de build na página Histórico do Cloud Build

Corrigir a vulnerabilidade

Atualize o Dockerfile para usar uma imagem de base que não contenha vulnerabilidades CRÍTICAS.

Substitua o Dockerfile para usar a imagem do Debian 10 com o comando a seguir:

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

Executar o processo de CI com a imagem boa

Envie o build para processamento e verifique se ele será bem-sucedido quando nenhuma vulnerabilidade de gravidade CRÍTICA for encontrada.

gcloud builds submit

Revisar o sucesso do build

O build que você acabou de enviar será concluído porque a imagem atualizada não contém vulnerabilidades CRÍTICAS.

Revise o sucesso do build na página Histórico do Cloud Build.

Analisar os resultados da verificação

Revise a imagem boa no Artifact Registry

  1. Abra o Artifact Registry no Console do Cloud
  2. Clique em artifact-scanning-repo para ver o conteúdo
  3. Clique nos detalhes da imagem
  4. Clique no resumo mais recente da sua imagem.
  5. Clique na guia "Vulnerabilidades" da imagem.

6. Assinando imagens

Criar uma nota de atestador

Uma nota do atestador é simplesmente um pequeno pedaço de dado que funciona como um rótulo para o tipo de assinatura que está sendo aplicada. Por exemplo, uma observação pode indicar a verificação de vulnerabilidades, enquanto outra pode ser usada para a aprovação do controle de qualidade. A nota será mencionada no processo de assinatura.

Criar uma nota

cat > ./vulnz_note.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "Container Vulnerabilities attestation authority"
    }
  }
}
EOM

Armazenar a nota

NOTE_ID=vulnz_note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./vulnz_note.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"

Verificar a nota

curl -vvv  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"

Como criar um atestador

Os atestadores são usados para realizar o processo de assinatura da imagem e anexarão uma ocorrência da nota à imagem para verificação posterior. Crie o atestador para uso posterior.

Criar atestador

ATTESTOR_ID=vulnz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

Verificar atestador

gcloud container binauthz attestors list

A última linha indica NUM_PUBLIC_KEYS: 0. Você vai fornecer as chaves em uma etapa posterior.

Além disso, o Cloud Build cria automaticamente o atestador built-by-cloud-build no seu projeto quando você executa uma versão que gera imagens. Portanto, o comando acima retorna dois atestadores, vulnz-attestor e built-by-cloud-build. Depois que as imagens são criadas, o Cloud Build assina e cria automaticamente atestados para elas.

Adicionando papel do IAM

A conta de serviço de autorização binária precisa de direitos para acessar as observações do atestado. Forneça o acesso com a seguinte chamada de API

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")

BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"


cat > ./iam_request.json << EOM
{
  'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
  'policy': {
    'bindings': [
      {
        'role': 'roles/containeranalysis.notes.occurrences.viewer',
        'members': [
          'serviceAccount:${BINAUTHZ_SA_EMAIL}'
        ]
      }
    ]
  }
}
EOM

Use o arquivo para criar a política do IAM

curl -X POST  \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @./iam_request.json \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"

Como adicionar uma chave KMS

O atestador precisa de chaves criptográficas para anexar a nota e fornecer assinaturas verificáveis. Nesta etapa, você vai criar e armazenar chaves no KMS para que o Cloud Build possa acessar mais tarde.

Primeiro, adicione algumas variáveis de ambiente para descrever a chave nova

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

Criar um keyring para armazenar um conjunto de chaves

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

Criar um novo par de chaves de assinatura assimétrica para o atestador

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing   \
    --default-algorithm="ec-sign-p256-sha256"

Sua chave será exibida na página KMS do console do Google Cloud.

Agora, associe a chave ao seu atestador usando o comando gcloud binauthz:

gcloud beta container binauthz attestors public-keys add  \
    --attestor="${ATTESTOR_ID}"  \
    --keyversion-project="${PROJECT_ID}"  \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

Se você imprimir a lista de autoridades novamente, vai encontrar uma chave registrada:

gcloud container binauthz attestors list

Como criar um atestado assinado

Agora, você tem os recursos configurados que permitem assinar imagens. Use o atestador criado anteriormente para assinar a imagem do contêiner com a qual você está trabalhando

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image

DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
    --format='get(image_summary.digest)')

Agora você pode usar a gcloud para criar seu atestado. O comando apenas recebe os detalhes da chave que você quer usar para assinatura e a imagem de contêiner específica que você quer aprovar

gcloud beta container binauthz attestations sign-and-create  \
    --artifact-url="${CONTAINER_PATH}@${DIGEST}" \
    --attestor="${ATTESTOR_ID}" \
    --attestor-project="${PROJECT_ID}" \
    --keyversion-project="${PROJECT_ID}" \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

Em termos do Container Analysis, isso criará uma nova ocorrência e a anexará à nota do atestador. Para garantir que tudo funcionou como esperado, liste seus atestados

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

7. Como assinar com o Cloud Build

Você ativou a assinatura de imagens e usou manualmente o atestador para assinar sua imagem de amostra. Na prática, convém aplicar atestados durante processos automatizados, como pipelines de CI/CD.

Nesta seção, você vai configurar o Cloud Build para atestar imagens automaticamente.

Papéis

Adicione o papel Visualizador de atestador de autorização binária à conta de serviço do Cloud Build:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/binaryauthorization.attestorsViewer

Adicione o papel Signatário/Verificador de CryptoKey do Cloud KMS à conta de serviço do Cloud Build (assinatura baseada em KMS):

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/cloudkms.signerVerifier

Adicione o papel Anexador de notas do Container Analysis à conta de serviço do Cloud Build:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/containeranalysis.notes.attacher

Preparar a etapa personalizada do Cloud Build

Você vai usar uma etapa do Custom Build no Cloud Build para simplificar o processo de atestado. O Google oferece essa etapa de criação personalizada, que contém funções auxiliares para simplificar o processo. Antes do uso, o código da etapa personalizada de build precisa ser integrado a um contêiner e enviado ao Cloud Build. Para fazer isso, execute os seguintes comandos:

git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/binauthz-attestation
gcloud builds submit . --config cloudbuild.yaml
cd ../..
rm -rf cloud-builders-community

Adicione uma etapa de assinatura ao seu cloudbuild.yaml

Nesta etapa, você vai adicionar a etapa de atestado ao pipeline do Cloud Build criado anteriormente.

  1. Revise a nova etapa que você vai adicionar.

Somente revisão. Não copiar

#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
  1. Substitua o arquivo cloudbuild.yaml pelo pipeline completo atualizado.
cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'



images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good
EOF

Executar o build

gcloud builds submit

Revisar o build no histórico do Cloud Build

Abra o console do Cloud na página Histórico do Cloud Build e revise o build mais recente e a execução das etapas de build.

8. Políticas de controle de admissão

A autorização binária é um recurso do GKE e do Cloud Run que permite validar regras antes que uma imagem de contêiner seja executada. A validação é executada em qualquer solicitação para executar uma imagem, seja ela de um pipeline de CI/CD confiável ou um usuário tentando implantar uma imagem manualmente. Com esse recurso, você protege os ambientes de execução de maneira mais eficaz do que apenas as verificações de pipeline de CI/CD.

Para entender esse recurso, você vai modificar a política padrão do GKE para aplicar uma regra de autorização rígida.

Crie o cluster do GKE

Crie o cluster do GKE:

gcloud beta container clusters create binauthz \
    --zone us-central1-a  \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE

Permita que o Cloud Build seja implantado neste cluster:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/container.developer"

Política "Permitir tudo"

Primeiro, verifique o estado da política padrão e sua capacidade de implantar qualquer imagem

  1. Revisar política atual
gcloud container binauthz policy export
  1. A política de aplicação está definida como ALWAYS_ALLOW.

evaluationMode: ALWAYS_ALLOW

  1. Implante o exemplo para verificar se é possível implantar qualquer coisa
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. Verificar se a implantação funcionou
kubectl get pods

A saída a seguir será exibida:

161db370d99ffb13.png

  1. Excluir implantação
kubectl delete pod hello-server

Política Negar tudo

Agora atualize a política para proibir todas as imagens.

  1. Exportar a política atual para um arquivo editável
gcloud container binauthz policy export  > policy.yaml
  1. Alterar a política

Em um editor de texto, altere o "avaliaçãoMode" de ALWAYS_ALLOW para ALWAYS_DENY.

edit policy.yaml

O arquivo YAML da política será exibido da seguinte maneira:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_DENY
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. Abra o Terminal, aplique a nova política e aguarde alguns segundos para que a alteração seja propagada.
gcloud container binauthz policy import policy.yaml
  1. Tentativa de implantação da carga de trabalho de amostra
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. A implantação falha com a seguinte mensagem
Error from server (VIOLATES_POLICY): admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image gcr.io/google-samples/hello-app:1.0 denied by Binary Authorization default admission rule. Denied by always_deny admission rule

Reverter a política para permitir todos

Antes de prosseguir para a próxima seção, reverta as alterações de política

  1. Alterar a política

Em um editor de texto, altere o "avaliaçãoMode" de ALWAYS_DENY para ALWAYS_ALLOW.

edit policy.yaml

O arquivo YAML da política será exibido da seguinte maneira:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. Aplicar a política revertida
gcloud container binauthz policy import policy.yaml

9. Bloquear vulnerabilidades no GKE

Nesta seção, você vai combinar o que aprendeu até agora implementando um pipeline de CI/CD com o Cloud Build que verifica as imagens e verifica se há vulnerabilidades antes de assinar a imagem e tentar a implantação. O GKE vai usar a autorização binária para validar se a imagem tem uma assinatura da verificação de vulnerabilidades antes de permitir que ela seja executada.

d5c41bb89e22fd61.png

Atualizar a política do GKE para exigir o atestado

Exigir que as imagens sejam assinadas pelo atestador adicionando clusterAdmissionRules à política BinAuth do GKE

Substitua a política pela configuração atualizada usando o comando abaixo.

COMPUTE_ZONE=us-central1-a

cat > binauth_policy.yaml << EOM
defaultAdmissionRule:
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  evaluationMode: ALWAYS_DENY
globalPolicyEvaluationMode: ENABLE
clusterAdmissionRules:
  ${COMPUTE_ZONE}.binauthz:
    evaluationMode: REQUIRE_ATTESTATION
    enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
    requireAttestationsBy:
    - projects/${PROJECT_ID}/attestors/vulnz-attestor
EOM

Aplicar a política

gcloud beta container binauthz policy import binauth_policy.yaml

Tentar implantar a imagem não assinada

Crie um descritor de implantação para o aplicativo criado anteriormente usando o comando a seguir. A imagem usada aqui é aquela que você criou anteriormente, que contém vulnerabilidades críticas e NÃO contém o atestado assinado.

Os controladores de admissão do GKE precisam saber a imagem exata a ser implantada para validar a assinatura de maneira consistente. Para fazer isso, você precisará usar o resumo da imagem em vez de uma tag simples.

Acessar o resumo da imagem ruim

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:bad \
    --format='get(image_summary.digest)')

Usar o resumo na configuração do Kubernetes

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

Tentar implantar o app no GKE

kubectl apply -f deploy.yaml

Analise a carga de trabalho no console e observe o erro que informa que a implantação foi negada:

No attestations found that were valid and signed by a key trusted by the attestor

Implantar uma imagem assinada

Conseguir o resumo da imagem ruim

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:good \
    --format='get(image_summary.digest)')

Usar o resumo na configuração do Kubernetes

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

Implantar o app no GKE

kubectl apply -f deploy.yaml

Analise a carga de trabalho no console e observe se a implantação da imagem foi concluída.

10. Parabéns!

Parabéns, você concluiu o codelab.

O que aprendemos:

  • Como ativar a verificação automática
  • Como realizar uma verificação sob demanda
  • Como integrar a verificação a um pipeline de build
  • Como assinar imagens aprovadas
  • Como usar os controladores de admissão do GKE para bloquear imagens
  • Como configurar o GKE para permitir apenas imagens aprovadas e assinadas

O que vem em seguida:

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto ou mantenha o projeto e exclua cada um dos recursos.

Excluir o projeto

O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para este tutorial.