1. Introduction
Container Analysis permet d'analyser les failles et de stocker les métadonnées des conteneurs. Le service d'analyse effectue des analyses des failles sur les images de Container Registry et Artifact Registry, puis stocke les métadonnées obtenues et les met à disposition via une API. Le stockage de métadonnées vous permet de stocker des informations provenant de différentes sources, y compris l'analyse des failles, les services Google Cloud et les fournisseurs tiers.
L'analyse des failles peut s'effectuer automatiquement ou à la demande:
- Lorsque l'analyse automatique est activée, l'analyse se déclenche automatiquement chaque fois que vous transférez une nouvelle image vers Artifact Registry ou Container Registry. Les informations sur les failles sont mises à jour en continu lorsque de nouvelles failles sont détectées.
- Lorsque l'analyse à la demande est activée, vous devez exécuter une commande pour analyser une image locale ou une image dans Artifact Registry ou Container Registry. L'analyse à la demande vous permet de choisir quand analyser les conteneurs. Par exemple, vous pouvez analyser une image créée localement et corriger les failles avant de la stocker dans un registre. Les résultats de l'analyse sont disponibles jusqu'à 48 heures après l'analyse, et les informations sur les failles ne sont pas mises à jour après l'analyse.
Container Analysis intégré à votre pipeline CI/CD vous permet de prendre des décisions basées sur ces métadonnées. Par exemple, vous pouvez utiliser l'autorisation binaire pour créer des stratégies de déploiement qui n'autorisent que les déploiements d'images conformes à partir de registres approuvés.
Points abordés
- Activer l'analyse automatique
- Effectuer une analyse à la demande
- Intégrer l'analyse dans un pipeline de compilation
- Signer des images approuvées
- Utiliser les contrôleurs d'admission GKE pour bloquer des images
- Configurer GKE pour n'autoriser que les images approuvées signées
2. Préparation
Configuration de l'environnement d'auto-formation
- Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)
- Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pouvez le mettre à jour à tout moment.
- L'ID du projet est unique parmi tous les projets Google Cloud et non modifiable une fois défini. La console Cloud génère automatiquement une chaîne unique (en général, vous n'y accordez d'importance particulière). Dans la plupart des ateliers de programmation, vous devrez indiquer l'ID de votre projet (généralement identifié par
PROJECT_ID
). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre de manière aléatoire. Vous pouvez également en spécifier un et voir s'il est disponible. Après cette étape, l'ID n'est plus modifiable et restera donc le même pour toute la durée du projet. - Pour information, il existe une troisième valeur (le numéro de projet) que certaines API utilisent. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
- Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour désactiver les ressources et éviter ainsi que des frais ne vous soient facturés après ce tutoriel, vous pouvez supprimer le projet ou les ressources que vous avez créées. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai gratuit pour bénéficier d'un crédit de 300 $.
Démarrer l'éditeur Cloudshell
Cet atelier a été conçu et testé pour être utilisé avec l'éditeur Google Cloud Shell. Pour accéder à l'éditeur :
- accéder à votre projet Google à l'adresse https://console.cloud.google.com ;
- En haut à droite, cliquez sur l'icône de l'éditeur Cloud Shell.
- Un nouveau volet s'ouvre en bas de la fenêtre.
Configuration de l'environnement
Dans Cloud Shell, définissez l'ID et le numéro de votre projet. Enregistrez-les en tant que variables PROJECT_ID
et PROJECT_ID
.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Activer les services
Activez tous les services nécessaires :
gcloud services enable \
cloudkms.googleapis.com \
cloudbuild.googleapis.com \
container.googleapis.com \
containerregistry.googleapis.com \
artifactregistry.googleapis.com \
containerscanning.googleapis.com \
ondemandscanning.googleapis.com \
binaryauthorization.googleapis.com
Créer un dépôt Artifact Registry
Dans cet atelier, vous allez utiliser Artifact Registry pour stocker et analyser vos images. Créez le dépôt à l'aide de la commande suivante.
gcloud artifacts repositories create artifact-scanning-repo \
--repository-format=docker \
--location=us-central1 \
--description="Docker repository"
Configurez Docker pour qu'il utilise vos identifiants gcloud lorsque vous accédez à Artifact Registry.
gcloud auth configure-docker us-central1-docker.pkg.dev
3. Analyse automatique
L'analyse des artefacts se déclenche automatiquement chaque fois que vous transférez une nouvelle image vers Artifact Registry ou Container Registry. Les informations sur les failles sont mises à jour en continu lorsque de nouvelles failles sont détectées. Dans cette section, vous allez transférer une image vers Artifact Registry et explorer les résultats.
Créer et accéder à un répertoire de travail
mkdir vuln-scan && cd vuln-scan
Définir un exemple d'image
Créez un fichier nommé Dockerfile avec le contenu suivant.
cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a
# System
RUN apt update && apt install python3-pip -y
# App
WORKDIR /app
COPY . ./
RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
EOF
Créez un fichier nommé main.py avec le contenu suivant :
cat > ./main.py << EOF
import os
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
name = os.environ.get("NAME", "Worlds")
return "Hello {}!".format(name)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF
Créer et transférer l'image vers la RA
Utilisez Cloud Build pour créer et transférer automatiquement votre conteneur vers Artifact Registry. Notez la balise bad
sur l'image. Cela vous aidera à l'identifier pour les étapes suivantes.
gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad
Examiner les détails de l'image
Une fois le processus de compilation terminé, examinez l'image et les résultats de failles dans le tableau de bord Artifact Registry.
- Ouvrez Artifact Registry dans Cloud Console.
- Cliquez sur le dépôt artifact-scanning-repo pour en afficher le contenu.
- Cliquez sur les détails de l'image
- Cliquez sur le dernier condensé de votre image.
- Une fois l'analyse terminée, cliquez sur l'onglet "Failles" de l'image.
Dans l'onglet "Failles", vous verrez les résultats de l'analyse automatique de l'image que vous venez de créer.
L'automatisation de l'analyse est activée par défaut. Consultez les paramètres d'Artifact Registry pour savoir comment désactiver/activer la recherche automatique.
4. On-Demand Scanning
Dans certains cas, vous devrez peut-être exécuter une analyse avant de transférer l'image vers un dépôt. Par exemple, un développeur de conteneur peut analyser une image et corriger les problèmes avant de transférer le code vers le contrôle des sources. Dans l'exemple ci-dessous, vous allez compiler et analyser l'image localement avant d'agir sur les résultats.
Créer une image
À cette étape, vous allez utiliser Docker local pour créer l'image dans votre cache local.
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .
Numériser l'image
Une fois l'image créée, demandez une analyse de l'image. Les résultats de l'analyse sont stockés dans un serveur de métadonnées. La tâche se termine avec l'emplacement des résultats sur le serveur de métadonnées.
gcloud artifacts docker images scan \
us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
--format="value(response.scan)" > scan_id.txt
Examiner le fichier de sortie
Prenez le temps de consulter la sortie de l'étape précédente, qui a été stockée dans le fichier scan_id.txt. Notez l'emplacement du rapport des résultats de l'analyse dans le serveur de métadonnées.
cat scan_id.txt
Examiner les résultats détaillés de l'analyse
Pour afficher les résultats réels de l'analyse, utilisez la commande list-vulnerabilities
sur l'emplacement du rapport indiqué dans le fichier de sortie.
gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt)
La sortie contient une quantité importante de données sur toutes les failles de l'image.
Signaler des problèmes critiques
Les humains utilisent rarement directement les données stockées dans le rapport. Les résultats sont généralement utilisés par un processus automatisé. Utilisez les commandes ci-dessous pour lire les détails du rapport et enregistrer les failles critiques détectées.
export SEVERITY=CRITICAL
gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi
Le résultat de cette commande sera
Failed vulnerability check for CRITICAL level
5. Analyse du pipeline de compilation
Dans cette section, vous allez créer un pipeline de compilation automatisé qui créera votre image de conteneur, l'analysera, puis évaluera les résultats. Si aucune faille critique n'est détectée, l'image est transmise au dépôt. Si des failles critiques sont détectées, la compilation échoue et se termine.
Accorder l'accès au compte de service Cloud Build
Cloud Build aura besoin de droits pour accéder à l'API d'analyse à la demande. Accordez l'accès à l'aide des commandes suivantes.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/ondemandscanning.admin"
Créer le pipeline Cloud Build
La commande suivante crée un fichier cloudbuild.yaml dans votre répertoire qui sera utilisé pour le processus automatisé. Pour cet exemple, les étapes sont limitées au processus de compilation du conteneur. En pratique, vous devez toutefois inclure des instructions et des tests spécifiques à l'application en plus des étapes de conteneur.
Créez le fichier à l'aide de la commande suivante.
cat > ./cloudbuild.yaml << EOF
steps:
# build
- id: "build"
name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
waitFor: ['-']
#Run a vulnerability scan at _SECURITY level
- id: scan
name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
(gcloud artifacts docker images scan \
us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
--location us \
--format="value(response.scan)") > /workspace/scan_id.txt
#Analyze the result of the scan
- id: severity check
name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
--format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi
#Retag
- id: "retag"
name: 'gcr.io/cloud-builders/docker'
args: ['tag', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']
#pushing to artifact registry
- id: "push"
name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']
images:
- us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF
Exécuter le pipeline de CI
Envoyez le build pour traitement afin de vérifier qu'il échoue lorsqu'une faille de gravité CRITICAL est détectée.
gcloud builds submit
Examiner l'échec de la compilation
La compilation que vous venez d'envoyer échouera, car l'image contient des failles CRITIQUES.
Examinez l'échec de la compilation sur la page Historique de compilation Cloud Build.
Corriger la faille
Mettez à jour le fichier Dockerfile pour utiliser une image de base qui ne contient pas de failles critiques.
Remplacez le fichier Dockerfile pour utiliser l'image Debian 10 à l'aide de la commande suivante :
cat > ./Dockerfile << EOF
from python:3.8-slim
# App
WORKDIR /app
COPY . ./
RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0
CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app
EOF
Exécuter le processus de CI avec l'image correcte
Envoyez le build pour traitement afin de vérifier qu'il aboutit lorsqu'aucune faille de gravité CRITICAL n'est détectée.
gcloud builds submit
Vérifier la réussite de la compilation
La compilation que vous venez d'envoyer aboutira, car l'image mise à jour ne contient aucune faille CRITICAL.
Vérifier que la compilation a bien réussi sur la page Historique Cloud Build
Examiner les résultats de l'analyse
Examiner l'image correcte dans Artifact Registry
- Ouvrez Artifact Registry dans Cloud Console.
- Cliquez sur le dépôt artifact-scanning-repo pour en afficher le contenu.
- Cliquez sur les détails de l'image
- Cliquez sur le dernier condensé de votre image.
- Cliquez sur l'onglet "Failles" de l'image.
6. Signature d'images
Créer une note de certificateur
Une note d'attestation est simplement un petit élément de données qui sert de libellé au type de signature appliqué. Par exemple, une note peut indiquer un scan de failles, tandis qu'une autre peut être utilisée pour la validation du contrôle qualité. La note sera utilisée pendant le processus de signature.
Créer une note
cat > ./vulnz_note.json << EOM
{
"attestation": {
"hint": {
"human_readable_name": "Container Vulnerabilities attestation authority"
}
}
}
EOM
Stocker la note
NOTE_ID=vulnz_note
curl -vvv -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
--data-binary @./vulnz_note.json \
"https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"
Vérifier la note
curl -vvv \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"
Créer un certificateur
Les certificateurs sont utilisés pour effectuer le processus de signature d'image et associent une occurrence de la note à l'image pour une vérification ultérieure. Créez le certificateur pour l'utiliser ultérieurement.
Créer un certificateur
ATTESTOR_ID=vulnz-attestor
gcloud container binauthz attestors create $ATTESTOR_ID \
--attestation-authority-note=$NOTE_ID \
--attestation-authority-note-project=${PROJECT_ID}
Valider le certificateur
gcloud container binauthz attestors list
Notez que la dernière ligne indique NUM_PUBLIC_KEYS: 0
. Vous fournirez les clés ultérieurement.
Notez également que Cloud Build crée automatiquement le certificateur built-by-cloud-build
dans votre projet lorsque vous exécutez une compilation qui génère des images. La commande ci-dessus renvoie donc deux attesteurs, vulnz-attestor
et built-by-cloud-build
. Une fois les images compilées, Cloud Build signe et crée automatiquement des attestations pour celles-ci.
Ajouter un rôle IAM
Le compte de service Autorisation binaire doit disposer des droits nécessaires pour afficher les notes d'attestation. Accordez l'accès à l'aide de l'appel d'API suivant :
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
cat > ./iam_request.json << EOM
{
'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
'policy': {
'bindings': [
{
'role': 'roles/containeranalysis.notes.occurrences.viewer',
'members': [
'serviceAccount:${BINAUTHZ_SA_EMAIL}'
]
}
]
}
}
EOM
Utilisez le fichier pour créer la stratégie IAM.
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
--data-binary @./iam_request.json \
"https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"
Ajouter une clé KMS
L'émetteur a besoin de clés cryptographiques pour joindre la note et fournir des signatures vérifiables. À cette étape, vous allez créer et stocker des clés dans KMS pour que Cloud Build puisse y accéder ultérieurement.
Ajoutez d'abord des variables d'environnement pour décrire la nouvelle clé.
KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1
Créer un trousseau pour contenir un ensemble de clés
gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"
Créer une paire de clés de signature asymétrique pour le certificateur
gcloud kms keys create "${KEY_NAME}" \
--keyring="${KEYRING}" --location="${KEY_LOCATION}" \
--purpose asymmetric-signing \
--default-algorithm="ec-sign-p256-sha256"
Votre clé devrait apparaître sur la page KMS de la console Google Cloud.
Associez maintenant la clé à votre émetteur d'attestation à l'aide de la commande gcloud binauthz:
gcloud beta container binauthz attestors public-keys add \
--attestor="${ATTESTOR_ID}" \
--keyversion-project="${PROJECT_ID}" \
--keyversion-location="${KEY_LOCATION}" \
--keyversion-keyring="${KEYRING}" \
--keyversion-key="${KEY_NAME}" \
--keyversion="${KEY_VERSION}"
Si vous imprimez à nouveau la liste des autorités, vous devriez voir une clé enregistrée:
gcloud container binauthz attestors list
Créer une attestation signée
À ce stade, vous avez configuré les fonctionnalités qui vous permettent de signer des images. Utilisez le certificateur que vous avez créé précédemment pour signer l'image de conteneur avec laquelle vous avez travaillé.
CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
--format='get(image_summary.digest)')
Vous pouvez maintenant utiliser gcloud pour créer votre attestation. La commande prend simplement en compte les détails de la clé que vous souhaitez utiliser pour la signature et l'image de conteneur spécifique que vous souhaitez approuver.
gcloud beta container binauthz attestations sign-and-create \
--artifact-url="${CONTAINER_PATH}@${DIGEST}" \
--attestor="${ATTESTOR_ID}" \
--attestor-project="${PROJECT_ID}" \
--keyversion-project="${PROJECT_ID}" \
--keyversion-location="${KEY_LOCATION}" \
--keyversion-keyring="${KEYRING}" \
--keyversion-key="${KEY_NAME}" \
--keyversion="${KEY_VERSION}"
En termes de Container Analysis, cela crée une nouvelle occurrence et l'associe à la note de votre attestateur. Pour vous assurer que tout a fonctionné comme prévu, vous pouvez lister vos attestations.
gcloud container binauthz attestations list \
--attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}
7. Signature avec Cloud Build
Vous avez activé la signature d'image et utilisé manuellement l'outil Attestor pour signer votre exemple d'image. En pratique, vous devez appliquer des attestations lors de processus automatisés tels que les pipelines CI/CD.
Dans cette section, vous allez configurer Cloud Build pour qu'il atteste automatiquement les images.
Rôles
Attribuez le rôle "Lecteur des certificateurs de l'autorisation binaire" au compte de service Cloud Build :
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
--role roles/binaryauthorization.attestorsViewer
Attribuez le rôle "Signataire/Validateur de CryptoKeys Cloud KMS" au compte de service Cloud Build (signature basée sur KMS) :
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
--role roles/cloudkms.signerVerifier
Attribuez le rôle "Agent d'association de notes Container Analysis" au compte de service Cloud Build :
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
--role roles/containeranalysis.notes.attacher
Préparer l'étape de compilation personnalisée Cloud Build
Vous allez utiliser une étape de compilation personnalisée dans Cloud Build pour simplifier le processus d'attestation. Google fournit cette étape de compilation personnalisée, qui contient des fonctions d'assistance pour simplifier le processus. Avant toute utilisation, le code de l'étape de compilation personnalisée doit être intégré à un conteneur et transféré vers Cloud Build. Pour ce faire, exécutez les commandes suivantes:
git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/binauthz-attestation
gcloud builds submit . --config cloudbuild.yaml
cd ../..
rm -rf cloud-builders-community
Ajouter une étape de signature à votre fichier cloudbuild.yaml
À cette étape, vous allez ajouter l'étape d'attestation à votre pipeline Cloud Build que vous avez créé précédemment.
- Examinez la nouvelle étape que vous allez ajouter.
Examen uniquement. Ne pas copier
#Sign the image only if the previous severity check passes - id: 'create-attestation' name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest' args: - '--artifact-url' - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image' - '--attestor' - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID' - '--keyversion' - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
- Remplacez votre fichier cloudbuild.yaml par le pipeline complet mis à jour.
cat > ./cloudbuild.yaml << EOF
steps:
# build
- id: "build"
name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
waitFor: ['-']
#Run a vulnerability scan at _SECURITY level
- id: scan
name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
(gcloud artifacts docker images scan \
us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
--location us \
--format="value(response.scan)") > /workspace/scan_id.txt
#Analyze the result of the scan
- id: severity check
name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- |
gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
--format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi
#Retag
- id: "retag"
name: 'gcr.io/cloud-builders/docker'
args: ['tag', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']
#pushing to artifact registry
- id: "push"
name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']
#Sign the image only if the previous severity check passes
- id: 'create-attestation'
name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
args:
- '--artifact-url'
- 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good'
- '--attestor'
- 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
- '--keyversion'
- 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
images:
- us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good
EOF
Exécuter le build
gcloud builds submit
Examiner la compilation dans l'historique Cloud Build
Ouvrez Cloud Console et accédez à la page Historique de compilation Cloud Build. Examinez la dernière compilation et l'exécution réussie des étapes de compilation.
8. Stratégies de contrôle d'admission
L'autorisation binaire est une fonctionnalité de GKE et de Cloud Run qui permet de valider des règles avant qu'une image de conteneur ne soit autorisée à s'exécuter. La validation s'exécute pour toute requête d'exécution d'une image, qu'elle provienne d'un pipeline CI/CD approuvé ou d'un utilisateur qui tente de déployer manuellement une image. Cette fonctionnalité vous permet de sécuriser vos environnements d'exécution plus efficacement que les vérifications du pipeline CI/CD seules.
Pour comprendre cette fonctionnalité, vous allez modifier la stratégie GKE par défaut afin d'appliquer une règle d'autorisation stricte.
Créer le cluster GKE
Créez le cluster GKE :
gcloud beta container clusters create binauthz \
--zone us-central1-a \
--binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE
Autorisez Cloud Build à déployer sur ce cluster:
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/container.developer"
Règle d'autorisation de tout
Vérifiez d'abord l'état de la stratégie par défaut et votre capacité à déployer une image.
- Examiner la stratégie existante
gcloud container binauthz policy export
- Notez que la règle d'application est définie sur
ALWAYS_ALLOW
.
evaluationMode: ALWAYS_ALLOW
- Déployer un exemple pour vérifier que vous pouvez déployer n'importe quoi
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
- Vérifier que le déploiement a fonctionné
kubectl get pods
Le résultat suivant s'affiche :
- Supprimer le déploiement
kubectl delete pod hello-server
Règle de refus de tout
Mettez à jour la stratégie pour interdire toutes les images.
- Exporter la stratégie actuelle vers un fichier modifiable
gcloud container binauthz policy export > policy.yaml
- Modifier les règles
Dans un éditeur de texte, remplacez la valeur ALWAYS_ALLOW par ALWAYS_DENY pour le paramètre evaluationMode.
edit policy.yaml
Le fichier YAML de stratégie doit ressembler à ceci :
globalPolicyEvaluationMode: ENABLE defaultAdmissionRule: evaluationMode: ALWAYS_DENY enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG name: projects/PROJECT_ID/policy
- Ouvrez le terminal, appliquez la nouvelle règle, puis attendez quelques secondes que la modification se propage.
gcloud container binauthz policy import policy.yaml
- Essayer de déployer un exemple de charge de travail
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
- Le déploiement échoue avec le message suivant
Error from server (VIOLATES_POLICY): admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image gcr.io/google-samples/hello-app:1.0 denied by Binary Authorization default admission rule. Denied by always_deny admission rule
Rétablir la stratégie pour autoriser tout
Avant de passer à la section suivante, veillez à annuler les modifications apportées aux règles.
- Modifier les règles
Dans un éditeur de texte, remplacez la valeur ALWAYS_DENY par ALWAYS_ALLOW pour le paramètre evaluationMode.
edit policy.yaml
Le fichier YAML de stratégie doit ressembler à ceci :
globalPolicyEvaluationMode: ENABLE defaultAdmissionRule: evaluationMode: ALWAYS_ALLOW enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG name: projects/PROJECT_ID/policy
- Appliquer la règle rétablie
gcloud container binauthz policy import policy.yaml
9. Bloquer les failles dans GKE
Dans cette section, vous allez combiner ce que vous avez appris jusqu'à présent en implémentant un pipeline CI/CD avec Cloud Build qui analyse les images, puis recherche les failles avant de signer l'image et de tenter de la déployer. GKE utilise l'autorisation binaire pour vérifier que l'image dispose d'une signature de l'analyse des failles avant de l'autoriser à s'exécuter.
Modifier le règlement GKE pour exiger une attestation
Exiger que les images soient signées par votre émetteur d'attestation en ajoutant des règles clusterAdmissionRules à votre stratégie BinAuth GKE
Remplacez la stratégie par la configuration mise à jour à l'aide de la commande ci-dessous.
COMPUTE_ZONE=us-central1-a
cat > binauth_policy.yaml << EOM
defaultAdmissionRule:
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
evaluationMode: ALWAYS_DENY
globalPolicyEvaluationMode: ENABLE
clusterAdmissionRules:
${COMPUTE_ZONE}.binauthz:
evaluationMode: REQUIRE_ATTESTATION
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
requireAttestationsBy:
- projects/${PROJECT_ID}/attestors/vulnz-attestor
EOM
Appliquer la règle
gcloud beta container binauthz policy import binauth_policy.yaml
Tentative de déploiement de l'image non signée
Créez un descripteur de déploiement pour l'application que vous avez compilée précédemment à l'aide de la commande suivante. L'image utilisée ici est celle que vous avez créée précédemment, qui contient des failles critiques et NE contient PAS l'attestation signée.
Les contrôleurs d'admission GKE doivent connaître l'image exacte à déployer pour valider de manière cohérente la signature. Pour ce faire, vous devez utiliser le condensé d'image plutôt qu'un tag simple.
Obtenir le condensé de l'image pour l'image incorrecte
CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:bad \
--format='get(image_summary.digest)')
Utiliser le condensé dans la configuration Kubernetes
cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
name: deb-httpd
spec:
selector:
app: deb-httpd
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deb-httpd
spec:
replicas: 1
selector:
matchLabels:
app: deb-httpd
template:
metadata:
labels:
app: deb-httpd
spec:
containers:
- name: deb-httpd
image: ${CONTAINER_PATH}@${DIGEST}
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
EOM
Tentative de déploiement de l'application sur GKE
kubectl apply -f deploy.yaml
Examinez la charge de travail dans la console et notez l'erreur indiquant que le déploiement a été refusé:
No attestations found that were valid and signed by a key trusted by the attestor
Déployer une image signée
Obtenir le condensé de l'image pour l'image incorrecte
CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:good \
--format='get(image_summary.digest)')
Utiliser le condensé dans la configuration Kubernetes
cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
name: deb-httpd
spec:
selector:
app: deb-httpd
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deb-httpd
spec:
replicas: 1
selector:
matchLabels:
app: deb-httpd
template:
metadata:
labels:
app: deb-httpd
spec:
containers:
- name: deb-httpd
image: ${CONTAINER_PATH}@${DIGEST}
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
EOM
Déployer l'application sur GKE
kubectl apply -f deploy.yaml
Examinez la charge de travail dans la console et notez que l'image a bien été déployée.
10. Félicitations !
Félicitations, vous avez terminé cet atelier de programmation.
Points abordés
- Activer l'analyse automatique
- Effectuer une analyse à la demande
- Intégrer l'analyse dans un pipeline de compilation
- Signer des images approuvées
- Utiliser les contrôleurs d'admission GKE pour bloquer des images
- Configurer GKE pour n'autoriser que les images approuvées signées
Étapes suivantes :
- Sécuriser les déploiements d'images sur Cloud Run et Google Kubernetes Engine | Documentation Cloud Build
- Guide de démarrage rapide: configurer une stratégie d'autorisation binaire avec GKE | Google Cloud
Effectuer un nettoyage
Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez chaque ressource individuellement.
Supprimer le projet
Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.