Erste Umgebung für Confidential Space erstellen


In diesem Leitfaden möchten Alex und Bola herausfinden, wer das höchste Gehalt hat, ohne sich gegenseitig die Zahlen offenzulegen. Sie entscheiden sich für die Nutzung von Confidential Space, um ihre Daten vertraulich zu behandeln, und einigen sich darauf, die folgenden Rollen anzunehmen:

  • Alex: Datenmitbearbeiter, Arbeitslastautor

  • Bola: Datenmitbearbeiter, Arbeitslastoperator

Diese Anordnung soll die Dinge in diesem Leitfaden so einfach wie möglich machen. Die Autoren und Operatoren von Arbeitslasten können jedoch völlig unabhängig von den Datenmitbearbeitern sein und Sie können so viele Mitbearbeiter haben, wie Sie möchten.

Hinweise

In dieser Anleitung wird ein Confidential Space-Szenario mit einem einzelnen Konto in einer einzelnen Organisation mit Zugriff auf mehrere Projekte veranschaulicht, sodass Sie den gesamten Prozess durchlaufen können. Bei einer Produktionsbereitstellung haben Mitbearbeiter, Arbeitslastautoren und Arbeitslastoperatoren separate Konten und ihre eigenen Projekte in eigenständigen Organisationen, die nicht füreinander zugänglich sind und ihre vertraulichen Daten getrennt halten.

Confidential Space kann mit vielen Diensten von Google Cloudinteragieren, um seine Ergebnisse zu erzielen, einschließlich, aber nicht beschränkt auf:

In dieser Anleitung werden alle diese Features verwendet und grundlegende Kenntnisse von ihnen vorausgesetzt.

Erforderliche APIs

Sie müssen die folgenden APIs in den angegebenen Projekten aktivieren, um diesen Leitfaden ausführen zu können.

API-Name API-Titel In diesen Projekten aktivieren
cloudkms.googleapis.com Cloud KMS Datenmitbearbeiter (Projekte von Alex und Bola)
iamcredentials.googleapis.com IAM Service Account Credentials API

Daten-Mitbearbeiter (Projekt von Alex)

In dieser Anleitung muss diese API nur für Alex aktiviert sein. Wenn jedoch mehr als zwei Parteien beteiligt sind, muss die IAM Service Account Credentials API in jedem Projekt der Datenbearbeiter aktiviert sein, in dem das Arbeitslast-Dienstkonto nicht gehostet wird.

artifactregistry.googleapis.com Artifact Registry Autor der Arbeitslast (Projekt von Alex)
compute.googleapis.com Compute Engine Arbeitslastoperator (Projekt von Bola)
confidentialcomputing.googleapis.com Confidential Computing Arbeitslastoperator (Projekt von Bola)

Erforderliche Rollen

Bitten Sie Ihren Administrator, Ihnen die folgenden IAM-Rollen für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Ausführen dieser Anleitung benötigen:

  • Cloud KMS-Administrator (roles/cloudkms.admin) für die Datenmitbearbeiter (Alex und Bola).
  • IAM Workload Identity-Pooladministrator (roles/iam.workloadIdentityPoolAdmin) für die Datenmitbearbeiter (Alex und Bola).
  • Service Usage-Administrator (roles/serviceusage.serviceUsageAdmin) für die Datenmitbearbeiter (Alex und Bola).
  • Dienstkontoadministrator (roles/iam.serviceAccountAdmin) für die Datenmitbearbeiter (Alex und Bola).
  • Storage-Administrator (roles/storage.admin) für die Datenmitbearbeiter (Alex und Bola) und den Arbeitslastoperator (Bola).
  • Compute-Administrator (roles/compute.admin) für den Arbeitslastoperator (Bola).
  • Sicherheitsadministrator (roles/securityAdmin) für den Arbeitslastoperator (Bola).
  • Artifact Registry-Administrator (roles/artifactregistry.admin) für den Arbeitslastautor (Alex)

Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

Ressourcen für Datenmitbearbeiter einrichten

Sowohl Alex als auch Bola benötigen unabhängige Projekte, die die folgenden Ressourcen enthalten:

  • Die vertraulichen Daten selbst.

  • Einen Verschlüsselungsschlüssel, um diese Daten zu verschlüsseln und vertraulich zu halten.

  • Ein Cloud Storage-Bucket, in dem die verschlüsselten Daten gespeichert werden.

  • Ein Dienstkonto, das Zugriff auf den Verschlüsselungsschlüssel hat, sodass es die vertraulichen Daten entschlüsseln kann.

  • Einen Workload Identity-Pool, mit dem dieses Dienstkonto verknüpft ist. Die Arbeitslast, die die vertraulichen Daten verarbeitet, verwendet den Pool, um sich als Dienstkonto auszugeben und die unverschlüsselten Daten abzurufen.

Rufen Sie zuerst die Google Cloud Console auf:

Google Cloud -Console aufrufen

Ressourcen für Alex einrichten

Führen Sie die folgenden Schritte aus, um die Ressourcen für Alex einzurichten.

  1. Klicken Sie auf Cloud Shell aktivieren.
  2. Geben Sie in Cloud Shell den folgenden Befehl ein, um ein Projekt für Alex zu erstellen. Ersetzen Sie dabei ALEX_PROJECT_ID durch einen beliebigen Namen:

    gcloud projects create ALEX_PROJECT_ID
  3. Wechseln Sie zum neu erstellten Projekt:

    gcloud config set project ALEX_PROJECT_ID
  4. Aktivieren Sie die APIs, die Alex als Datenmitbearbeiter und Arbeitslastautor benötigt, falls Sie dies noch nicht getan haben:

    gcloud services enable cloudkms.googleapis.com artifactregistry.googleapis.com iamcredentials.googleapis.com
  5. So erstellen Sie einen Schlüsselbund und einen Verschlüsselungsschlüssel mit dem Cloud Key Management Service:

    gcloud kms keyrings create ALEX_KEYRING_NAME \
        --location=global
    gcloud kms keys create ALEX_KEY_NAME \
        --location=global \
        --keyring=ALEX_KEYRING_NAME \
        --purpose=encryption
  6. Gewähren Sie Alex die Rolle cloudkms.cryptoKeyEncrypter, damit er den neu erstellten Verschlüsselungsschlüssel zum Verschlüsseln von Daten verwenden kann:

    gcloud kms keys add-iam-policy-binding \
        projects/ALEX_PROJECT_ID/locations/global/keyRings/ALEX_KEYRING_NAME/cryptoKeys/ALEX_KEY_NAME \
        --member=user:$(gcloud config get-value account) \
        --role=roles/cloudkms.cryptoKeyEncrypter
  7. Erstellen Sie ein Dienstkonto, das später von der Arbeitslast zum Entschlüsseln der Daten verwendet wird:

    gcloud iam service-accounts create ALEX_SERVICE_ACCOUNT_NAME
  8. Weisen Sie dem Dienstkonto die Rolle cloudkms.cryptoKeyDecrypter zu, damit es den von Ihnen erstellten Verschlüsselungsschlüssel zum Entschlüsseln von Daten verwenden kann:

    gcloud kms keys add-iam-policy-binding \
        projects/ALEX_PROJECT_ID/locations/global/keyRings/ALEX_KEYRING_NAME/cryptoKeys/ALEX_KEY_NAME \
        --member=serviceAccount:ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/cloudkms.cryptoKeyDecrypter
  9. Erstellen Sie einen Workload Identity-Pool und verknüpfen Sie das Dienstkonto mit der Rolle iam.workloadIdentityUser:

    gcloud iam workload-identity-pools create ALEX_POOL_NAME \
        --location=global
    gcloud iam service-accounts add-iam-policy-binding \
        ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com \
        --member="principalSet://iam.googleapis.com/projects/"$(gcloud projects describe ALEX_PROJECT_ID \
            --format="value(projectNumber)")"/locations/global/workloadIdentityPools/ALEX_POOL_NAME/*" \
        --role=roles/iam.workloadIdentityUser
  10. Erstellen Sie einen Cloud Storage-Bucket für die Eingabedaten und einen weiteren, in dem die Ergebnisse gespeichert werden:

    gcloud storage buckets create gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME
  11. Erstellen Sie eine Datei, die nur das Gehalt von Alex als Zahl enthält:

    echo 123456 > ALEX_SALARY.txt
  12. Verschlüsseln Sie die Datei und laden Sie sie in den Bucket von Alex hoch:

    gcloud kms encrypt \
        --ciphertext-file="ALEX_ENCRYPTED_SALARY_FILE" \
        --plaintext-file="ALEX_SALARY.txt" \
        --key=projects/ALEX_PROJECT_ID/locations/global/keyRings/ALEX_KEYRING_NAME/cryptoKeys/ALEX_KEY_NAME
    gcloud storage cp ALEX_ENCRYPTED_SALARY_FILE gs://ALEX_INPUT_BUCKET_NAME

Ressourcen für Bola einrichten

Führen Sie die folgenden Anweisungen aus, um die Ressourcen für Bola einzurichten.

  1. Geben Sie in Cloud Shell den folgenden Befehl ein, um ein Projekt für Bola zu erstellen. Ersetzen Sie dabei BOLA_PROJECT_ID durch einen beliebigen Namen:

    gcloud projects create BOLA_PROJECT_ID
  2. Wechseln Sie zum neu erstellten Projekt:

    gcloud config set project BOLA_PROJECT_ID
  3. Aktivieren Sie die APIs, die Bola als Datenmitbearbeiter und Arbeitslastoperator benötigt, falls Sie dies noch nicht getan haben:

    gcloud services enable cloudkms.googleapis.com compute.googleapis.com confidentialcomputing.googleapis.com
  4. So erstellen Sie einen Schlüsselbund und einen Verschlüsselungsschlüssel mit dem Cloud Key Management Service:

    gcloud kms keyrings create BOLA_KEYRING_NAME \
        --location=global
    gcloud kms keys create BOLA_KEY_NAME \
        --location=global \
        --keyring=BOLA_KEYRING_NAME \
        --purpose=encryption
  5. Gewähren Sie Bola die Rolle cloudkms.cryptoKeyEncrypter, damit er den neu erstellten Verschlüsselungsschlüssel zum Verschlüsseln von Daten verwenden kann:

    gcloud kms keys add-iam-policy-binding \
        projects/BOLA_PROJECT_ID/locations/global/keyRings/BOLA_KEYRING_NAME/cryptoKeys/BOLA_KEY_NAME \
        --member=user:$(gcloud config get-value account) \
        --role=roles/cloudkms.cryptoKeyEncrypter
  6. Erstellen Sie ein Dienstkonto, das später von der Arbeitslast zum Entschlüsseln der Daten verwendet wird:

    gcloud iam service-accounts create BOLA_SERVICE_ACCOUNT_NAME
  7. Weisen Sie dem Dienstkonto die Rolle cloudkms.cryptoKeyDecrypter zu, damit es den von Ihnen erstellten Verschlüsselungsschlüssel zum Entschlüsseln von Daten verwenden kann:

    gcloud kms keys add-iam-policy-binding \
        projects/BOLA_PROJECT_ID/locations/global/keyRings/BOLA_KEYRING_NAME/cryptoKeys/BOLA_KEY_NAME \
        --member=serviceAccount:BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/cloudkms.cryptoKeyDecrypter
  8. Erstellen Sie einen Workload Identity-Pool und verknüpfen Sie das Dienstkonto mit der Rolle iam.workloadIdentityUser:

    gcloud iam workload-identity-pools create BOLA_POOL_NAME \
        --location=global
    gcloud iam service-accounts add-iam-policy-binding \
        BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --member="principalSet://iam.googleapis.com/projects/"$(gcloud projects describe BOLA_PROJECT_ID \
            --format="value(projectNumber)")"/locations/global/workloadIdentityPools/BOLA_POOL_NAME/*" \
        --role=roles/iam.workloadIdentityUser
  9. Erstellen Sie einen Cloud Storage-Bucket für die Eingabedaten und einen weiteren, in dem die Ergebnisse gespeichert werden:

    gcloud storage buckets create gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME
  10. Erstellen Sie eine Datei, die nur das Gehalt von Bola als Zahl enthält:

    echo 111111 > BOLA_SALARY.txt
  11. Verschlüsseln Sie die Datei und laden Sie sie in den Bucket von Bola hoch:

    gcloud kms encrypt \
        --ciphertext-file="BOLA_ENCRYPTED_SALARY_FILE" \
        --plaintext-file="BOLA_SALARY.txt" \
        --key=projects/BOLA_PROJECT_ID/locations/global/keyRings/BOLA_KEYRING_NAME/cryptoKeys/BOLA_KEY_NAME
    gcloud storage cp BOLA_ENCRYPTED_SALARY_FILE gs://BOLA_INPUT_BUCKET_NAME

Dienstkonto für die Arbeitslast erstellen

Zusätzlich zu den Dienstkonten, die Alex und Bola zum Entschlüsseln ihrer Daten eingerichtet haben, ist ein weiteres Dienstkonto erforderlich, um die Arbeitslast auszuführen. Da Dienstkonten sowohl zum Entschlüsseln als auch zum Verarbeiten dieser vertraulichen Daten verwendet werden, ist die Sichtbarkeit der Daten auf ihre Inhaber beschränkt.

In dieser Anleitung wird die Arbeitslast von Bola betrieben und ausgeführt. Jedoch kann jeder diese Rollen übernehmen, auch ein Dritter.

Führen Sie im Projekt von Bola die folgenden Schritte aus, um das Dienstkonto einzurichten:

  1. Erstellen Sie ein Dienstkonto, um die Arbeitslast auszuführen:

    gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAME
    
  2. Weisen Sie Bola die Rolle iam.serviceAccountUser zu, um die Identität des Dienstkontos zu übernehmen. Dies ist erforderlich, damit er später eine Arbeitslast-VM erstellen kann:

    gcloud iam service-accounts add-iam-policy-binding \
        WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --member=user:$(gcloud config get-value account) \
        --role=roles/iam.serviceAccountUser
    
  3. Weisen Sie dem Dienstkonto die Rolle confidentialcomputing.workloadUser zu, damit es ein Attestierungstoken generieren kann:

    gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/confidentialcomputing.workloadUser
    
  4. Weisen Sie dem Dienstkonto die Rolle logging.logWriter zu, damit es Protokolle in Cloud Logging schreiben und Sie so den Fortschritt der Arbeitslast prüfen können:

    gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/logging.logWriter
    
  5. Gewähren Sie dem Dienstkonto Lesezugriff auf die beiden Buckets von Alex und Bola, die ihre verschlüsselten Daten enthalten, und Schreibzugriff auf jeden ihrer Ergebnis-Buckets:

    gcloud storage buckets add-iam-policy-binding gs://ALEX_INPUT_BUCKET_NAME \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/storage.objectViewer
    
    gcloud storage buckets add-iam-policy-binding gs://BOLA_INPUT_BUCKET_NAME \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/storage.objectViewer
    
    gcloud storage buckets add-iam-policy-binding gs://ALEX_RESULTS_BUCKET_NAME \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/storage.objectAdmin
    
    gcloud storage buckets add-iam-policy-binding gs://BOLA_RESULTS_BUCKET_NAME \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/storage.objectAdmin
    

    Dabei wird davon ausgegangen, dass der Nutzer, der den Zugriff gewährt, die Rolle „Storage-Administrator“ (roles/storage.admin) für das Projekt hat, das den Cloud Storage-Bucket enthält, auf den zugegriffen wird.

Arbeitslast erstellen

In dieser Anleitung stellt Alex den Code für die Arbeitslast bereit und erstellt ein Docker-Image, der ihn enthalten soll. Jedoch kann jeder diese Rollen übernehmen, auch ein Dritter.

Alex muss die folgenden Ressourcen für die Arbeitslast erstellen:

  • Den Code, der die Arbeitslast ausführt.

  • Ein Docker-Repository in Artifact Registry, auf das das Dienstkonto Zugriff hat, das die Arbeitslast ausführt.

  • Ein Docker-Image, das den Arbeitslastcode enthält und ausführt.

Führen Sie die folgenden Schritte in Alex' Projekt aus, um die Ressourcen zu erstellen und einzurichten:

  1. Wechseln Sie zu Alex' Projekt:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Docker-Repository in Artifact Registry erstellen

    gcloud artifacts repositories create REPOSITORY_NAME \
        --repository-format=docker \
        --location=us
    
  3. Gewähren Sie dem Dienstkonto, das die Arbeitslast ausführen wird, die Rolle "Artifact Registry-Leser" (roles/artifactregistry.reader), damit es aus dem Repository lesen kann:

    gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
        --location=us \
        --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/artifactregistry.reader
    
  4. Klicken Sie auf Editor öffnen, um den Cloud Shell-Editor zu öffnen, und erstellen Sie dann eine neue Datei namens salary.go. Kopieren Sie den folgenden Code in die Datei und speichern Sie sie dann:

    // READ ME FIRST: Before compiling, customize the details in the USER VARIABLES
    // SECTION starting at line 30.
    
    package main
    
    import (
      kms "cloud.google.com/go/kms/apiv1"
      "cloud.google.com/go/storage"
      "context"
      "fmt"
      "google.golang.org/api/option"
      kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
      "io/ioutil"
      "strconv"
      "strings"
      "time"
    )
    
    type collaborator struct {
      name         string
      wipName      string
      sa           string
      keyName      string
      inputBucket  string
      inputFile    string
      outputBucket string
      outputFile   string
    }
    
    // ============================
    // START USER VARIABLES SECTION
    // You need to customize this section, replacing each const's value with your
    // own.
    
    // To get a project number, use the following command, and substitute
    // <PROJECT_ID> for the data collaborator's project ID.
    // gcloud projects describe <PROJECT_ID> --format="value(projectNumber)"
    
    // Alex's values
    const collaborator1Name string = "Alex"                // Alex's name
    const collaborator1EncryptedSalaryFileName string = "" // The name of Alex's encrypted salary file
    const collaborator1BucketInputName string = ""         // The name of the storage bucket that contains Alex's encrypted salary file
    const collaborator1BucketOutputName string = ""        // The name of the storage bucket to store Alex's results in
    const collaborator1BucketOutputFileName string = ""    // The name of Alex's output file that contains the results
    const collaborator1KMSKeyringName string = ""          // Alex's Key Management Service key ring
    const collaborator1KMSKeyName string = ""              // Alex's Key Management Service key
    const collaborator1ProjectName string = ""             // Alex's project ID
    const collaborator1ProjectNumber string = ""           // Alex's project number
    const collaborator1PoolName string = ""                // Alex's workload identity pool name
    const collaborator1ServiceAccountName string = ""      // The name of Alex's service account that can decrypt their salary
    
    // Bola's values
    const collaborator2Name string = "Bola"                // Bola's name
    const collaborator2EncryptedSalaryFileName string = "" // The name of Bola's encrypted salary file
    const collaborator2BucketInputName string = ""         // The name of the storage bucket that contains Bola's encrypted salary file
    const collaborator2BucketOutputName string = ""        // The name of the storage bucket to store Bola's results in
    const collaborator2BucketOutputFileName string = ""    // The name of Bola's output file that contains the results
    const collaborator2KMSKeyringName string = ""          // Bola's Key Management Service key ring
    const collaborator2KMSKeyName string = ""              // Bola's Key Management Service key
    const collaborator2ProjectName string = ""             // Bola's project ID
    const collaborator2ProjectNumber string = ""           // Bola's project number
    const collaborator2PoolName string = ""                // Bola's workload identity pool name
    const collaborator2ServiceAccountName string = ""      // The name of Bola's service account that can decrypt their salary
    
    // END USER VARIABLES SECTION
    // ==========================
    
    var collaborators = [2]collaborator{
      {
        collaborator1Name,
        "projects/" + collaborator1ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator1PoolName + "/providers/attestation-verifier",
        collaborator1ServiceAccountName + "@" + collaborator1ProjectName + ".iam.gserviceaccount.com",
        "projects/" + collaborator1ProjectName + "/locations/global/keyRings/" + collaborator1KMSKeyringName + "/cryptoKeys/" + collaborator1KMSKeyName,
        collaborator1BucketInputName,
        collaborator1EncryptedSalaryFileName,
        collaborator1BucketOutputName,
        collaborator1BucketOutputFileName,
      },
      {
        collaborator2Name,
        "projects/" + collaborator2ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator2PoolName + "/providers/attestation-verifier",
        collaborator2ServiceAccountName + "@" + collaborator2ProjectName + ".iam.gserviceaccount.com",
        "projects/" + collaborator2ProjectName + "/locations/global/keyRings/" + collaborator2KMSKeyringName + "/cryptoKeys/" + collaborator2KMSKeyName,
        collaborator2BucketInputName,
        collaborator2EncryptedSalaryFileName,
        collaborator2BucketOutputName,
        collaborator2BucketOutputFileName,
      },
    }
    
    const credentialConfig = `{
            "type": "external_account",
            "audience": "//iam.googleapis.com/%s",
            "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
            "token_url": "https://sts.googleapis.com/v1/token",
            "credential_source": {
              "file": "/run/container_launcher/attestation_verifier_claims_token"
            },
            "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:generateAccessToken"
            }`
    
    func main() {
      fmt.Println("workload started")
      ctx := context.Background()
    
      storageClient, err := storage.NewClient(ctx) // using the default credential on the Compute Engine VM
      if err != nil {
        panic(err)
      }
    
      // get and decrypt
      s0, err := getSalary(ctx, storageClient, collaborators[0])
      if err != nil {
        panic(err)
      }
    
      s1, err := getSalary(ctx, storageClient, collaborators[1])
      if err != nil {
        panic(err)
      }
    
      res := ""
      if s0 > s1 {
        res = fmt.Sprintf("%s earns more!\n", collaborators[0].name)
      } else if s1 < s0 {
        res = fmt.Sprintf("%s earns more!\n", collaborators[1].name)
      } else {
        res = "earns same\n"
      }
    
      now := time.Now()
      for _, cw := range collaborators {
        outputWriter := storageClient.Bucket(cw.outputBucket).Object(fmt.Sprintf("%s-%d", cw.outputFile, now.Unix())).NewWriter(ctx)
    
        _, err = outputWriter.Write([]byte(res))
        if err != nil {
          fmt.Printf("Could not write: %v", err)
          panic(err)
        }
        if err = outputWriter.Close(); err != nil {
          fmt.Printf("Could not close: %v", err)
          panic(err)
        }
      }
    }
    
    func getSalary(ctx context.Context, storageClient *storage.Client, cw collaborator) (float64, error) {
      encryptedBytes, err := getFile(ctx, storageClient, cw.inputBucket, cw.inputFile)
      if err != nil {
        return 0.0, err
      }
      decryptedByte, err := decryptByte(ctx, cw.keyName, cw.sa, cw.wipName, encryptedBytes)
      if err != nil {
        return 0.0, err
      }
      decryptedNumber := strings.TrimSpace(string(decryptedByte))
      num, err := strconv.ParseFloat(decryptedNumber, 64)
      if err != nil {
        return 0.0, err
      }
      return num, nil
    }
    
    func decryptByte(ctx context.Context, keyName, trustedServiceAccountEmail, wippro string, encryptedData []byte) ([]byte, error) {
      cc := fmt.Sprintf(credentialConfig, wippro, trustedServiceAccountEmail)
      kmsClient, err := kms.NewKeyManagementClient(ctx, option.WithCredentialsJSON([]byte(cc)))
      if err != nil {
        return nil, fmt.Errorf("creating a new KMS client with federated credentials: %w", err)
      }
    
      decryptRequest := &kmspb.DecryptRequest{
        Name:       keyName,
        Ciphertext: encryptedData,
      }
      decryptResponse, err := kmsClient.Decrypt(ctx, decryptRequest)
      if err != nil {
        return nil, fmt.Errorf("could not decrypt ciphertext: %w", err)
      }
    
      return decryptResponse.Plaintext, nil
    }
    
    func getFile(ctx context.Context, c *storage.Client, bucketName string, objPath string) ([]byte, error) {
      bucketHandle := c.Bucket(bucketName)
      objectHandle := bucketHandle.Object(objPath)
    
      objectReader, err := objectHandle.NewReader(ctx)
      if err != nil {
        return nil, err
      }
      defer objectReader.Close()
    
      s, err := ioutil.ReadAll(objectReader)
      if err != nil {
        return nil, err
      }
    
      return s, nil
    }
    
  5. Ändern Sie die USER VARIABLES SECTION im Quellcode und ersetzen Sie die leeren const-Werte durch die entsprechenden Ressourcennamen, wie in den Codekommentaren beschrieben. Wenn Sie die Platzhaltervariablen wie ALEX_PROJECT_ID in diesem Leitfaden bearbeitet haben, sind die Werte im folgenden Codebeispiel enthalten. Sie können es kopieren und über den vorhandenen Code einfügen:

    // Alex's values
    const collaborator1Name string = "Alex"                                            // Alex's name
    const collaborator1EncryptedSalaryFileName string = "ALEX_ENCRYPTED_SALARY_FILE" // The name of Alex's encrypted salary file
    const collaborator1BucketInputName string = "ALEX_INPUT_BUCKET_NAME"             // The name of the storage bucket that contains Alex's encrypted salary file
    const collaborator1BucketOutputName string = "ALEX_RESULTS_BUCKET_NAME"          // The name of the storage bucket to store Alex's results in
    const collaborator1BucketOutputFileName string = "ALEX_RESULTS_FILE_NAME"        // The name of Alex's output file that contains the results
    const collaborator1KMSKeyringName string = "ALEX_KEYRING_NAME"                   // Alex's Key Management Service key ring
    const collaborator1KMSKeyName string = "ALEX_KEY_NAME"                           // Alex's Key Management Service key
    const collaborator1ProjectName string = "ALEX_PROJECT_ID"                        // Alex's project ID
    const collaborator1ProjectNumber string = "ALEX_PROJECT_NUMBER"                  // Alex's project number
    const collaborator1PoolName string = "ALEX_POOL_NAME"                            // Alex's workload identity pool name
    const collaborator1ServiceAccountName string = "ALEX_SERVICE_ACCOUNT_NAME"       // The name of Alex's service account that can decrypt their salary
    
    // Bola's values
    const collaborator2Name string = "Bola"                                            // Bola's name
    const collaborator2EncryptedSalaryFileName string = "BOLA_ENCRYPTED_SALARY_FILE" // The name of Bola's encrypted salary file
    const collaborator2BucketInputName string = "BOLA_INPUT_BUCKET_NAME"             // The name of the storage bucket that contains Bola's encrypted salary file
    const collaborator2BucketOutputName string = "BOLA_RESULTS_BUCKET_NAME"          // The name of the storage bucket to store Bola's results in
    const collaborator2BucketOutputFileName string = "BOLA_RESULTS_FILE_NAME"        // The name of Bola's output file that contains the results
    const collaborator2KMSKeyringName string = "BOLA_KEYRING_NAME"                   // Bola's Key Management Service key ring
    const collaborator2KMSKeyName string = "BOLA_KEY_NAME"                           // Bola's Key Management Service key
    const collaborator2ProjectName string = "BOLA_PROJECT_ID"                        // Bola's project ID
    const collaborator2ProjectNumber string = "BOLA_PROJECT_NUMBER"                  // Bola's project number
    const collaborator2PoolName string = "BOLA_POOL_NAME"                            // Bola's workload identity pool name
    const collaborator2ServiceAccountName string = "BOLA_SERVICE_ACCOUNT_NAME"       // The name of Bola's service account that can decrypt their salary
    

    Aktualisieren Sie auch die Projektnummern für Alex und Bola. Sie können sie mit dem folgenden Befehl abrufen:

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  6. Achten Sie darauf, dass alle Beteiligten den Quellcode lesen und prüfen.

  7. Klicken Sie auf Terminal > Neues Terminal, um ein Terminal im Cloud Shell-Editor zu öffnen.

  8. Geben Sie die folgenden Befehle in das Terminal ein, um die Go-Umgebung einzurichten:

    go mod init salary
    go get cloud.google.com/go/kms/apiv1 cloud.google.com/go/storage google.golang.org/api/option google.golang.org/genproto/googleapis/cloud/kms/v1
    
  9. Geben Sie den folgenden Befehl ein, um den Quellcode in einer statisch verknüpften Binärdatei zu kompilieren:

    CGO_ENABLED=0 go build -trimpath
    
  10. Erstellen Sie im Cloud Shell-Editor eine Datei mit dem Namen Dockerfile und folgendem Inhalt:

    FROM alpine:latest
    WORKDIR /test
    COPY salary /test
    ENTRYPOINT ["/test/salary"]
    CMD []
    
  11. Aktualisieren Sie Ihre Docker-Anmeldedaten, um den Domainnamen us-docker.pkg.dev einzuschließen:

    gcloud auth configure-docker us-docker.pkg.dev
    
  12. Erstellen Sie ein Docker-Image aus Dockerfile, indem Sie im Terminal den folgenden Befehl eingeben:

    docker build -t \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest .
    
  13. Übertragen Sie das Docker-Image per Push an Artifact Registry:

    docker push \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME
    
  14. Kopieren Sie aus der Docker-Push-Antwort den Digest des Docker-Images (einschließlich des Präfixes sha256:) an einen sicheren Ort, um ihn später verwenden zu können.

  15. Sorgen Sie dafür, dass alle Parteien das Docker-Image prüfen und verifizieren, dass es vertrauenswürdig ist, bevor sie die Verwendung autorisieren.

Arbeitslast autorisieren

Mit der von beiden Parteien genehmigten Arbeitslast müssen Alex und Bola den Dienst zur Confidential Space-Attestierungsprüfung als Anbieter zu ihren Workload Identity-Pools hinzufügen. Dadurch kann das mit der Arbeitslast verknüpfte Dienstkonto die Identität der Dienstkonten übernehmen, die mit ihren Pools verbunden sind, und auf ihre Daten zugreifen, vorausgesetzt, bestimmte Attributbedingungen sind erfüllt. Die Attributbedingungen fungieren also als Attestierungsrichtlinien.

In diesem Leitfaden werden die folgenden Attributbedingungen verwendet:

  • Der Digest des ausgeführten Docker-Images

  • Die E-Mail-Adresse des Dienstkontos, mit dem die Arbeitslast ausgeführt wird

Wenn ein böswilliger Akteur das Docker-Image ändert oder ein anderes Dienstkonto an die Arbeitslast angehängt ist, wird der Arbeitslast kein Zugriff auf die Daten von Alex oder Bola gewährt.

Informationen zu den verfügbaren Attestationsaussagen finden Sie unter Attestationsaussagen.

So richten Sie die Anbieter für Alex und Bola mit den erforderlichen Bedingungen ein:

  1. Geben Sie den folgenden Befehl ein, um den Anbieter für Alex zu erstellen:

    gcloud iam workload-identity-pools providers create-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=ALEX_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE' \
    && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    
  2. Zum Projekt von Bola wechseln:

    gcloud config set project BOLA_PROJECT_ID
    
  3. Geben Sie den folgenden Befehl ein, um den Anbieter für Bola zu erstellen:

    gcloud iam workload-identity-pools providers create-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=BOLA_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE' \
    && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    

Arbeitslast bereitstellen

Da nun sowohl dem Workload Identity-Pool von Alex als auch dem von Bola Anbieter hinzugefügt wurden, ist es Zeit, dass der Arbeitslastoperator die Arbeitslast ausführt.

Um die Arbeitslast bereitzustellen, erstellen Sie im Projekt von Bola eine neue Confidential VM-Instanz mit den folgenden Eigenschaften:

  • Eine unterstützte Konfiguration für eine AMD SEV- oder Intel TDX Confidential VM-Instanz.

  • Ein Betriebssystem, das auf dem Confidential Space-Image basiert.

  • Aktiviertes Secure Boot.

  • Das angehängte Docker-Image, das zuvor von Alex erstellt wurde.

  • Das angehängte Dienstkonto, mit dem die Arbeitslast ausgeführt wird.

Geben Sie den folgenden Befehl in der Cloud Shell von Bola ein, um die Arbeitslast bereitzustellen:

gcloud compute instances create WORKLOAD_VM_NAME \
    --confidential-compute-type=SEV \
    --shielded-secure-boot \
    --scopes=cloud-platform \
    --zone=us-west1-b \
    --maintenance-policy=MIGRATE \
    --min-cpu-platform="AMD Milan" \
    --image-project=confidential-space-images \
    --image-family=confidential-space \
    --service-account=WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
    --metadata="^~^tee-image-reference=us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest"

Sie können den Fortschritt der Arbeitslast im Projekt von Bola ansehen. Rufen Sie dazu den Logs-Explorer auf.

Zum Log-Explorer

Wenn Sie die Confidential Space-Logs finden möchten, filtern Sie nach den folgenden Logfeldern, sofern verfügbar:

  • Ressourcentyp:VM-Instanz

  • Instanz-ID: Die Instanz-ID der VM

  • Logname: confidential-space-launcher

Klicken Sie auf Zu jetzt springen, um das Protokoll zu aktualisieren.

Wenn die Arbeitslast abgeschlossen ist, wird die VM-Instanz beendet. Wenn Sie die verschlüsselten Gehaltsdateien ändern und die Arbeitslast noch einmal bereitstellen möchten, müssen Sie nur die vorhandene VM starten:

gcloud compute instances start WORKLOAD_VM_NAME --zone=us-west1-b

Arbeitslast debuggen

Sie können mit dem Log-Explorer auch Probleme beheben, z. B. Ressourcen, die nicht korrekt eingerichtet sind, oder Attributbedingungen in Anbietern, die nicht den Anforderungen der Confidential Space-Arbeitslast entsprechen.

Dazu müssen Sie die folgenden Änderungen vornehmen:

  • Aktualisieren Sie die Anbieter der Workload Identity-Pools von Alex und Bola, um die support_attributes-Behauptung zu entfernen. Sie müssen das Debug-Image für Confidential Space verwenden, um eine umfassendere Fehlerbehebung durchzuführen. Dieses Image hat keine zu prüfenden Supportattribute.

  • Erstellen Sie die Arbeitslast-VM mit dem Debug-Image für den Confidential Space und legen Sie die VM-Metadaten so fest, dass STDOUT und STDERR an Cloud Logging weitergeleitet werden, um die gesamte Ausgabe der Arbeitslast zu erfassen.

So nehmen Sie die Änderungen vor:

  1. Wechseln Sie zu Alex' Projekt:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Aktualisieren Sie den Anbieter von Alex, um die support_attributes-Behauptung zu entfernen:

    gcloud iam workload-identity-pools providers update-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=ALEX_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  3. Zum Projekt von Bola wechseln:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Aktualisieren Sie den Anbieter von Bola, um die support_attributes-Bestätigung zu entfernen:

    gcloud iam workload-identity-pools providers update-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=BOLA_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  5. Erstellen Sie eine neue VM mit dem Debug-Image für den Confidential Space und legen Sie in den Metadaten tee-container-log-redirect auf true fest.

    gcloud compute instances create WORKLOAD_VM_2_NAME \
        --confidential-compute-type=SEV \
        --shielded-secure-boot \
        --scopes=cloud-platform \
        --zone=us-west1-b \
        --maintenance-policy=MIGRATE \
        --min-cpu-platform="AMD Milan" \
        --image-project=confidential-space-images \
        --image-family=confidential-space-debug \
        --service-account=WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --metadata="^~^tee-image-reference=us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest~tee-container-log-redirect=true"
    

Im Gegensatz zum Produktions-Image bleibt die VM mit dem Debugging-Image nach Abschluss der Arbeitslast aktiv. Sie können also SSH verwenden, um eine Verbindung zu Ihrer VM herzustellen und mit der Fehlerbehebung fortzufahren.

Ergebnisse aufrufen

Nachdem die Arbeitslast erfolgreich abgeschlossen wurde, können sowohl Alex als auch Bola die Ergebnisse in ihren jeweiligen Ergebnis-Buckets ansehen:

  1. Wechseln Sie zu Alex' Projekt:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Listen Sie alle Dateien in seinem Ergebnis-Bucket auf:

    gcloud storage ls gs://ALEX_RESULTS_BUCKET_NAME
    

    Lesen Sie dann die neueste Datei:

    gcloud storage cat gs://ALEX_RESULTS_BUCKET_NAME/ALEX_RESULTS_FILE_NAME
    
  3. Zum Projekt von Bola wechseln:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Listen Sie für Bola alle Dateien in seinem Ergebnis-Bucket auf:

    gcloud storage ls gs://BOLA_RESULTS_BUCKET_NAME
    

    Lesen Sie dann die neueste Datei:

    gcloud storage cat gs://BOLA_RESULTS_BUCKET_NAME/BOLA_RESULTS_FILE_NAME
    

Indem sie die Dateien lesen, stellen Alex und Bola jeweils fest, wer mehr verdient, ohne sich dabei jemals gegenseitig ihre Gehälter offenzulegen.

Bereinigen

Führen Sie die folgenden Schritte aus, um die in dieser Anleitung erstellten Ressourcen zu entfernen.

Ressourcen von Alex bereinigen

  1. Wechseln Sie zu Alex' Projekt:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Löschen Sie das Dienstkonto, das die Daten von Alex entschlüsselt:

    gcloud iam service-accounts delete \
        ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com
    
  3. So löschen Sie den Workload Identity-Pool von Alex:

    gcloud iam workload-identity-pools delete ALEX_POOL_NAME \
        --location=global
    
  4. Löschen Sie die Cloud Storage-Buckets von Alex:

    gcloud storage rm gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME --recursive
    
  5. Löschen Sie die Gehaltsdateien von Alex und den Go-Code:

    rm ALEX_SALARY.txt \
        ALEX_ENCRYPTED_SALARY_FILE \
        salary.go salary \
        go.mod go.sum
    
  6. Optional: Deaktivieren oder löschen Sie den Cloud Key Management Service-Schlüssel von Alex.

  7. Optional: Beenden Sie das Projekt von Alex.

Ressourcen von Bola bereinigen

  1. Zum Projekt von Bola wechseln:

    gcloud config set project BOLA_PROJECT_ID
    
  2. Löschen Sie die Arbeitslast-VM:

    gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-b
    
  3. Löschen Sie das Dienstkonto, das die Daten von Bola entschlüsselt, und das Dienstkonto, das die Arbeitslast ausführt:

    gcloud iam service-accounts delete \
        BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com
    
    gcloud iam service-accounts delete \
        WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com
    
  4. So löschen Sie den Workload Identity-Pool von Bola:

    gcloud iam workload-identity-pools delete BOLA_POOL_NAME \
        --location=global
    
  5. Löschen Sie die Cloud Storage-Buckets von Bola:

    gcloud storage rm gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME --recursive
    
  6. Löschen Sie die Gehaltsdateien von Bola:

    rm BOLA_SALARY.txt \
        BOLA_ENCRYPTED_SALARY_FILE
    
  7. Optional: Deaktivieren oder löschen Sie den Cloud Key Management Service-Schlüssel von Bola.

  8. Optional: Beenden Sie das Projekt von Bola.