Assinar imagens de contêiner em fluxos de trabalho do GitHub usando Notation e Assinatura de Artefatos

Este artigo faz parte de uma série sobre como garantir a integridade e a autenticidade de imagens de contêiner e outros artefatos da OCI (Open Container Initiative). Para a imagem completa, comece com a visão geral, que explica por que a assinatura importa e descreve os vários cenários.

Neste artigo, você aprenderá a criar um fluxo de trabalho do GitHub Actions para:

  • Crie uma imagem e envie-a por push para o Registro de Contêiner do Azure.
  • Assine a imagem usando o GitHub Actions de Notação e a Assinatura de Artefato.
  • Armazene automaticamente a assinatura gerada no Registro de Contêiner.

Pré-requisitos

Autenticar do Azure para o GitHub

De acordo com o Uso do GitHub Actions para se conectar ao Azure, você deve se autenticar com o Azure em seu fluxo de trabalho usando a ação de Logon do Azure antes de executar comandos da CLI do Azure ou do Azure PowerShell. A ação de Logon do Azure dá suporte a vários métodos de autenticação.

Neste guia, você entra com o OpenID Connect (OIDC), usa uma identidade gerenciada atribuída pelo usuário e segue as etapas em Usar a ação de Logon do Azure com o OpenID Connect.

  1. Criar uma identidade gerenciada atribuída pelo usuário. Ignore esta etapa se você tiver uma identidade gerenciada existente.

    az login
    az identity create -g <identity-resource-group> -n <identity-name>
    

  1. Obtenha a ID de cliente da sua identidade gerenciada.

    CLIENT_ID=$(az identity show -g <identity-resource-group> -n <identity-name> --query clientId -o tsv)
    

  1. Atribua funções à identidade gerenciada para acessar o Registro de Contêiner do Azure.

    Para registros que não estão habilitados com controle de acesso baseado em atributos (ABAC), atribua as funções AcrPush e AcrPull.

    ACR_SCOPE=/subscriptions/<subscription-id>/resourceGroups/<acr-resource-group>
    az role assignment create --assignee $CLIENT_ID --scope $ACR_SCOPE --role "acrpush" --role "acrpull"
    

    Quanto aos registros habilitados para ABAC, atribua as funções Container Registry Repository Reader e Container Registry Repository Writer:

    ACR_SCOPE=/subscriptions/<subscription-id>/resourceGroups/<acr-resource-group>
    az role assignment create --assignee $CLIENT_ID --scope $ACR_SCOPE --role "Container Registry Repository Reader" --role "Container Registry Repository Writer"
    

  1. Atribua a função Artifact Signing Certificate Profile Signer à identidade gerenciada para acessar a Assinatura de Artefato:

    AS_SCOPE=/subscriptions/<subscription-id>/resourceGroups/<ts-account-resource-group>/providers/Microsoft.CodeSigning/codeSigningAccounts/<ts-account>/certificateProfiles/<ts-cert-profile>
    az role assignment create --assignee $CLIENT_ID --scope $AS_SCOPE --role "Artifact Signing Certificate Profile Signer"
    

  1. Configure o GitHub para confiar em sua identidade. Siga as instruções de Configuração de uma identidade gerenciada atribuída pelo usuário para confiar em um provedor de identidade externo.

  2. Crie segredos do GitHub seguindo as instruções para criar segredos para um repositório.

    Mapeie os valores de identidade gerenciada para esses segredos:

    Segredo do GitHub Valor da identidade gerenciada
    AZURE_CLIENT_ID ID do cliente
    AZURE_SUBSCRIPTION_ID ID da assinatura
    AZURE_TENANT_ID ID do diretório (locatário)

Armazenar o certificado raiz da TSA

O carimbo de data/hora (RFC 3161) estende a confiança para assinaturas além do período de validade do certificado de assinatura. A Assinatura de Artefato usa certificados de curta duração, portanto, o carimbo de data/hora é crítico. A URL do servidor para a autoridade de carimbo de data/hora (TSA) está disponível em http://timestamp.acs.microsoft.com/, conforme recomendado em Contra-atribuições de carimbo de data/hora.

  1. Baixe o certificado raiz da TSA:

    curl -o msft-tsa-root-certificate-authority-2020.crt "http://www.microsoft.com/pkiops/certs/microsoft%20identity%20verification%20root%20certificate%20authority%202020.crt"
    

  1. Armazene o certificado raiz em seu repositório; por exemplo, .github/certs/msft-identity-verification-root-cert-authority-2020.crt. Você usará o caminho do arquivo no fluxo de trabalho.

Criar o fluxo de trabalho do GitHub Actions

  1. Crie um .github/workflows diretório em seu repositório, se ele não existir.

  2. Criar um novo arquivo de fluxo de trabalho; por exemplo, .github/workflows/sign-with-artifact-signing.yml.

  3. Copie o seguinte modelo de fluxo de trabalho de assinatura em seu arquivo.

Expanda para exibir o modelo de fluxo de trabalho de assinatura.
# Build and push an image to Azure Container Registry, set up notation, and sign the image
name: notation-github-actions-sign-with-artifact-signing-template

on:
  push:

env:
  ACR_LOGIN_SERVER: <registry-login-server>             # example: myregistry.azurecr.io
  ACR_REPO_NAME: <repository-name>                      # example: myrepo
  IMAGE_TAG: <image-tag>                                # example: v1
  PLUGIN_NAME: azure-artifactsigning                     # name of Notation Artifact Signing plug-in; do not change
  PLUGIN_DOWNLOAD_URL: <plugin-download-url>            # example: "https://github.com/Azure/artifact-signing-notation-plugin/releases/download/v1.0.0/notation-azure-artifactsigning_1.0.0_linux_amd64.tar.gz"
  PLUGIN_CHECKSUM: <plugin-package-checksum>            # example: 2f45891a14aa9c88c9bee3d11a887c1adbe9d2d24e50de4bc4b4fa3fe595292f
  TSA_URL: "http://timestamp.acs.microsoft.com/"        # timestamping server URL
  TSA_ROOT_CERT: <root-cert-file-path>                  # example: .github/certs/msft-identity-verification-root-cert-authority-2020.crt
  AS_ACCOUNT_NAME: <artifact-signing-account-name>       # Artifact Signing account name
  AS_CERT_PROFILE: <artifact-signing-cert-profile-name>  # Artifact Signing certificate profile name 
  AS_ACCOUNT_URI: <artifact-signing-account-uri>         # Artifact Signing account URI; for example, "https://eus.codesigning.azure.net/"

jobs:
  notation-sign:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
     # packages: write
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: prepare
        id: prepare
        run: |
          echo "target_artifact_reference=${{ env.ACR_LOGIN_SERVER }}/${{ env.ACR_REPO_NAME }}:${{ env.IMAGE_TAG }}" >> "$GITHUB_ENV"
      
      # Log in to Azure with your service principal secret
      # - name: Azure login
      #  uses: Azure/login@v1
      #  with:
      #    creds: ${{ secrets.AZURE_CREDENTIALS }}
      # If you're using OIDC and federated credentials, make sure to replace the preceding step with the following:
      - name: Azure login
        uses: Azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      # Log in to your container registry
      - name: ACR login
        run: |
            az acr login --name ${{ env.ACR_LOGIN_SERVER }}
      # Build and push an image to the registry
      # Use `Dockerfile` as an example to build an image
      - name: Build and push
        id: push
        uses: docker/build-push-action@v4
        with:
          push: true
          tags: ${{ env.target_artifact_reference }}
          build-args: |
            IMAGE_TAG={{ env.IMAGE_TAG }}
      # Get the manifest digest of the OCI artifact
      - name: Retrieve digest
        run: |
          echo "target_artifact_reference=${{ env.ACR_LOGIN_SERVER }}/${{ env.ACR_REPO_NAME }}@${{ steps.push.outputs.digest }}" >> "$GITHUB_ENV" 
      # Set up the Notation CLI
      - name: setup notation
        uses: notaryproject/notation-action/setup@v1.2.2
      # Sign your container images and OCI artifacts by using a private key stored in Azure Key Vault
      - name: sign OCI artifacts with Artifact Signing
        uses: notaryproject/notation-action/sign@v1
        with:
          timestamp_url: ${{ env.TSA_URL}}
          timestamp_root_cert: ${{env.TSA_ROOT_CERT }}
          plugin_name: ${{ env.PLUGIN_NAME }}
          plugin_url: ${{ env.PLUGIN_DOWNLOAD_URL }}
          plugin_checksum: ${{ env.PLUGIN_CHECKSUM }}
          key_id: ${{ env.AS_CERT_PROFILE }}
          target_artifact_reference: ${{ env.target_artifact_reference }}
          signature_format: cose
          plugin_config: |-
            accountName=${{ env.AS_ACCOUNT_NAME }}
            baseUrl=${{ env.AS_ACCOUNT_URI }}
            certProfile=${{ env.AS_CERT_PROFILE }}
          force_referrers_tag: 'false'

Anotações sobre variáveis de ambiente:

  • PLUGIN_NAME: sempre use azure-artifactsigning.
  • PLUGIN_DOWNLOAD_URL: obtenha a URL da página de lançamento do plug-in de Assinatura de Artefato.
  • PLUGIN_CHECKSUM: use o arquivo de soma de verificação na página de versão; por exemplo, notation-azure-artifactsigning_<version>_checksums.txt.
  • AS_ACCOUNT_URI: use o ponto de extremidade da sua conta de Assinatura de Artefato, específico da sua região, por exemplo, https://eus.codesigning.azure.net/.

Acionar o fluxo de trabalho do GitHub Actions

A sintaxe on:push aciona o fluxo de trabalho de exemplo. Confirmar alterações inicia o fluxo de trabalho. No nome do repositório GitHub, selecione Ações para exibir os logs de fluxo de trabalho.

Se houver êxito, o fluxo de trabalho criará a imagem, enviará por push para o Registro de Contêiner do Azure e a assinará usando a Assinatura de Artefato. Você pode exibir os logs de fluxo de trabalho para confirmar se o azure-artifactsigning plug-in foi instalado e a imagem foi assinada com êxito.

Além disso, você pode abrir o registro de contêiner no portal do Azure. Vá para Repositórios, vá para sua imagem e selecione Referenciadores. Confirme se os artefatos (assinaturas) do tipo application/vnd.cncf.notary.signature estão listados.