Créer des attestations

Cette page explique comment créer une attestation dans l'autorisation binaire à partir de la ligne de commande.

Les instructions de cette page décrivent les étapes qu'un signataire doit effectuer pour autoriser le déploiement d'une image de conteneur. En situation réelle, vous intégrez ces étapes dans un script ou une automatisation pouvant être déclenché par un processus machine ou un utilisateur humain, plutôt que de les saisir manuellement en ligne de commande.

Présentation

Une attestation est un document signé numériquement, généré par un signataire, qui certifie qu'un processus requis dans votre pipeline est terminé et que l'image de conteneur obtenue est autorisée pour le déploiement dans GKE. L'attestation elle-même contient le chemin d'accès complet à la version de l'image de conteneur stockée dans votre registre d'images de conteneurs, ainsi qu'une signature créée en signant le condensé globalement unique qui identifie une compilation d'image de conteneur spécifique.

Vous pouvez créer une attestation à l'aide d'une signature PKIX (recommandée) ou PGP. Ce guide utilise le format d'infrastructure à clé publique X.509 (PKIX) pour les clés cryptographiques et utilise l'algorithme de signature numérique à courbe elliptique (ECDSA) recommandé pour signer et créer l'attestation. Vous pouvez également utiliser des clés RSA ou PGP pour la signature. Consultez la page Objectifs et algorithmes des clés pour plus d'informations sur les algorithmes de signature.

Définir le projet par défaut

Si vous n'avez pas encore défini votre projet Google Cloud par défaut, exécutez la commande suivante :

PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}

PROJECT_ID correspond au nom de votre projet.

Configurer l'environnement

  1. Configurez des variables d'environnement pour stocker vos ID de projet :

    ATTESTOR_PROJECT_ID=ATTESTOR_PROJECT_ID
    ATTESTATION_PROJECT_ID=ATTESTATION_PROJECT_ID
    

    Où :

    • ATTESTOR_PROJECT_ID correspond au nom du projet dans lequel vous stockez vos certificateurs ;
    • ATTESTATION_PROJECT_ID correspond au nom du projet dans lequel vous stockez vos attestations.

    Si votre projet pour les certificateurs est le même que votre projet pour les attestations, utilisez le même ID de projet pour les deux variables.

  2. Configurez des variables d'environnement pour stocker le nom du certificateur qui valide l'attestation et le chemin d'accès du registre à l'image que vous souhaitez déployer :

    ATTESTOR_NAME=ATTESTOR_NAME
    IMAGE_PATH=IMAGE_PATH
    IMAGE_DIGEST=IMAGE_DIGEST
    PUBLIC_KEY_ID=PUBLIC_KEY_ID
    PRIVATE_KEY_FILE=PRIVATE_KEY_FILE
    IMAGE_TO_ATTEST="${IMAGE_PATH}@${IMAGE_DIGEST}"
    

    Où :

    • ATTESTOR_NAME correspond au nom du certificateur (par exemple, build-secure ou prod-qa) ;
    • IMAGE_PATH correspond au chemin d'accès dans Container Registry vers l'image que vous souhaitez déployer (par exemple, gcr.io/example-project/quickstart-image) ;
    • PUBLIC_KEY_ID correspond à l'ID associé à la clé publique de la paire de clés générée. La clé publique est stockée dans le certificateur ;
    • PRIVATE_KEY_FILE correspond au fichier contenant la clé privée de la paire de clés que vous avez générée. La charge utile de l'attestation est signée avec cette clé ;
    • IMAGE_DIGEST correspond au condensé SHA-256 du fichier manifeste de l'image (par exemple, sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4). Pour plus d'informations sur l'obtention du condensé de l'image, consultez la section Répertorier les versions d'une image dans Container Registry.

Chaque image de conteneur stockée dans Container Registry ou un autre registre est accessible via un chemin d'accès unique. En outre, un condensé SHA-256 identifie de manière unique la version de l'image. Les attestations référencent le chemin d'accès complet de l'image et son condensé, ce qui vous permet d'autoriser des versions spécifiques d'une image.

Voici un exemple de chemin de registre complet :

gcr.io/example-project/quickstart-image@sha256:bedb3feb23e81d162e33976fd7b245adff00379f4755c0213e84405e5b1e0988

Créer une attestation avec une signature PKIX à l'aide d'une clé stockée localement

Pour les attestations signées avec une clé publique PKIX, vous devez procéder comme suit :

  1. Créer une charge utile d'attestation à envoyer à l'autorisation binaire, qui référence le chemin d'accès au registre.
  2. Signer la charge utile et générer un fichier de signature PKIX.
  3. Obtenir l'ID de clé publique.
  4. Créer l'attestation avec le fichier de signature et l'ID de clé publique.

Créer une charge utile d'attestation

La charge utile d'un certificat est un fichier au format JSON qui référence l'emplacement de l'image de conteneur.

Pour créer le fichier de charge utile :

gcloud

Saisissez ce qui suit :

gcloud container binauthz create-signature-payload \
    --artifact-url="${IMAGE_TO_ATTEST}" > /tmp/generated_payload.json

Le fichier de charge utile ressemble à ceci :

{
  "critical": {
    "identity": {
      "docker-reference": "gcr.io/google-samples/hello-app"
    },
    "image": {
      "docker-manifest-digest": "sha256:bedb3feb23e81d162e33976fd7b245
adff00379f4755c0213e84405e5b1e0988"
    },
    "type": "Google cloud binauthz container signature"
  }
}

REST

Créez un fichier de charge utile nommé /tmp/generated_payload.json à l'aide des variables d'environnement que vous avez définies ci-dessus :

cat > /tmp/generated_payload.json << EOM
{
  "critical": {
    "identity": {
      "docker-reference": "${IMAGE_PATH}"
    },
    "image": {
      "${IMAGE_DIGEST}"
    },
    "type": "Google cloud binauthz container signature"
  }
}
EOM

Signer le fichier de charge utile et générer un fichier de signature

Après avoir créé le fichier de charge utile, vous devez le signer à l'aide de la clé cryptographique privée de la paire de clés générée précédemment. Rappelez-vous que la clé publique correspondante a été stockée dans le certificateur associé. La clé publique de ce certificateur est utilisée pour vérifier cette signature au moment du déploiement.

Pour savoir comment créer un certificateur, consultez la page Créer des certificateurs à l'aide de la CLI ou Créer des certificateurs à l'aide de la console.

Pour obtenir un exemple de bout en bout incluant toutes ces étapes, consultez la page Premiers pas avec la CLI ou Premiers pas avec la console.

Pour signer le fichier de charge utile :

  1. Signez le fichier de charge utile à l'aide de votre clé privée PKIX locale et générez un fichier de signature :

    openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} /tmp/generated_payload.json > /tmp/ec_signature
    

    Le fichier de signature est une version signée numériquement du fichier JSON de charge utile que vous avez créé ci-dessus.

Obtenir l'ID de clé publique

Vous devez envoyer un ID de clé publique à l'autorisation binaire avec le fichier de signature lorsque vous créez une attestation.

Pour obtenir l'ID de clé publique :

  1. Enregistrez l'ID de clé publique.

    Pour afficher ultérieurement l'ID de clé publique de votre certificateur, utilisez la commande gcloud container binauthz attestors describe ${ATTESTOR_NAME} :

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
      --format='value(userOwnedGrafeasNote.publicKeys[0].id)')
    

Créer l'attestation

gcloud

Pour créer l'attestation, saisissez la commande suivante :

gcloud container binauthz attestations create \
    --project="${ATTESTATION_PROJECT_ID}" \
    --artifact-url="${IMAGE_TO_ATTEST}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
    --signature-file=/tmp/ec_signature \
    --public-key-id="${PUBLIC_KEY_ID}"

Vous pouvez également créer et valider la vérification de l'attestation par le certificateur fourni :

gcloud alpha container binauthz attestations create \
    --project="${ATTESTATION_PROJECT_ID}" \
    --artifact-url="${IMAGE_TO_ATTEST}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
    --signature-file=/tmp/ec_signature \
    --public-key-id="${PUBLIC_KEY_ID}" \
    --validate

Remarque : Le format de la chaîne de l'ID de clé est libre.

REST

Pour créer l'attestation, procédez comme suit :

  1. Récupérez le certificateur associé à l'attestation et extrayez l'ID de la clé publique stockée :

    curl \
        -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
        -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
        "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors/"
    

    L'autorisation binaire renvoie un objet JSON semblable à celui-ci :

    {
      "name": "projects/example-project/attestors/test-attestor",
      "userOwnedGrafeasNote": {
        "noteReference": "projects/example-project/notes/test-attestor",
        "publicKeys": [
          {
            "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
            "pkixPublicKey": {
              "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
              "signatureAlgorithm": "ECDSA_P256_SHA256"
            }
          }
        ],
        "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
      },
      "updateTime": "2019-06-26T16:58:33.977438Z"
    }
    
  2. Dans un éditeur de texte, créez un fichier JSON dans /tmp/attestation.json qui décrit l'attestation :

    cat > /tmp/attestation.json << EOM
    {
      "resourceUri": "${IMAGE_TO_ATTEST}",
      "note_name": "${NOTE_URI}",
      "attestation": {
         "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
         "signatures": [
            {
             "public_key_id": "KEY_ID",
             "signature": "$(base64 --wrap=0 /tmp/ec_signature)"
             }
         ]
      }
     }
    EOM
    

    KEY_ID correspond à l'ID de clé publique renvoyé à l'étape précédente.

  3. Créez l'attestation :

    curl -X POST \
        -H "Content-Type: application/json" \
        -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)" \
        --data-binary @/tmp/attestation.json \
        "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
    

Créer une attestation avec une signature PKIX basée sur Cloud Key Management Service

Pour créer une attestation avec une signature PKIX basée sur Cloud Key Management Service, procédez comme suit :

  1. Configurez des variables d'environnement pour stocker des informations sur les projets où sont stockés vos attestations, vos certificateurs et vos clés Cloud Key Management Service, ainsi que des informations sur votre paire de clés PKIX :

    KMS_KEY_PROJECT_ID=KMS_KEY_PROJECT_ID
    KMS_KEY_LOCATION=KMS_KEY_LOCATION
    KMS_KEYRING_NAME=KMS_KEYRING_NAME
    KMS_KEY_NAME=KMS_KEY_NAME
    KMS_KEY_VERSION=KMS_KEY_VERSION
    

    Où :

    • KMS_KEY_PROJECT_ID correspond à l'ID du projet dans lequel vos clés Cloud Key Management Service sont stockées ;
    • KMS_KEY_LOCATION correspond à l'emplacement de la clé (global est la valeur par défaut) ;
    • KMS_KEYRING_NAME correspond au nom du trousseau de clés ;
    • KMS_KEY_NAME correspond au nom de la clé ;
    • KMS_KEY_VERSION correspond à la version de clé.
  2. Signez et créez l'attestation :

    gcloud

    Saisissez ce qui suit dans la ligne de commande :

    gcloud beta container binauthz attestations sign-and-create \
        --project="${ATTESTATION_PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="${ATTESTOR_NAME}" \
        --attestor-project="${ATTESTOR_PROJECT_ID}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    

    REST

    1. Créez un fichier de charge utile nommé /tmp/generated_payload.json à l'aide des variables d'environnement que vous avez définies ci-dessus :

      cat > /tmp/generated_payload.json << EOM
      {
        "critical": {
          "identity": {
            "docker-reference": "${IMAGE_PATH}"
          },
          "image": {
            "${IMAGE_DIGEST}"
          },
          "type": "Google cloud binauthz container signature"
        }
      }
      EOM
      
    2. Signez le fichier de charge utile :

      gcloud --project="${KMS_KEY_PROJECT_ID}"  \
          alpha kms asymmetric-sign \
          --location="${KMS_KEY_LOCATION}" \
          --keyring="${KMS_KEYRING_NAME}" \
          --key="${KMS_KEY_NAME}" \
          --version="${KMS_KEY_VERSION}" \
          --digest-algorithm="DIGEST_ALGORITHM" \
          --input-file=/tmp/generated_payload.json \
          --signature-file=/tmp/generated_payload.json.sig
      

      DIGEST_ALGORITHM est l'un des éléments suivants : sha256, sha384 ou sha512. Il s'agit de l'algorithme de condensé de la version de clé que vous utilisez pour la signature.

      Cette commande génère un fichier nommé /tmp/generated_payload.json.sig contenant la signature numérique.

    3. Récupérez le certificateur au nom duquel vous signez l'attestation et extrayez l'ID de la clé publique stockée :

      curl \
          -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
          -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
          "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors/"
      

      L'autorisation binaire renvoie un objet JSON semblable à celui-ci :

      {
        "name": "projects/example-project/attestors/test-attestor",
        "userOwnedGrafeasNote": {
          "noteReference": "projects/example-project/notes/test-attestor",
          "publicKeys": [
            {
              "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
              "pkixPublicKey": {
                "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
                "signatureAlgorithm": "ECDSA_P256_SHA256"
              }
            }
          ],
          "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
        },
        "updateTime": "2019-06-26T16:58:33.977438Z"
      }
      
    4. Dans un éditeur de texte, créez un fichier JSON dans /tmp/attestation.json qui décrit l'attestation :

      cat > /tmp/attestation.json << EOM
      {
        "resourceUri": "${IMAGE_TO_ATTEST}",
        "note_name": "${NOTE_URI}",
        "attestation": {
           "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
           "signatures": [
               {
                   "public_key_id": "KEY_ID",
                   "signature": "$(base64 --wrap=0 /tmp/generated_payload.json.sig)"
               }
           ]
        }
      
      }
      EOM
      

      KEY_ID correspond à l'ID de clé publique renvoyé à l'étape précédente.

    5. Créez l'attestation :

      curl -X POST \
          -H "Content-Type: application/json" \
          -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
          -H "Authorization: Bearer $(gcloud auth print-access-token)" \
          --data-binary @/tmp/attestation.json \
      "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
      

Vérifier que l'attestation a bien été créée

Pour vérifier que l'attestation a été créée, procédez comme suit :

gcloud

Saisissez ce qui suit dans la ligne de commande :

gcloud container binauthz attestations list \
    --project="${ATTESTATION_PROJECT_ID}" \
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}"

REST

Récupérez une liste d'attestations :

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences?filter=kind%3D%22ATTESTATION%22"

S'il existe de nombreuses attestations, une valeur "nextPageToken" peut être renvoyée dans la réponse. Dans ce cas, la requête doit être répétée, mais le paramètre de requête pageToken doit être défini sur cette valeur nextPageToken pour récupérer d'autres attestations. Lorsque nextPageToken est vide, cela signifie qu'il n'y a plus de résultats.

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/?filter=kind%3D%22ATTESTATION%22&pageToken=${NEXT_PAGE_TOKEN}"

Étape suivante