Como criar atestados

Nesta página, explicamos como criar um attestation na autorização binária a partir da linha de comando.

As instruções nesta página descrevem as etapas que um signatário precisa executar para autorizar uma imagem de contêiner para implantação. Em um cenário real, você incorpora essas etapas em um script ou automação que pode ser acionada por um processo de máquina ou um usuário humano, em vez de serem inseridas manualmente na linha de comando.

Visão geral

Um attestation é um documento assinado digitalmente, feito por um signatário (em inglês), que garante que o processo necessário no pipeline foi concluído e que a imagem de contêiner resultante. está autorizado para implantação no GKE. O próprio atestado contém o caminho completo para a versão da imagem do contêiner, conforme armazenado no registro da imagem do contêiner, além de uma assinatura criada assinando o resumo globalmente exclusivo que identifica uma versão específica da imagem do contêiner.

Você pode criar um atestado usando uma assinatura PKIX (recomendada) ou PGP. Neste guia, usamos o formato Infraestrutura de chave pública (X.509) (PKIX, na sigla em inglês) para chaves criptográficas e usa o Algoritmo de assinatura digital de curva elíptica (ECDSA, na sigla em inglês) recomendado. ) para assinar e criar o atestado. Também é possível usar chaves RSA ou PGP para assinatura. Consulte Principais finalidades e algoritmos para mais informações sobre algoritmos de assinatura.

Defina o projeto padrão.

Se você ainda não definiu seu projeto padrão do Google Cloud:

PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}

PROJECT_ID é o nome do projeto.

Configure o ambiente

  1. Configure variáveis de ambiente para armazenar os IDs do projeto:

    ATTESTOR_PROJECT_ID=ATTESTOR_PROJECT_ID
    ATTESTATION_PROJECT_ID=ATTESTATION_PROJECT_ID
    

    em que:

    • ATTESTOR_PROJECT_ID é o nome do projeto em que você está armazenando seus atestadores;
    • ATTESTATION_PROJECT_ID é o nome do projeto em que você está armazenando os atestados.

    Se os projetos de atestador e de confirmação forem o mesmo, use o mesmo ID do projeto para as duas variáveis.

  2. Configure variáveis de ambiente para armazenar o nome do atestador que verificará o atestado e o caminho do registro da imagem que você quer implantar:

    ATTESTOR_NAME=ATTESTOR_NAME
    IMAGE_PATH=IMAGE_PATH
    IMAGE_DIGEST=IMAGE_DIGEST
    PUBLIC_KEY_ID=PUBLIC_KEY_ID
    PRIVATE_KEY_FILE=PRIVATE_KEY_FILE
    IMAGE_TO_ATTEST="${IMAGE_PATH}@${IMAGE_DIGEST}"
    

    em que:

    • ATTESTOR_NAME é o nome do atestador (por exemplo, build-secure ou prod-qa);
    • IMAGE_PATH é o caminho no Container Registry para a imagem que você quer implantar (por exemplo, gcr.io/example-project/quickstart-image).
    • PUBLIC_KEY_ID é o código associado à chave pública do par de chaves que você gerou. A chave pública em si é armazenada no atestador.
    • PRIVATE_KEY_FILE é o arquivo que contém a chave privada do par de chaves que você gerou. O payload do atestado é assinado com essa chave.
    • IMAGE_DIGEST é o resumo de SHA-256 do manifesto da imagem (por exemplo, sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4). Para informações sobre como conseguir o resumo da imagem, consulte Como listar o de uma imagem no Container Registry

Cada imagem de contêiner armazenada no Container Registry ou outro registro tem um caminho exclusivo para o local, bem como um resumo SHA-256 que identifica exclusivamente sua versão. Os atestados fazem referência ao caminho completo e ao resumo da imagem, o que permite autorizar versões específicas de uma imagem.

Veja a seguir um exemplo de caminho de registro completo:

gcr.io/example-project/quickstart-image@sha256:bedb3feb23e81d162e33976fd7b245adff00379f4755c0213e84405e5b1e0988

Criar um atestado com uma assinatura PKIX usando uma chave armazenada localmente

Para atestados assinados com uma chave pública PKIX, faça o seguinte:

  1. Criar um payload de confirmação para enviar à autorização binária que faz referência ao caminho do registro
  2. Assine o payload e gere um arquivo de assinatura PKIX
  3. Receber o código da chave pública
  4. Criar o atestado com o arquivo de assinatura e o código da chave pública

Criar um payload de confirmação

O payload de atestado é um arquivo no formato JSON que faz referência ao local da imagem do contêiner.

Para criar o arquivo de payload:

gcloud

Digite o seguinte:

gcloud container binauthz create-signature-payload \
    --artifact-url="${IMAGE_TO_ATTEST}" > /tmp/generated_payload.json

O arquivo de payload é semelhante ao seguinte:

{
  "critical": {
    "identity": {
      "docker-reference": "gcr.io/google-samples/hello-app"
    },
    "image": {
      "docker-manifest-digest": "sha256:bedb3feb23e81d162e33976fd7b245
adff00379f4755c0213e84405e5b1e0988"
    },
    "type": "Google cloud binauthz container signature"
  }
}

REST

Crie um arquivo de payload chamado /tmp/generated_payload.json usando as variáveis de ambiente definidas acima:

cat > /tmp/generated_payload.json << EOM
{
  "critical": {
    "identity": {
      "docker-reference": "${IMAGE_PATH}"
    },
    "image": {
      "${IMAGE_DIGEST}"
    },
    "type": "Google cloud binauthz container signature"
  }
}
EOM

Assine o payload e gere um arquivo de assinatura

Depois de criar o arquivo de payload, você precisa assiná-lo usando a chave criptográfica privada do par de chaves gerado anteriormente. Lembre-se de que a chave pública correspondente foi armazenada no atestador associado. A chave pública desse atestador será usada para verificar essa assinatura no momento da implantação.

Para analisar como criar um atestador, consulte Como criar atestadores usando a CLI ou Como criar atestadores usando o Console.

Para ver um exemplo completo que inclui todas essas etapas, consulte Primeiros passos usando a CLI ou Primeiros passos usando o Console.

Para assinar o arquivo de payload:

  1. Assine o payload com a chave privada PKIX local e gere um arquivo de assinatura:

    openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} /tmp/generated_payload.json > /tmp/ec_signature
    

    O arquivo de assinatura é uma versão assinada digitalmente do payload JSON criado acima.

Receber o código da chave pública

É preciso enviar um código de chave pública para autorização binária com o arquivo de assinatura ao criar um atestado.

Para receber o código da chave pública:

  1. Salve o código da chave pública.

    Para ver o código da chave pública do atestador depois, use gcloud container binauthz attestors describe ${ATTESTOR_NAME}:

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
      --format='value(userOwnedGrafeasNote.publicKeys[0].id)')
    

Criar o atestado

gcloud

Para criar o atestado, digite o seguinte:

gcloud container binauthz attestations create \
    --project="${ATTESTATION_PROJECT_ID}" \
    --artifact-url="${IMAGE_TO_ATTEST}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
    --signature-file=/tmp/ec_signature \
    --public-key-id="${PUBLIC_KEY_ID}"

Como alternativa, para criar e validar o atestado pode ser verificado pelo atestador fornecido:

gcloud alpha container binauthz attestations create \
    --project="${ATTESTATION_PROJECT_ID}" \
    --artifact-url="${IMAGE_TO_ATTEST}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
    --signature-file=/tmp/ec_signature \
    --public-key-id="${PUBLIC_KEY_ID}" \
    --validate

Observação: o código da chave pode ser qualquer string.

REST

Para criar o atestado:

  1. Recupere o atestador associado ao atestado e extraia o ID da chave pública armazenada:

    curl \
        -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
        -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
        "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors/"
    

    A autorização binária retorna um objeto JSON semelhante ao seguinte:

    {
      "name": "projects/example-project/attestors/test-attestor",
      "userOwnedGrafeasNote": {
        "noteReference": "projects/example-project/notes/test-attestor",
        "publicKeys": [
          {
            "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
            "pkixPublicKey": {
              "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
              "signatureAlgorithm": "ECDSA_P256_SHA256"
            }
          }
        ],
        "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
      },
      "updateTime": "2019-06-26T16:58:33.977438Z"
    }
    
  2. Em um editor de texto, crie um arquivo JSON em /tmp/attestation.json que descreva o atestado:

    cat > /tmp/attestation.json << EOM
    {
      "resourceUri": "${IMAGE_TO_ATTEST}",
      "note_name": "${NOTE_URI}",
      "attestation": {
         "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
         "signatures": [
            {
             "public_key_id": "KEY_ID",
             "signature": "$(base64 --wrap=0 /tmp/ec_signature)"
             }
         ]
      }
     }
    EOM
    

    em que KEY_ID é o código da chave pública retornado na etapa anterior.

  3. Crie o atestado:

    curl -X POST \
        -H "Content-Type: application/json" \
        -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)" \
        --data-binary @/tmp/attestation.json \
        "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
    

Criar um atestado com uma assinatura PKIX baseada em serviço do Cloud Key Management Service

Para criar um atestado com uma assinatura PKIX baseada no Cloud Key Management Service:

  1. Configure variáveis de ambiente para armazenar informações sobre os projetos onde seus atestados, atestadores e chaves do Cloud Key Management Service estão armazenados, bem como informações sobre o par de chaves PKIX:

    KMS_KEY_PROJECT_ID=KMS_KEY_PROJECT_ID
    KMS_KEY_LOCATION=KMS_KEY_LOCATION
    KMS_KEYRING_NAME=KMS_KEYRING_NAME
    KMS_KEY_NAME=KMS_KEY_NAME
    KMS_KEY_VERSION=KMS_KEY_VERSION
    

    em que:

    • KMS_KEY_PROJECT_ID é o código do projeto em que as chaves do Cloud Key Management Service estão armazenadas;
    • KMS_KEY_LOCATION é o local da chave (global é o padrão)
    • KMS_KEYRING_NAME é o nome do keyring;
    • KMS_KEY_NAME é o nome da chave;
    • KMS_KEY_VERSION é a versão da chave
  2. Assine e crie o atestado:

    gcloud

    Digite o seguinte na linha de comando:

    gcloud beta container binauthz attestations sign-and-create \
        --project="${ATTESTATION_PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="${ATTESTOR_NAME}" \
        --attestor-project="${ATTESTOR_PROJECT_ID}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    

    REST

    1. Crie um arquivo de payload chamado /tmp/generated_payload.json usando as variáveis de ambiente definidas acima:

      cat > /tmp/generated_payload.json << EOM
      {
        "critical": {
          "identity": {
            "docker-reference": "${IMAGE_PATH}"
          },
          "image": {
            "${IMAGE_DIGEST}"
          },
          "type": "Google cloud binauthz container signature"
        }
      }
      EOM
      
    2. Assine o arquivo de payload:

      gcloud --project="${KMS_KEY_PROJECT_ID}"  \
          alpha kms asymmetric-sign \
          --location="${KMS_KEY_LOCATION}" \
          --keyring="${KMS_KEYRING_NAME}" \
          --key="${KMS_KEY_NAME}" \
          --version="${KMS_KEY_VERSION}" \
          --digest-algorithm="DIGEST_ALGORITHM" \
          --input-file=/tmp/generated_payload.json \
          --signature-file=/tmp/generated_payload.json.sig
      

      em que DIGEST_ALGORITHM é sha256, sha384 ou sha512. Esse é o algoritmo de resumo da versão da chave que você está usando para assinatura.

      Esse comando gera um arquivo chamado /tmp/generated_payload.json.sig que contém a assinatura digital.

    3. Recupere o atestador em nome de quem você está assinando o atestado e extraia o código da chave pública armazenada:

      curl \
          -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
          -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
          "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors/"
      

      A autorização binária retorna um objeto JSON semelhante ao seguinte:

      {
        "name": "projects/example-project/attestors/test-attestor",
        "userOwnedGrafeasNote": {
          "noteReference": "projects/example-project/notes/test-attestor",
          "publicKeys": [
            {
              "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
              "pkixPublicKey": {
                "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
                "signatureAlgorithm": "ECDSA_P256_SHA256"
              }
            }
          ],
          "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
        },
        "updateTime": "2019-06-26T16:58:33.977438Z"
      }
      
    4. Em um editor de texto, crie um arquivo JSON em /tmp/attestation.json que descreva o atestado:

      cat > /tmp/attestation.json << EOM
      {
        "resourceUri": "${IMAGE_TO_ATTEST}",
        "note_name": "${NOTE_URI}",
        "attestation": {
           "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
           "signatures": [
               {
                   "public_key_id": "KEY_ID",
                   "signature": "$(base64 --wrap=0 /tmp/generated_payload.json.sig)"
               }
           ]
        }
      
      }
      EOM
      

      em que KEY_ID é o ID da chave pública retornado na etapa anterior.

    5. Crie o atestado:

      curl -X POST \
          -H "Content-Type: application/json" \
          -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
          -H "Authorization: Bearer $(gcloud auth print-access-token)" \
          --data-binary @/tmp/attestation.json \
      "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
      

Verificar se o atestado foi criado

Para verificar se o atestado foi criado:

gcloud

Digite o seguinte na linha de comando:

gcloud container binauthz attestations list \
    --project="${ATTESTATION_PROJECT_ID}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}"

REST

Recupere uma lista de atestados:

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences?filter=kind%3D%22ATTESTATION%22"

Se houver muitos atestados, um nextPageToken poderá ser retornado na resposta. Nesse caso, a solicitação deve ser repetida, mas com o parâmetro de consulta pageToken definido como esse valor nextPageToken para buscar mais atestados. Quando nextPageToken está vazio, isso significa que não há mais resultados.

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/?filter=kind%3D%22ATTESTATION%22&pageToken=${NEXT_PAGE_TOKEN}"

A seguir