Compartilhar via


Assinar imagens de contêiner usando o Notation, o Azure Key Vault e um certificado autoassinado

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.

Assinar imagens de contêiner é um processo que ajuda a garantir sua autenticidade e integridade. Uma assinatura digital adicionada a uma imagem de contêiner é verificada durante a implantação. A assinatura ajuda a verificar se a imagem é de um editor confiável e não é modificada.

Este artigo discute as seguintes ferramentas envolvidas no processo de assinatura:

  • Notação é uma ferramenta de segurança de cadeia de suprimentos de software livre desenvolvida pela comunidade do Notary Project e apoiada pela Microsoft. Ele dá suporte à assinatura e verificação de imagens de contêiner e outros artefatos.

    Se você quiser assinar uma imagem de contêiner usando o Notation em pipelines de CI/CD (integração contínua e entrega contínua), siga as diretrizes do Azure Pipelines ou do GitHub Actions.

  • O Azure Key Vault é um serviço para armazenar certificados com chaves de assinatura. O Notation pode usar essas chaves pelo plug-in do Key Vault (notation-azure-kv) para assinar e verificar imagens de contêiner e outros artefatos.

  • O Registro de Contêiner do Azure é um registro privado que você pode usar para anexar assinaturas a imagens de contêiner e outros artefatos, juntamente com a exibição dessas assinaturas.

Neste artigo, você aprenderá a:

  • Instale a CLI (interface de linha de comando) do Notation e o plug-in do Key Vault.
  • Crie um certificado autoassinado no Key Vault.
  • Crie e envie por push uma imagem de contêiner usando tarefas do Registro de Contêiner.
  • Assine uma imagem de contêiner usando a CLI do Notation e o plug-in do Key Vault.
  • Valide uma imagem de contêiner contra a assinatura utilizando a Notation CLI.
  • Use marcação de data/hora.

Pré-requisitos

Instalar a CLI do Notation e o plug-in do Key Vault

  1. Instale o Notation v1.3.2 em um ambiente AMD64 do Linux. Para baixar o pacote para outros ambientes, siga o guia de instalação do Notation.

    # Download, extract, and install
    curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.3.2/notation_1.3.2_linux_amd64.tar.gz
    tar xvzf notation.tar.gz
    
    # Copy the Notation binary to the desired bin directory in $PATH, for example
    cp ./notation /usr/local/bin
    
  2. Instale o plug-in do Key Vault (notation-azure-kv) v1.2.1 em um ambiente AMD64 do Linux.

    Observação

    Você pode encontrar a URL e a soma de verificação SHA256 para o plug-in na página de lançamento do plug-in.

    notation plugin install --url https://github.com/Azure/notation-azure-kv/releases/download/v1.2.1/notation-azure-kv_1.2.1_linux_amd64.tar.gz --sha256sum 67c5ccaaf28dd44d2b6572684d84e344a02c2258af1d65ead3910b3156d3eaf5
    
  3. Liste os plug-ins disponíveis e confirme se o notation-azure-kv plug-in com a versão 1.2.1 está incluído na lista:

    notation plugin ls
    

Configurar variáveis de ambiente

Para facilitar a execução de comandos neste artigo, forneça valores para que os recursos do Azure correspondam aos recursos existentes do Registro de Contêiner e do Key Vault.

  1. Configurar nomes de recursos do Key Vault:

    AKV_SUB_ID=myAkvSubscriptionId
    AKV_RG=myAkvResourceGroup
    # Name of the existing key vault used to store the signing keys
    AKV_NAME=myakv
    # Name of the certificate created in the key vault
    CERT_NAME=wabbit-networks-io
    CERT_SUBJECT="CN=wabbit-networks.io,O=Notation,L=Seattle,ST=WA,C=US"
    CERT_PATH=./${CERT_NAME}.pem
    
  2. Configurar o Registro de Contêiner e os nomes de recursos de imagem:

    ACR_SUB_ID=myAcrSubscriptionId
    ACR_RG=myAcrResourceGroup
    # Name of the existing registry (example: myregistry.azurecr.io)
    ACR_NAME=myregistry
    # Existing full domain of the container registry
    REGISTRY=$ACR_NAME.azurecr.io
    # Container name inside the container registry where the image will be stored
    REPO=net-monitor
    TAG=v1
    IMAGE=$REGISTRY/${REPO}:$TAG
    # Source code directory that contains the Dockerfile to build
    IMAGE_SOURCE=https://github.com/wabbit-networks/net-monitor.git#main
    

Entre usando a CLI do Azure

az login

Para obter mais informações, consulte Autenticar no Azure usando a CLI do Azure.

Conceder permissões de acesso ao Registro de Contêiner e ao Key Vault

Quando você está trabalhando com o Registro de Contêiner e o Key Vault, é essencial conceder as permissões apropriadas para ajudar a garantir o acesso seguro e controlado. Você pode autorizar o acesso a várias entidades, como entidades de usuário, entidades de serviço ou identidades gerenciadas, dependendo de seus cenários específicos. Neste artigo, o acesso é autorizado para um usuário conectado do Azure.

Autorizar o acesso ao Registro de Contêiner

Para registros habilitados para o Microsoft Entra (controle de acesso baseado em atributo - ABAC), as funções Container Registry Repository Reader e Container Registry Repository Writer são necessárias para compilar e assinar imagens de contêiner no Registro de Contêiner.

Para registros não habilitados para ABAC, as funções AcrPull e AcrPush são necessárias.

Para obter mais informações sobre o ABAC, consulte o controle de acesso baseado em atributo do Microsoft Entra para obter permissões de repositório.

  1. Defina a assinatura que contém o recurso registro de contêiner:

    az account set --subscription $ACR_SUB_ID
    
  2. Atribua as funções. A função correta a ser usada na atribuição de função depende se o registro está habilitado ou não para ABAC.

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    ROLE1="Container Registry Repository Reader" # For ABAC-enabled registries. Otherwise, use "AcrPull" for non-ABAC-enabled registries.
    ROLE2="Container Registry Repository Writer" # For ABAC-enabled registries. Otherwise, use "AcrPush" for non-ABAC-enabled registries.
    az role assignment create --role "$ROLE1" --role "$ROLE2" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"
    

Autorizar o acesso ao Key Vault

Esta seção explora duas opções para autorizar o acesso ao Key Vault.

As seguintes funções são necessárias para assinatura usando certificados autoassinados:

  • Key Vault Certificates Officer para criar e ler certificados
  • Key Vault Certificates User para ler certificados existentes
  • Key Vault Crypto User para operações de assinatura

Para saber mais sobre o acesso ao Key Vault com o RBAC (controle de acesso baseado em função) do Azure, consulte Fornecer acesso a chaves, certificados e segredos do Key Vault usando o controle de acesso baseado em função do Azure.

  1. Defina a assinatura que contém o recurso do Key Vault:

    az account set --subscription $AKV_SUB_ID
    
  2. Atribua as funções:

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    az role assignment create --role "Key Vault Certificates Officer" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"
    

Atribuir uma política de acesso no Key Vault (herdado)

As seguintes permissões são necessárias para uma identidade:

  • Permissões Create para criar um certificado
  • Permissões Get para ler certificados existentes
  • Permissões Sign para operações de assinatura

Para saber mais sobre como atribuir uma política a um principal, consulte Atribuir uma política de acesso do Key Vault (herdada).

  1. Defina a assinatura que contém o recurso do Key Vault:

    az account set --subscription $AKV_SUB_ID
    
  2. Defina a política de acesso no Key Vault:

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    az keyvault set-policy -n $AKV_NAME --certificate-permissions create get --key-permissions sign --object-id $USER_ID
    

Importante

Este exemplo mostra as permissões mínimas necessárias para criar um certificado e assinar uma imagem de contêiner. Dependendo de seus requisitos, talvez seja necessário conceder mais permissões.

Criar um certificado autoassinado no Key Vault (CLI do Azure)

As etapas a seguir mostram como criar um certificado autoassinado para fins de teste:

  1. Criar um arquivo de política de certificação.

    Depois que o arquivo de política de certificado é executado por meio do código a seguir, ele cria um certificado válido compatível com os requisitos de certificado do Projeto de Notário no Key Vault. O valor de ekus é para assinatura de código, mas não é necessário que o Notation assine artefatos. O assunto é usado posteriormente como uma identidade confiável durante a verificação.

    cat <<EOF > ./my_policy.json
    {
        "issuerParameters": {
        "certificateTransparency": null,
        "name": "Self"
        },
        "keyProperties": {
          "exportable": false,
          "keySize": 2048,
          "keyType": "RSA",
          "reuseKey": true
        },
        "secretProperties": {
          "contentType": "application/x-pem-file"
        },
        "x509CertificateProperties": {
        "ekus": [
            "1.3.6.1.5.5.7.3.3"
        ],
        "keyUsage": [
            "digitalSignature"
        ],
        "subject": "$CERT_SUBJECT",
        "validityInMonths": 12
        }
    }
    EOF
    
  2. Crie o certificado:

    az keyvault certificate create -n $CERT_NAME --vault-name $AKV_NAME -p @my_policy.json
    

Assinar uma imagem de contêiner usando a CLI do Notation e plug-in do Key Vault

  1. Autentique-se no registro de contêiner usando sua identidade individual do Azure:

    az acr login --name $ACR_NAME
    

    Importante

    Se você tiver o Docker instalado em seu sistema e usou az acr login ou docker login para autenticar no registro de contêiner, suas credenciais já estarão armazenadas e disponíveis para Notation. Nesse caso, você não precisa executar notation login novamente para se autenticar no registro de contêineres. Para saber mais sobre as opções de autenticação para Notação, consulte Autenticar com registros em conformidade com OCI.

  2. Crie e envie por push uma nova imagem usando tarefas do Registro de Contêiner do Azure. Sempre use o valor do resumo para identificar a imagem a ser assinada, pois as marcas são mutáveis e podem ser substituídas.

    DIGEST=$(az acr build -r $ACR_NAME -t $REGISTRY/${REPO}:$TAG $IMAGE_SOURCE --no-logs --query "outputImages[0].digest" -o tsv)
    IMAGE=$REGISTRY/${REPO}@$DIGEST
    

    Neste artigo, se a imagem já estiver criada e estiver armazenada no registro de imagens, o tag servirá como um identificador para essa imagem por conveniência.

    IMAGE=$REGISTRY/${REPO}:$TAG
    
  3. Obtenha a ID da chave de assinatura. Um certificado no Key Vault pode ter várias versões. O comando a seguir obtém a ID da chave da versão mais recente:

    KEY_ID=$(az keyvault certificate show -n $CERT_NAME --vault-name $AKV_NAME --query 'kid' -o tsv)
    
  4. Assine a imagem de contêiner com o formato de assinatura Assinatura e Criptografia de Objetos CBOR (COSE), usando a ID da chave de assinatura. Para assinar com um certificado autoassinado, você precisa definir o valor de configuração self_signed=true do plug-in.

    notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config self_signed=true $IMAGE
    

    Para autenticar com o Key Vault, por padrão, os seguintes tipos de credencial (se habilitados) são tentados na ordem:

    Se você quiser especificar um tipo de credencial, use uma configuração de plug-in adicional chamada credential_type. Por exemplo, você pode definir explicitamente credential_type como azurecli para usar uma credencial da CLI do Azure, conforme demonstrado neste exemplo.

    notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config self_signed=true --plugin-config credential_type=azurecli $IMAGE
    

    A tabela a seguir mostra os valores de credential_type para vários tipos de credenciais.

    Tipo de credencial Valor para credential_type
    Credencial de ambiente environment
    Credencial de identidade de carga de trabalho workloadid
    Credencial de identidade gerenciada managedid
    Credencial da CLI do Azure azurecli

    Observação

    Desde a versão 1.2.0, o Notation usa o esquema de referência de tags OCI para armazenar a assinatura no Registro de Contêiner por padrão. Você também pode habilitar a API de Referenciadores OCI usando o sinalizador --force-referrers-tag false, se necessário. Os recursos do Registro de Contêiner dão suporte à API de Referenciadores OCI, exceto pelo registro criptografado por meio de CMKs (chaves gerenciadas pelo cliente).

  5. Exiba o grafo de imagens assinadas e assinaturas associadas:

    notation ls $IMAGE
    

Verifique uma imagem de contêiner usando o Notation CLI

Para verificar a imagem do contêiner, primeiro adicione o certificado raiz que assina o certificado intermediário ao repositório de confiança e, em seguida, crie políticas de confiança para a verificação. Para o certificado autoassinado que este artigo usa, o certificado raiz é o próprio certificado autoassinado.

  1. Baixe um certificado público:

    az keyvault certificate download --name $CERT_NAME --vault-name $AKV_NAME --file $CERT_PATH
    
  2. Adicione o certificado público baixado ao repositório de confiança nomeado para verificação de assinatura:

    STORE_TYPE="ca"
    STORE_NAME="wabbit-networks.io"
    notation cert add --type $STORE_TYPE --store $STORE_NAME $CERT_PATH
    
  3. Liste o certificado para confirmar:

    notation cert ls
    
  4. Configure uma política de confiança antes da verificação.

    As políticas de confiança permitem que os usuários especifiquem políticas de verificação ajustadas. O exemplo a seguir configura uma política de confiança chamada wabbit-networks-images. Essa política se aplica a todos os artefatos em $REGISTRY/$REPO e utiliza o repositório de confiança nomeado $STORE_NAME do tipo $STORE_TYPE. Ele também pressupõe que o usuário confia em uma identidade específica com o assunto X.509 $CERT_SUBJECT. Para obter mais informações, consulte o repositório de confiança e a especificação de política de confiança.

    cat <<EOF > ./trustpolicy.json
    {
        "version": "1.0",
        "trustPolicies": [
            {
                "name": "wabbit-networks-images",
                "registryScopes": [ "$REGISTRY/$REPO" ],
                "signatureVerification": {
                    "level" : "strict" 
                },
                "trustStores": [ "$STORE_TYPE:$STORE_NAME" ],
                "trustedIdentities": [
                    "x509.subject: $CERT_SUBJECT"
                ]
            }
        ]
    }
    EOF
    
  5. Use notation policy para importar a configuração de política de confiança do arquivo JSON que você criou anteriormente:

    notation policy import ./trustpolicy.json
    notation policy show
    
  6. Use notation verify para verificar se a imagem do contêiner não foi alterada após o tempo de build:

    notation verify $IMAGE
    

    Após a verificação bem-sucedida da imagem por meio da política de confiança, o resumo SHA256 da imagem verificada é retornado em uma mensagem de saída bem-sucedida.

Usar o carimbo de data/hora

Desde a versão Notation v1.2.0, o Notation dá suporte a timestamps compatíveis com RFC 3161. Esse aprimoramento estende a confiança nas assinaturas criadas dentro do período de validade do certificado por meio da confiança em uma autoridade de carimbo de data e hora (TSA). Essa confiança permite a verificação de assinatura bem-sucedida mesmo após a expiração dos certificados.

Como signatário de imagens, você deve garantir que assina imagens de contêiner com carimbos de data/hora gerados por uma TSA confiável. Como verificador de imagens, você deve garantir que confia tanto no signatário da imagem quanto na TSA associada e estabelecer confiança usando armazenamentos confiáveis e políticas de confiança.

O carimbo de data/hora reduz custos, eliminando a necessidade de assinar novamente as imagens periodicamente por causa do vencimento do certificado. Essa capacidade é especialmente crítica quando você usa certificados de curta duração. Para obter instruções detalhadas sobre como assinar e verificar imagens usando timestamp, consulte o guia de timestamp do Projeto Notary.

A notação fornece soluções de CI/CD no Azure Pipelines e no GitHub Actions:

Para garantir que apenas imagens de contêiner confiáveis sejam implantadas no AKS (Serviço de Kubernetes do Azure):