Vérification des signatures d'artefact d'image et non-image

Conservez l'intégrité des images qui sont générées dans le pipeline d'intégration continue (CI) avant le déploiement en vérifiant les signatures d'image.

Avant de commencer

Avant de commencer à utiliser la vérification par image, assurez-vous que les conditions préalables suivantes sont remplies.

  • Vous devez disposer de la clé publique GPG. Pour obtenir de l'aide sur la génération de votre clé GPG, voir la documentation.
  • Vous devez ajouter la variable d'environnement code-signing-certificate avec la clé publique GPG codée en base 64.
  • Vous devez configurer les identifiants du registre pour pouvoir accéder aux images de conteneurs pendant la vérification (voir « Configuration des identifiants du registre »).

Vérification des images

Une nouvelle étape prod-verify-artifact vérifie la signature d'une image dans le pipeline Continuous Delivery (CD). Cette étape effectue les étapes suivantes:

  1. Décode la clé publique GPG codée fournie par l'utilisateur dans un fichier temporaire.

  2. Crée une règle de conteneur Docker (/etc/containers/policy.json) avec la clé publique.

     {
       "default": [
         {
           "type": "reject"
         }
       ],
       "transports": {
         "docker-daemon": {
           "": [
             {
               "type": "reject"
             }
           ]
         },
         "docker": {
           "": [
             {
               "type": "signedBy",
               "keyType": "GPGKeys",
               "keyPath": "/tmp/GPGPublicKey"
             }
           ]
         }
       }
     }
    
  3. Extrait la liste des artefacts pour chaque artefact à l'aide de Skopeo pour extraire l'image avec la règle de conteneur.

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

Si la signature est valide et vérifiée par la clé publique fournie par l'utilisateur, l'extraction d'image aboutit.

Configuration des informations d'identification du registre pour la vérification

Lors de la vérification des signatures des images de conteneurs, le pipeline a besoin d'identifiants pour s'authentifier auprès du registre de conteneurs et accéder aux images signées. Le pipeline « DevSecOps » prend en charge la résolution dynamique des identifiants lors de l'exécution, ce qui vous permet de configurer ces identifiants de différentes manières grâce à des mécanismes de repli automatiques.

Hiérarchie de résolution des informations d'identification

Le pipeline résout dynamiquement les identifiants (nom d'utilisateur et clé API) au moment de l'exécution en suivant la hiérarchie suivante :

Ordre de résolution des clés API :

  1. Clé API spécifique à l'espace de noms: signing-token-apikey-{registry}-{namespace} (secret)
  2. Clé API spécifique au registre: signing-token-apikey-{registry} (secret)
  3. Docker Fichier de configuration JSON: signing-dockerconfigjson (secret)
  4. Solutions de secours spécifiques à l'ICR:
    • ciso-ibmcloud-api-key (secret)
    • ibmcloud-api-key (secret)

Ordre de résolution des noms d'utilisateur :

  1. Nom d'utilisateur spécifique à l'espace de noms: signing-token-username-{registry}-{namespace} (variable d'environnement)
  2. Nom d'utilisateur spécifique au registre: signing-token-username-{registry} (variable d'environnement)
  3. Par défaut: iamapikey (si aucun nom d'utilisateur n'est configuré)

Où :

  • {registry} est le nom d'hôte du registre (par exemple, us.icr.io, de.icr.io)
  • {namespace} correspond au chemin d'accès complet de l'espace de noms, dans lequel les barres obliques et les points ont été remplacés par des traits de soulignement (par exemple, my_namespace_path)

Configuration des identifiants spécifiques à un espace de noms

Pour un contrôle d'accès plus précis, vous pouvez configurer des identifiants spécifiques à un espace de noms du registre :

Clé API (secret): signing-token-apikey-{registry}-{namespace}

Nom d'utilisateur (variable d'environnement): signing-token-username-{registry}-{namespace}

Exemple: pour une image us.icr.io/my-namespace/my-app:latest

  • Registre : us.icr.io
  • Espace de noms : my-namespace
  • Clé secrète de l'API : signing-token-apikey-us.icr.io-my_namespace
  • Variable d'environnement « nom d'utilisateur » : signing-token-username-us.icr.io-my_namespace
  • Si le nom d'utilisateur n'est pas indiqué, la valeur par défaut est : iamapikey

Configuration des informations d'identification spécifiques au registre

Pour un accès plus large à l'ensemble des espaces de noms d'un registre :

Clé API (secret): signing-token-apikey-{registry}

Nom d'utilisateur (variable d'environnement): signing-token-username-{registry}

Exemple: pour toute image dans us.icr.io

  • Clé secrète de l'API : signing-token-apikey-us.icr.io
  • Variable d'environnement « nom d'utilisateur » : signing-token-username-us.icr.io
  • Si le nom d'utilisateur n'est pas indiqué, la valeur par défaut est : iamapikey

Configuration du fichier JSON de configuration d' Docker

Vous pouvez fournir un fichier de configuration JSON de type base64-encoded Docker contenant les identifiants d'accès pour plusieurs registres :

Nom secret: signing-dockerconfigjson

Format: Base64-encoded JSON, conforme au format config.json de Docker:

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

Le pipeline correspond d'abord au chemin le plus spécifique, ce qui permet des remplacements au niveau de l'espace de noms dans la configuration d' Docker.

Exemple de configuration

Pour une image us.icr.io/production/my-app:v1.0.0:

Option 1 : spécifique à l'espace de noms (recommandée pour la production)

  • Clé secrète de l'API : signing-token-apikey-us.icr.io-production = your-namespace-api-key
  • Variable d'environnement « username » (facultative): signing-token-username-us.icr.io-production = iamapikey
  • Si le nom d'utilisateur n'est pas indiqué, la valeur par défaut est iamapikey

Option 2 : À l'échelle du registre

  • Clé secrète de l'API : signing-token-apikey-us.icr.io = your-registry-api-key
  • Variable d'environnement « username » (facultative): signing-token-username-us.icr.io = iamapikey
  • Si le nom d'utilisateur n'est pas indiqué, la valeur par défaut est iamapikey

Option 3 : Fichier de configuration JSON d' Docker

  • Secret : signing-dockerconfigjson = base64-encoded-docker-config
  • Le nom d'utilisateur est extrait du fichier de configuration JSON situé à l'adresse Docker

Option 4 : valeur par défaut de « IBM Cloud » (automatique pour ICR)

  • Clé secrète de l'API : ibmcloud-api-key = your-ibmcloud-api-key
  • Le nom d'utilisateur par défaut est iamapikey

Vérification des artefacts autres que des images

Dans les pipelines d' DevSecOps, la signature des artefacts signés fait l'objet d'une vérification. Cette section décrit les prérequis que les utilisateurs doivent respecter avant de procéder à la vérification des artefacts.

Avant de commencer

Avant de pouvoir utiliser la vérification d'image, vérifiez que vous disposez des prérequis suivants.

  1. Modifiez la configuration de votre pipeline pour activer le processus de vérification. Ajoutez l'extrait de code suivant à votre fichier .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. Téléchargez l'artefact et stockez-le dans l'environnement d'exécution du pipeline.

    Avant d'appeler l'étape verify-artifact, téléchargez et stockez les artefacts requis dans l'environnement d'exécution Cocoa. Par défaut, tous les artefacts répertoriés dans la collection « list_artifacts » sont vérifiés. Utilisez la propriété de texte « skip-sign-artifact-type » pour ignorer la vérification de la signature des images pour les types d'artefacts indiqués (par exemple : log; report; documentation). L'exemple de code suivant montre comment télécharger un artefact depuis Cloud Object Storage et l'enregistrer dans l'environnement d'exécution 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
    

Vérification des artefacts

Dans le processus de vérification d'artefact, la clé publique GPG fournie par l'utilisateur est importée dans le fichier de clés GPG. Tous les artefacts répertoriés dans la collection list_artifacts seront vérifiés. L'étape tente d'extraire la signature de l'inventaire et effectue la vérification suivante:

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

Si la signature est valide et vérifiée à l'aide de la clé publique fournie, l'étape enregistre les preuves et marque l'étape comme réussie.