Verificando assinaturas de artefato de imagem e não imagem

Mantenha a integridade de imagens que são construídas no pipeline de Integração Contínua (CI) antes da implementação, verificando as assinaturas de imagem

Antes de Iniciar

Antes de começar a trabalhar com a verificação por imagem, certifique-se de que cumpre os seguintes pré-requisitos.

  • Você deve ter a chave pública GPG. Para obter ajuda na geração de sua chave GPG, consulte a documentação
  • Deve-se incluir a variável de ambiente code-signing-certificate com a chave pública GPG codificada em base 64.
  • É necessário configurar as credenciais do registro para acessar imagens de contêiner durante a verificação (consulte Configurando credenciais do registro ).

Verificando imagens

Um novo estágio prod-verify-artifact verifica a assinatura de uma imagem no pipeline do Continuous Delivery (CD) Esse estágio executa as seguintes etapas:

  1. Decodifica a chave pública GPG fornecida pelo usuário em um arquivo temporário.

  2. Cria uma política de contêiner Docker (/etc/containers/policy.json) com a chave pública.

     {
       "default": [
         {
           "type": "reject"
         }
       ],
       "transports": {
         "docker-daemon": {
           "": [
             {
               "type": "reject"
             }
           ]
         },
         "docker": {
           "": [
             {
               "type": "signedBy",
               "keyType": "GPGKeys",
               "keyPath": "/tmp/GPGPublicKey"
             }
           ]
         }
       }
     }
    
  3. Recupera a lista de artefatos para cada artefato usando Skopeo para fazer pull da imagem com a política de contêiner

        skopeo copy docker://"${image}" dir:"${tmp_sign_dir}" --src-creds iamapikey:"${ibmcloud_api_key}"
    

Se a assinatura for válida e verificada pela chave pública fornecida pelo usuário, a extração de imagem será bem-sucedida.

Configurando credenciais do Registro para verificação

Ao verificar as assinaturas das imagens de contêiner, o pipeline precisa de credenciais para se autenticar no registro de contêineres e acessar as imagens assinadas. O pipeline do DevSecOps oferece suporte à resolução dinâmica de credenciais em tempo de execução, permitindo que você configure credenciais de várias maneiras com mecanismos automáticos de fallback.

Hierarquia de resolução de credenciais

O pipeline resolve dinamicamente as credenciais de nome de usuário e chave de API em tempo de execução, utilizando a seguinte hierarquia:

Ordem de resolução da chave da API:

  1. Chave de API específica do namespace: signing-token-apikey-{registry}-{namespace} (segredo)
  2. Chave de API específica do registro: signing-token-apikey-{registry} (segredo)
  3. Docker Arquivo de configuração JSON: signing-dockerconfigjson (segredo)
  4. Soluções alternativas específicas para ICR:
    • ciso-ibmcloud-api-key (segredo)
    • ibmcloud-api-key (segredo)

Ordem de resolução de nomes de usuário:

  1. Nome de usuário específico do namespace: signing-token-username-{registry}-{namespace} (variável de ambiente)
  2. Nome de usuário específico do Registro: signing-token-username-{registry} (variável de ambiente)
  3. Padrão: iamapikey (se nenhum nome de usuário estiver configurado)

Em que:

  • {registry} é o nome de host do registro (por exemplo, us.icr.io, de.icr.io)
  • {namespace} é o caminho completo do namespace, com barras e pontos substituídos por sublinhados (por exemplo, my_namespace_path)

Configurando credenciais específicas do namespace

Para um controle de acesso mais detalhado, é possível configurar credenciais específicas para um namespace do registro:

Chave da API (Segredo): signing-token-apikey-{registry}-{namespace}

Nome de usuário (variável de ambiente): signing-token-username-{registry}-{namespace}

Exemplo: Para a imagem us.icr.io/my-namespace/my-app:latest

  • Registro: us.icr.io
  • Espaço de nomes: my-namespace
  • Chave secreta da API: signing-token-apikey-us.icr.io-my_namespace
  • Variável de ambiente "username": signing-token-username-us.icr.io-my_namespace
  • Se o nome de usuário não for fornecido, o padrão será: iamapikey

Configurando credenciais específicas do registro

Para obter acesso mais amplo a todos os espaços de nomes em um registro:

Chave da API (Segredo): signing-token-apikey-{registry}

Nome de usuário (variável de ambiente): signing-token-username-{registry}

Exemplo: Para qualquer imagem em us.icr.io

  • Chave secreta da API: signing-token-apikey-us.icr.io
  • Variável de ambiente "username": signing-token-username-us.icr.io
  • Se o nome de usuário não for fornecido, o padrão será: iamapikey

Configurando o arquivo JSON de configuração d Docker

Você pode fornecer um arquivo JSON de configuração do tipo base64-encoded Docker que contenha credenciais para vários registros:

Nome secreto: signing-dockerconfigjson

Formato: Base64-encoded JSON compatível com o formato config.json do site Docker:

{
  "auths": {
    "us.icr.io": {
      "username": "iamapikey",
      "password": "your-api-key"
    },
    "us.icr.io/my-namespace": {
      "username": "iamapikey",
      "password": "namespace-specific-key"
    }
  }
}

O pipeline corresponde primeiro ao caminho mais específico, permitindo substituições no nível do namespace dentro da configuração do Docker.

Configuração de exemplo

Para ver uma imagem us.icr.io/production/my-app:v1.0.0:

Opção 1: Específico do namespace (recomendado para produção)

  • Chave secreta da API: signing-token-apikey-us.icr.io-production = your-namespace-api-key
  • Variável de ambiente de nome de usuário (opcional): signing-token-username-us.icr.io-production = iamapikey
  • Se o nome de usuário não for especificado, o padrão será iamapikey

Opção 2: Em todo o Registro

  • Chave secreta da API: signing-token-apikey-us.icr.io = your-registry-api-key
  • Variável de ambiente de nome de usuário (opcional): signing-token-username-us.icr.io = iamapikey
  • Se o nome de usuário não for especificado, o padrão será iamapikey

Opção 3: Arquivo JSON de configuração do Docker

  • Segredo: signing-dockerconfigjson = base64-encoded-docker-config
  • O nome de usuário é extraído do arquivo JSON de configuração Docker

Opção 4: Padrão do IBM Cloud (automático para ICR)

  • Chave secreta da API: ibmcloud-api-key = your-ibmcloud-api-key
  • O nome de usuário padrão é iamapikey

Verificando artefatos sem imagem

Nos pipelines do DevSecOps, a assinatura dos artefatos assinados está sujeita a verificação. Esta seção descreve os pré-requisitos que os usuários devem atender antes de prosseguir com a verificação de artefato

Antes de Iniciar

Antes de poder trabalhar com a verificação de imagem, certifique-se de ter os pré-requisitos a seguir.

  1. Modifique a configuração de seu pipeline para ativar o processo de verificação Adicione o seguinte trecho de código ao seu arquivo .pipeline-config.yaml .

    verify-artifact:
      image: icr.io/continuous-delivery/pipeline/image-signing:1.0.0@sha256:e9d8e354668ba3d40be2aaee08298d2aa7f0e1c8a1829cca4094ec93830e3e6a
      image_pull_policy: IfNotPresent
      abort_on_failure: false
      dind: true
      script: |
        #!/usr/bin/env bash
        source /opt/commons/verify-artifact/verify_non_image_artifact.sh
    
  2. Faça download do artefato e o armazene no tempo de execução do pipeline.

    Antes de chamar o estágio verify-artifact, fazer download e armazenar os artefatos necessários no tempo de execução do Cocoa. Por padrão, todos os artefatos listados na coleção list_artifacts são verificados. Use a propriedade de texto " skip-sign-artifact-type " para ignorar a verificação da assinatura da imagem para os tipos de artefato especificados (por exemplo: log; relatório; documentação). O código de exemplo a seguir demonstra como baixar um artefato do site Cloud Object Storage e salvá-lo no ambiente de execução do Cocoa:

    #!/usr/bin/env bash
    
    export SECRET_PATH="/config/ibmcloud-api-key"
    . "${ONE_PIPELINE_PATH}"/iam/get_token
    
    SKIP_SIGN_ARTIFACTS_TYPE="$(get_env skip-sign-artifact-type "")"
    IFS=';' read -ra ARTIFACT_LIST <<<"$SKIP_SIGN_ARTIFACTS_TYPE"
    
    list_artifacts | while IFS= read -r artifact; do
    
       type="$(load_artifact "$artifact" "type")"
    
       if [[ ! "${ARTIFACT_LIST[@]}" =~ "$type" ]] && [[ "$type" != "image" ]]; then
    
          inventory_entry="$(load_artifact "$artifact" "inventory-entry")"
          inventory_entry=${inventory_entry///artifacts/$WORKSPACE}
          artifact_url=$(jq -r .'app_artifacts.artifact_url' ${inventory_entry})
          echo "downloading the artifact  ${artifact_url}"
          curl -H "Authorization: bearer ${IAM_ACCESS_TOKEN}" --output outputfile ${artifact_url}
          save_file "${artifact}" outputfile
    
       fi
    done
    

Verificando artefatos

No processo de verificação de artefato, a chave pública GPG fornecida pelo usuário é importada para o conjunto de chaves GPG. Todos os artefatos listados na coleção do list_artifacts serão verificados O estágio tenta recuperar a assinatura do inventário e executa a verificação a seguir:

gpg --verify  "${signature}" "${artifactName}"

Se a assinatura for válida e verificada usando a chave pública fornecida, o estágio registrará a evidência e marcará o estágio como bem-sucedido..