Verifica delle firme delle risorse utente immagine e non immagine

Mantenere l'integrità delle immagini create nella pipeline CI (Continuous Integration) prima della distribuzione verificando le firme delle immagini.

Prima di iniziare

Prima di iniziare a utilizzare la verifica tramite immagine, assicurati di soddisfare i seguenti requisiti.

  • È necessario disporre della chiave pubblica GPG. Per un aiuto sulla creazione della tua chiave GPG, consulta la documentazione.
  • È necessario aggiungere la variabile di ambiente code-signing-certificate con la chiave pubblica GPG codificata in base 64.
  • È necessario configurare le credenziali del registro per accedere alle immagini dei container durante la verifica (vedere Configurazione delle credenziali del registro ).

Verifica delle immagini

Una nuova fase prod-verify-artifact verifica la firma di un'immagine nella pipeline Continuous Delivery (CD). Questa fase esegue le seguenti operazioni:

  1. Decodifica la chiave pubblica GPG codificata fornita dall'utente in un file temporaneo.

  2. Crea una politica del contenitore Docker (/etc/containers/policy.json) con chiave pubblica.

     {
       "default": [
         {
           "type": "reject"
         }
       ],
       "transports": {
         "docker-daemon": {
           "": [
             {
               "type": "reject"
             }
           ]
         },
         "docker": {
           "": [
             {
               "type": "signedBy",
               "keyType": "GPGKeys",
               "keyPath": "/tmp/GPGPublicKey"
             }
           ]
         }
       }
     }
    
  3. Richiama l'elenco di risorse utente per ogni risorsa utente utilizzando Skopeo per eseguire il pull dell'immagine con la politica del contenitore.

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

Se la firma è valida e verificata dalla chiave pubblica fornita dall'utente, il pull dell'immagine ha esito positivo.

Configurazione delle credenziali del registro per la verifica

Per verificare le firme delle immagini dei container, la pipeline necessita delle credenziali necessarie per autenticarsi nel registro dei container e accedere alle immagini firmate. Il pipeline " DevSecOps " supporta la risoluzione dinamica delle credenziali in fase di esecuzione, consentendo di configurare le credenziali in diversi modi con meccanismi di fallback automatici.

Gerarchia di risoluzione delle credenziali

La pipeline risolve dinamicamente sia le credenziali del nome utente che quelle della chiave API in fase di esecuzione, utilizzando la seguente gerarchia:

Ordine di risoluzione delle chiavi API:

  1. Chiave API specifica per lo spazio dei nomi: signing-token-apikey-{registry}-{namespace} (segreto)
  2. Chiave API specifica del registro: signing-token-apikey-{registry} (segreta)
  3. Docker file di configurazione JSON: signing-dockerconfigjson (segreto)
  4. Soluzioni alternative specifiche per ICR:
    • ciso-ibmcloud-api-key (segreto)
    • ibmcloud-api-key (segreto)

Ordine di risoluzione dei nomi utente:

  1. Nome utente specifico dello spazio dei nomi: signing-token-username-{registry}-{namespace} (variabile d'ambiente)
  2. Nome utente specifico del Registro di sistema: signing-token-username-{registry} (variabile d'ambiente)
  3. Impostazione predefinita: iamapikey (se non è stato configurato alcun nome utente)

Dove:

  • {registry} è il nome host del registro (ad es., us.icr.io, de.icr.io)
  • {namespace} è il percorso completo dello spazio dei nomi con le barre e i punti sostituiti da trattini bassi (ad es., my_namespace_path)

Configurazione delle credenziali specifiche per lo spazio dei nomi

Per un controllo degli accessi più dettagliato, è possibile configurare credenziali specifiche per uno spazio dei nomi del registro:

Chiave API (segreta): signing-token-apikey-{registry}-{namespace}

Nome utente (variabile d'ambiente): signing-token-username-{registry}-{namespace}

Esempio: per un'immagine us.icr.io/my-namespace/my-app:latest

  • Registro: us.icr.io
  • Namespace: my-namespace
  • Codice segreto della chiave API: signing-token-apikey-us.icr.io-my_namespace
  • Variabile d'ambiente "username": signing-token-username-us.icr.io-my_namespace
  • Se il nome utente non viene specificato, il valore predefinito è: iamapikey

Configurazione delle credenziali specifiche del registro

Per un accesso più ampio a tutti gli spazi dei nomi in un registro:

Chiave API (segreta): signing-token-apikey-{registry}

Nome utente (variabile d'ambiente): signing-token-username-{registry}

Esempio: Per qualsiasi immagine in us.icr.io

  • Codice segreto della chiave API: signing-token-apikey-us.icr.io
  • Variabile d'ambiente "username": signing-token-username-us.icr.io
  • Se il nome utente non viene specificato, il valore predefinito è: iamapikey

Configurazione del file JSON di configurazione di Docker

È possibile fornire un file JSON di configurazione base64-encoded Docker contenente le credenziali per più registri:

Nome segreto: signing-dockerconfigjson

Formato: Base64-encoded JSON conforme al formato config.json di Docker:

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

La pipeline individua innanzitutto il percorso più specifico, consentendo di sovrascrivere le impostazioni a livello di namespace all'interno della configurazione di Docker.

Configurazione di esempio

Per un'immagine us.icr.io/production/my-app:v1.0.0:

Opzione 1: specifica per namespace (consigliata per l'ambiente di produzione)

  • Codice segreto della chiave API: signing-token-apikey-us.icr.io-production = your-namespace-api-key
  • Variabile d'ambiente "username" (facoltativa): signing-token-username-us.icr.io-production = iamapikey
  • Se il nome utente non viene specificato, il valore predefinito è iamapikey

Opzione 2: A livello di registro

  • Codice segreto della chiave API: signing-token-apikey-us.icr.io = your-registry-api-key
  • Variabile d'ambiente "username" (facoltativa): signing-token-username-us.icr.io = iamapikey
  • Se il nome utente non viene specificato, il valore predefinito è iamapikey

Opzione 3: file JSON di configurazione di Docker

  • Segreto: signing-dockerconfigjson = base64-encoded-docker-config
  • Il nome utente viene estratto dal file JSON di configurazione Docker

Opzione 4: impostazione predefinita " IBM Cloud " (automatica per ICR)

  • Codice segreto della chiave API: ibmcloud-api-key = your-ibmcloud-api-key
  • Il nome utente predefinito è iamapikey

Verifica delle risorse utente non immagine

Nelle pipeline di DevSecOps, la firma degli artefatti firmati è soggetta a verifica. Questa sezione descrive i prerequisiti che gli utenti devono soddisfare prima di procedere con la verifica della risorsa utente.

Prima di iniziare

Prima di poter gestire la verifica dell'immagine, assicurati di avere i seguenti prerequisiti.

  1. Modificare la configurazione della pipeline per abilitare il processo di verifica. Aggiungi il seguente frammento di codice al tuo file .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. Scaricare la risorsa utente e memorizzarla nel runtime della pipeline.

    Prima di richiamare la fase verify-artifact, scaricare e archiviare le risorse utente richieste nel runtime Cocoa. Per impostazione predefinita, tutti gli artefatti elencati nella raccolta " list_artifacts " vengono verificati. Utilizza la proprietà di testo " skip-sign-artifact-type " per escludere la verifica della firma delle immagini per i tipi di artefatti specificati (ad es.: log; report; documentazione). Il codice di esempio riportato di seguito mostra come scaricare un artefatto da Cloud Object Storage e salvarlo nel runtime 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
    

Verifica delle risorse utente

Nel processo di verifica della risorsa utente, la chiave pubblica GPG fornita dall'utente viene importata nel keyring GPG. Tutte le risorse utente elencate nella raccolta list_artifacts verranno verificate. La fase tenta di richiamare la firma dall'inventario ed esegue la seguente verifica:

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

Se la firma è valida e verificata utilizzando la chiave pubblica fornita, la fase registrerà la prova e contrassegnerà la fase come riuscita.