Secure Build & Mit Cloud Build, Artifact Registry und GKE bereitstellen

1. Einführung

Container Analysis bietet Scans auf Sicherheitslücken und Metadatenspeicherung für Container. Der Scandienst führt Scans auf Sicherheitslücken in Images in Artifact Registry und Container Registry durch, speichert die resultierenden Metadaten und stellt sie über eine API zur Verfügung. Mit der Speicherung von Metadaten können Sie Informationen aus verschiedenen Quellen speichern, einschließlich Scans auf Sicherheitslücken, Google Cloud-Diensten und Drittanbietern.

Das Scannen auf Sicherheitslücken kann automatisch oder on demand erfolgen:

  • Wenn automatisches Scannen aktiviert ist, wird jedes Mal automatisch gescannt, wenn Sie ein neues Image in Artifact Registry oder Container Registry hochladen. Die Informationen zu Sicherheitslücken werden kontinuierlich aktualisiert, wenn neue Sicherheitslücken entdeckt werden.
  • Wenn On-Demand-Scanning aktiviert ist, müssen Sie einen Befehl ausführen, um ein lokales Image oder ein Image in Artifact Registry oder Container Registry zu scannen. On-Demand-Scanning bietet mehr Flexibilität beim Scannen von Containern. Sie können beispielsweise ein lokal erstelltes Image scannen und Sicherheitslücken beheben, bevor Sie es in einer Registry speichern. Scanergebnisse sind bis zu 48 Stunden nach Abschluss des Scans verfügbar und Informationen zu Sicherheitslücken werden nach dem Scan nicht aktualisiert.

Durch das Einbinden von Container Analysis in Ihre CI-/CD-Pipeline können Sie auf der Grundlage dieser Metadaten Entscheidungen treffen. Sie können beispielsweise mit der Binärautorisierung Deployment-Richtlinien erstellen, die nur Deployments für konforme Images aus vertrauenswürdigen Registries zulassen.

Lerninhalte

  • Automatisches Scannen aktivieren
  • On-Demand-Scans durchführen
  • Scannen in eine Build-Pipeline einbinden
  • Genehmigte Bilder signieren
  • GKE-Zugangs-Controller zum Blockieren von Images verwenden
  • GKE so konfigurieren, dass nur signierte, genehmigte Images zugelassen werden

2. Einrichtung und Anforderungen

Umgebung zum selbstbestimmten Lernen einrichten

  1. Melden Sie sich in der Google Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Der Projektname ist der Anzeigename für die Teilnehmer dieses Projekts. Es handelt sich um einen String, der nicht von Google APIs verwendet wird. Sie können ihn jederzeit aktualisieren.
  • Die Projekt-ID ist für alle Google Cloud-Projekte eindeutig und unveränderlich (kann nach dem Festlegen nicht mehr geändert werden). In der Cloud Console wird automatisch ein eindeutiger String generiert. Normalerweise ist es nicht wichtig, wie dieser String aussieht. In den meisten Codelabs müssen Sie auf die Projekt-ID verweisen (sie wird in der Regel als PROJECT_ID angegeben). Wenn Ihnen die generierte ID nicht gefällt, können Sie eine andere zufällige ID generieren. Alternativ können Sie es mit einem eigenen versuchen und sehen, ob es verfügbar ist. Sie kann nach diesem Schritt nicht mehr geändert werden und bleibt für die Dauer des Projekts bestehen.
  • Zur Information: Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu diesen drei Werten
  1. Als Nächstes müssen Sie die Abrechnung in der Cloud Console aktivieren, um Cloud-Ressourcen/-APIs zu verwenden. Die Durchführung dieses Codelabs sollte keine oder nur geringe Kosten verursachen. Wenn Sie Ressourcen herunterfahren möchten, damit Ihnen nach Abschluss dieser Anleitung keine Kosten mehr in Rechnung gestellt werden, können Sie die von Ihnen erstellten Ressourcen oder das gesamte Projekt löschen. Neue Nutzer von Google Cloud kommen für das Programm für kostenlose Testversionen mit einem Guthaben von 300$ infrage.

Cloud Shell-Editor starten

Dieses Lab wurde für die Verwendung mit Google Cloud Shell Editor entwickelt und getestet. So greifen Sie auf den Editor zu:

  1. Rufen Sie Ihr Google-Projekt unter https://console.cloud.google.com auf.
  2. Klicken Sie oben rechts auf das Cloud Shell Editor-Symbol.

8560cc8d45e8c112.png

  1. Unten im Fenster wird ein neuer Bereich geöffnet.

Umgebung einrichten

Legen Sie in Cloud Shell Ihre Projekt-ID und die Projektnummer für Ihr Projekt fest. Speichern Sie sie als die Variablen PROJECT_ID und PROJECT_ID.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

Dienste aktivieren

Aktivieren Sie alle erforderlichen Dienste:

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 

Artifact Registry-Repository erstellen

In diesem Lab verwenden Sie Artifact Registry zum Speichern und Scannen Ihrer Images. Erstellen Sie das Repository mit dem folgenden Befehl.

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

Konfigurieren Sie Docker so, dass Ihre gcloud-Anmeldedaten für den Zugriff auf Artifact Registry verwendet werden.

gcloud auth configure-docker us-central1-docker.pkg.dev

3. Automatisches Scannen

Das Scannen von Artefakten wird jedes Mal automatisch ausgelöst, wenn Sie ein neues Image in Artifact Registry oder Container Registry hochladen. Die Informationen zu Sicherheitslücken werden kontinuierlich aktualisiert, wenn neue Sicherheitslücken entdeckt werden. In diesem Abschnitt übertragen Sie ein Image per Push in die Artifact Registry und sehen sich die Ergebnisse an.

Arbeitsverzeichnis erstellen und in dieses Verzeichnis wechseln

mkdir vuln-scan && cd vuln-scan

Beispielbild definieren

Erstellen Sie eine Datei mit dem Namen „Dockerfile“ und dem folgenden Inhalt.

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

Erstellen Sie eine Datei mit dem Namen „main.py“ und dem folgenden Inhalt:

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

Image erstellen und per Push in AR übertragen

Mit Cloud Build können Sie Ihren Container erstellen und automatisch per Push in Artifact Registry übertragen. Beachten Sie das Tag bad auf dem Bild. So können Sie ihn in späteren Schritten leichter identifizieren.

gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad

Image-Details prüfen

Nach Abschluss des Build-Prozesses können Sie sich das Image und die Ergebnisse zu den Sicherheitslücken im Artifact Registry-Dashboard ansehen.

  1. Öffnen Sie Artifact Registry in der Cloud Console.
  2. Klicken Sie auf „artifact-scanning-repo“, um den Inhalt aufzurufen.
  3. Klicken Sie auf die Bilddetails.
  4. Klicken Sie auf den neuesten Digest Ihres Images.
  5. Klicken Sie nach Abschluss des Scans auf den Tab „Sicherheitslücken“ für das Image.

Auf dem Tab „Sicherheitslücken“ sehen Sie die Ergebnisse des automatischen Scans für das Image, das Sie gerade erstellt haben.

361be7b3bf293fca.png

Das automatisierte Scannen ist standardmäßig aktiviert. In den Artifact Registry-Einstellungen können Sie das automatische Scannen deaktivieren oder aktivieren.

4. On-Demand-Scanning

Es gibt verschiedene Szenarien, in denen Sie einen Scan durchführen müssen, bevor Sie das Image in ein Repository übertragen. Bei der Containerentwicklung können Sie z. B. ein Image scannen und die gefundenen Probleme beheben, bevor Sie den Code in die Quellcodeverwaltung übertragen. Im folgenden Beispiel erstellen und analysieren Sie das Image lokal, bevor Sie auf die Ergebnisse reagieren.

Image erstellen

In diesem Schritt verwenden Sie das lokale Docker, um das Image in Ihrem lokalen Cache zu erstellen.

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

Bild scannen

Wenn das Image erstellt wurde, fordern Sie einen Scan des Images an. Die Ergebnisse des Scans werden auf einem Metadatenserver gespeichert. Der Job wird mit dem Speicherort der Ergebnisse auf dem Metadatenserver abgeschlossen.

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

Ausgabedatei prüfen

Sehen Sie sich die Ausgabe des vorherigen Schritts an, die in der Datei „scan_id.txt“ gespeichert wurde. Beachten Sie den Speicherort des Berichts mit den Scanergebnissen auf dem Metadatenserver.

cat scan_id.txt

Detaillierte Scanergebnisse ansehen

Verwenden Sie den Befehl list-vulnerabilities für den in der Ausgabedatei angegebenen Speicherort des Berichts, um die tatsächlichen Ergebnisse des Scans aufzurufen.

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

Die Ausgabe enthält eine erhebliche Menge an Daten zu allen Sicherheitslücken im Image.

Schwerwiegende Probleme melden

Die im Bericht gespeicherten Daten werden selten von Menschen direkt verwendet. Die Ergebnisse werden normalerweise von einem automatisierten Prozess genutzt. Mit den folgenden Befehlen können Sie die Berichtsdetails lesen und protokollieren, ob CRITICAL-Sicherheitslücken gefunden wurden.

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

Dies ist die Ausgabe dieses Befehls:

Failed vulnerability check for CRITICAL level

5. Build-Pipeline-Scanning

In diesem Abschnitt erstellen Sie eine automatisierte Build-Pipeline, um Ihr Container-Image zu erstellen, zu scannen und die Ergebnisse auszuwerten. Wenn keine Sicherheitslücken mit dem Schweregrad CRITICAL gefunden werden, wird das Image in das Repository übertragen. Wenn CRITICAL-Sicherheitslücken gefunden werden, schlägt der Build fehl und wird beendet.

Zugriff für Cloud Build-Dienstkonto bereitstellen

Cloud Build benötigt Berechtigungen für den Zugriff auf die On-Demand Scanning API. Gewähren Sie Zugriff mit den folgenden Befehlen.

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"

Cloud Build-Pipeline erstellen

Mit dem folgenden Befehl wird in Ihrem Verzeichnis eine cloudbuild.yaml-Datei erstellt, die für den automatisierten Prozess verwendet wird. In diesem Beispiel beschränken sich die Schritte auf den Container-Build-Prozess. In der Praxis würden Sie jedoch zusätzlich zu den Container-Schritten anwendungsspezifische Anweisungen und Tests einfügen.

Erstellen Sie die Datei mit dem folgenden Befehl.

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

CI-Pipeline ausführen

Senden Sie den Build zur Verarbeitung, um zu prüfen, ob er fehlschlägt, wenn eine Sicherheitslücke mit dem Schweregrad CRITICAL gefunden wird.

gcloud builds submit

Build-Fehler prüfen

Der Build, den Sie gerade eingereicht haben, schlägt fehl, weil das Image KRITISCHE Sicherheitslücken enthält.

Sehen Sie sich den Build-Fehler auf der Seite Cloud Build-Verlauf an.

Sicherheitslücke beheben

Aktualisieren Sie das Dockerfile, damit ein Basis-Image verwendet wird, das keine Sicherheitslücken mit dem Schweregrad CRITICAL enthält.

Überschreiben Sie das Dockerfile mit dem folgenden Befehl, um das Debian 10-Image zu verwenden:

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

CI-Prozess mit dem guten Bild ausführen

Senden Sie den Build zur Verarbeitung, um zu prüfen, ob er erfolgreich ist, wenn keine Sicherheitslücken mit dem Schweregrad CRITICAL gefunden werden.

gcloud builds submit

Erfolg von Builds prüfen

Der Build, den Sie gerade eingereicht haben, wird erfolgreich sein, da das aktualisierte Image keine Sicherheitslücken mit dem Schweregrad CRITICAL enthält.

Prüfen Sie den Build-Erfolg auf der Seite Cloud Build-Verlauf.

Scanergebnisse prüfen

Funktionierendes Image in Artifact Registry prüfen

  1. Öffnen Sie Artifact Registry in der Cloud Console.
  2. Klicken Sie auf „artifact-scanning-repo“, um den Inhalt aufzurufen.
  3. Klicken Sie auf die Bilddetails.
  4. Klicken Sie auf den neuesten Digest Ihres Images.
  5. Klicken Sie für das Image auf den Tab „Sicherheitslücken“.

6. Images signieren

Attestier-Hinweis erstellen

Ein Attestier-Hinweis ist einfach ein kleiner Datenteil, der als Label für die Art der angewendeten Signatur dient. Ein Hinweis kann sich beispielsweise auf einen Scan auf Sicherheitslücken beziehen während ein anderer für die QA-Freigabe verwendet werden kann. Während des Signierungsprozesses wird auf den Hinweis Bezug genommen.

Notiz erstellen

cat > ./vulnz_note.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "Container Vulnerabilities attestation authority"
    }
  }
}
EOM

Speichern Sie den Hinweis:

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}"

Bestätigen Sie den Hinweis:

curl -vvv  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"

Attestierer erstellen

Attestierer werden verwendet, um den eigentlichen Signierungsprozess für das Image durchzuführen. Sie fügen dem Image eine Version des Hinweises zur späteren Überprüfung hinzu. Erstellen Sie den Attestierer zur späteren Verwendung.

Attestierer erstellen

ATTESTOR_ID=vulnz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

Bestätigen Sie den Attestierer:

gcloud container binauthz attestors list

In der letzten Zeile wird NUM_PUBLIC_KEYS: 0 angezeigt. Sie geben die Schlüssel in einem späteren Schritt an.

Beachten Sie außerdem, dass Cloud Build automatisch den Attestierer built-by-cloud-build in Ihrem Projekt erstellt, wenn Sie einen Build ausführen, der Images generiert. Der obige Befehl gibt also zwei Attestierer zurück: vulnz-attestor und built-by-cloud-build. Nachdem die Images erfolgreich erstellt wurden, signiert Cloud Build automatisch Attestierungen für die Images.

IAM-Rolle hinzufügen

Das Dienstkonto der Binärautorisierung benötigt Berechtigungen zum Aufrufen der Attestierung-Hinweise. Gewähren Sie den Zugriff mit dem folgenden API-Aufruf:

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

Verwenden Sie die Datei, um die IAM-Richtlinie zu erstellen.

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"

KMS-Schlüssel hinzufügen

Der Attestierer benötigt kryptografische Schlüssel, um die Anmerkung anzuhängen und überprüfbare Signaturen bereitzustellen. In diesem Schritt erstellen und speichern Sie Schlüssel in KMS, auf die Cloud Build später zugreifen kann.

Fügen Sie zuerst einige Umgebungsvariablen hinzu, um den neuen Schlüssel zu beschreiben.

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

Schlüsselbund zum Speichern von Schlüsseln erstellen

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

Erstellen Sie ein neues asymmetrisches Schlüsselpaar für die Signierung für den Attestierer:

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing   \
    --default-algorithm="ec-sign-p256-sha256"

Ihr Schlüssel sollte in der Google Cloud Console auf der KMS-Seite angezeigt werden.

Verknüpfen Sie den Schlüssel nun mit Ihrem Attestierer über den gcloud-Befehl „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}"

Wenn Sie die Liste der Zertifizierungsstellen noch einmal ausdrucken, sollte jetzt ein registrierter Schlüssel angezeigt werden:

gcloud container binauthz attestors list

Signierte Attestierung erstellen

An diesem Punkt haben Sie die Features konfiguriert, mit denen Sie Images signieren können. Verwenden Sie den zuvor erstellten Attestierer, um das Container-Image zu signieren, mit dem Sie gearbeitet haben.

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)')

Jetzt können Sie mit gcloud Ihre Attestierung erstellen. Der Befehl verwendet einfach die Details des Schlüssels, den Sie zum Signieren verwenden möchten, und das spezifische Container-Image, das Sie genehmigen möchten.

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}"

In Bezug auf Container Analysis wird dadurch ein neuer Hinweis erstellt und an die Notiz des Attestierers angehängt. Sie können Ihre Attestierungen auflisten, um zu prüfen, ob alles wie erwartet funktioniert hat.

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

7. Mit Cloud Build signieren

Sie haben die Image-Signierung aktiviert und den Attestierer manuell verwendet, um Ihr Beispiel-Image zu signieren. In der Praxis sollten Sie Attestierungen während automatisierter Prozesse wie CI/CD-Pipelines anwenden.

In diesem Abschnitt konfigurieren Sie Cloud Build so, dass Images automatisch bestätigt werden.

Rollen

Fügen Sie dem Cloud Build-Dienstkonto die Rolle "Betrachter der Attestierer von Binärautorisierungen" hinzu:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/binaryauthorization.attestorsViewer

Fügen Sie dem Cloud Build-Dienstkonto (KMS-basierte Signatur) die Rolle "Cloud KMS CryptoKey-Signer/Prüffunktion" hinzu:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/cloudkms.signerVerifier

Fügen Sie dem Cloud Build-Dienstkonto die Rolle "Hinzufüger von Container Analysis-Hinweisen" hinzu:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/containeranalysis.notes.attacher

Benutzerdefinierten Cloud Build-Schritt vorbereiten

Sie verwenden einen benutzerdefinierten Build-Schritt in Cloud Build, um den Attestierungsprozess zu vereinfachen. Dieser Schritt wird von Google bereitgestellt und umfasst Hilfsfunktionen zur Optimierung des Prozesses. Bevor Sie den Schritt verwenden, muss sein Code in einen Container eingebunden und per Push an Cloud Build übertragen werden. Führen Sie dazu die folgenden Befehle aus:

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

Fügen Sie Ihrer Datei „cloudbuild.yaml“ einen Signierungsschritt hinzu.

In diesem Schritt fügen Sie Ihrer zuvor erstellten Cloud Build-Pipeline den Attestierungsschritt hinzu.

  1. Prüfen Sie den neuen Schritt, den Sie hinzufügen möchten.

Nur überprüfen. Nicht kopieren

#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'
  1. Überschreiben Sie Ihre Datei „cloudbuild.yaml“ mit der aktualisierten vollständigen Pipeline.
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

Build ausführen

gcloud builds submit

Überprüfen Sie den Build im Cloud Build-Verlauf:

Öffnen Sie in der Cloud Console die Seite Cloud Build-Verlauf und prüfen Sie den letzten Build und die erfolgreiche Ausführung der Build-Schritte.

8. Richtlinien für die Zugangssteuerung

Die Binärautorisierung ist ein Feature in GKE und Cloud Run, mit dem Regeln validiert werden können, bevor ein Container-Image ausgeführt werden darf. Die Validierung wird bei jeder Anfrage zum Ausführen eines Images ausgeführt, unabhängig davon, ob die Anfrage von einer vertrauenswürdigen CI/CD-Pipeline oder von jemandem stammt, der versucht, ein Image manuell bereitzustellen. So können Sie Ihre Laufzeitumgebungen effektiver schützen als mit CI/CD-Pipeline-Prüfungen allein.

Sie ändern hierfür die Standardrichtlinie für GKE, um eine strenge Autorisierungsregel zu erzwingen.

GKE-Cluster erstellen

Erstellen Sie den GKE-Cluster:

gcloud beta container clusters create binauthz \
    --zone us-central1-a  \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE

Erlauben Sie Cloud Build die Bereitstellung in diesem Cluster:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/container.developer"

„Alle zulassen“-Richtlinie

Prüfen Sie zuerst den Standardrichtlinienstatus und ob Sie ein beliebiges Image bereitstellen können.

  1. Vorhandene Richtlinie prüfen
gcloud container binauthz policy export
  1. Die Richtlinie zur Durchsetzung ist auf ALWAYS_ALLOW festgelegt.

evaluationMode: ALWAYS_ALLOW

  1. Beispiel bereitstellen, um zu prüfen, ob Sie etwas bereitstellen können
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. Prüfen, ob die Bereitstellung funktioniert hat
kubectl get pods

Es wird die folgende Ausgabe angezeigt:

161db370d99ffb13.png

  1. Deployment löschen
kubectl delete pod hello-server

„Alle ablehnen“-Richtlinie

Aktualisieren Sie nun die Richtlinie, um keine Images zuzulassen.

  1. Aktuelle Richtlinie in eine bearbeitbare Datei exportieren
gcloud container binauthz policy export  > policy.yaml
  1. Richtlinie ändern

Ändern Sie in einem Texteditor „evaluationMode“ von „ALWAYS_ALLOW“ in ALWAYS_DENY.

edit policy.yaml

Die YAML-Richtliniendatei sollte so aussehen:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_DENY
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. Öffnen Sie das Terminal, wenden Sie die neue Richtlinie an und warten Sie einige Sekunden, bis die Änderung wirksam wird.
gcloud container binauthz policy import policy.yaml
  1. Beispielarbeitslast bereitstellen
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. Die Bereitstellung schlägt mit der folgenden Meldung fehl:
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

Richtlinie auf „Alle zulassen“ zurücksetzen

Machen Sie die Richtlinienänderungen rückgängig, bevor Sie mit dem nächsten Abschnitt fortfahren.

  1. Richtlinie ändern

Ändern Sie in einem Texteditor „evaluationMode“ von „ALWAYS_DENY“ in ALWAYS_ALLOW.

edit policy.yaml

Die YAML-Richtliniendatei sollte so aussehen:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. Zurückgesetzte Richtlinie anwenden
gcloud container binauthz policy import policy.yaml

9. Sicherheitslücken in GKE blockieren

In diesem Abschnitt kombinieren Sie das bisher Gelernte, indem Sie eine CI/CD-Pipeline mit Cloud Build implementieren, die die Images scannt und dann vor dem Signieren des Images und dem Bereitstellungsversuch auf Sicherheitslücken prüft. GKE verwendet die Binärautorisierung, um zu prüfen, ob das Image eine Signatur vom Scannen auf Sicherheitslücken hat, bevor das Image ausgeführt werden darf.

d5c41bb89e22fd61.png

GKE-Richtlinie auf „require“-Attestierung aktualisieren

„require“-Images werden von Ihrem Attestor signiert, indem Sie Ihrer GKE BinAuth-Richtlinie „clusterAdmissionRules“ hinzufügen.

Überschreiben Sie die Richtlinie mit der aktualisierten Konfiguration, indem Sie den folgenden Befehl ausführen.

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

Richtlinie anwenden

gcloud beta container binauthz policy import binauth_policy.yaml

Versuchen Sie, das nicht signierte Image bereitzustellen.

Erstellen Sie mit dem folgenden Befehl einen Bereitstellungsdeskriptor für die Anwendung, die Sie zuvor erstellt haben. Das hier verwendete Image ist das Image, das Sie zuvor erstellt haben und das kritische Sicherheitslücken enthält und KEINE signierte Attestierung.

GKE-Zulassungscontroller müssen das genaue Image kennen, das bereitgestellt werden soll, um die Signatur konsistent zu validieren. Dazu müssen Sie den Image-Digest anstelle eines einfachen Tags verwenden.

Image-Digest für das fehlerhafte Bild abrufen

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)')

Digest in der Kubernetes-Konfiguration verwenden

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

Versuchen Sie, die Anwendung in GKE bereitzustellen:

kubectl apply -f deploy.yaml

Sehen Sie sich die Arbeitslast in der Console an und notieren Sie sich den Fehler, der angibt, dass die Bereitstellung abgelehnt wurde:

No attestations found that were valid and signed by a key trusted by the attestor

Signiertes Image bereitstellen

Image-Digest für das fehlerhafte Bild abrufen

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)')

Digest in der Kubernetes-Konfiguration verwenden

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

Stellen Sie die Anwendung in GKE bereit:

kubectl apply -f deploy.yaml

Sehen Sie sich die Arbeitslast in der Console an und notieren Sie sich die erfolgreiche Bereitstellung des Images.

10. Glückwunsch!

Herzlichen Glückwunsch! Sie haben das Codelab abgeschlossen.

Behandelte Themen:

  • Automatisches Scannen aktivieren
  • On-Demand-Scans durchführen
  • Scannen in eine Build-Pipeline einbinden
  • Genehmigte Bilder signieren
  • GKE-Zugangs-Controller zum Blockieren von Images verwenden
  • GKE so konfigurieren, dass nur signierte, genehmigte Images zugelassen werden

Nächste Schritte:

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, können Sie entweder das Projekt löschen, das die Ressourcen enthält, oder das Projekt beibehalten und die einzelnen Ressourcen löschen.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten durch Löschen des für die Anleitung erstellten Projekts.