Analizzare i dati riservati con Confidential Space

In questa guida, Alex e Bola vogliono scoprire chi ha lo stipendio più alto senza rivelarsi l'uno l'altro. Decide di utilizzare lo spazio riservato per mantenere riservati i propri dati e accetta di assumersi i seguenti ruoli:

  • Alex: collaboratore dati, autore del carico di lavoro
  • Bola: collaboratore dati, operatore del carico di lavoro

Questa disposizione semplifica la vita di questa guida, tuttavia è possibile che l'autore e l'operatore del carico di lavoro siano completamente indipendenti dai collaboratori dei dati e che tu possa avere tutti i collaboratori che vuoi.

Prima di iniziare

Questa guida illustra uno scenario Confidential Space con un singolo account in una singola organizzazione con accesso a più progetti, per consentirti di sperimentare l'intero processo. In un deployment di produzione, collaboratori, autori di carichi di lavoro e operatori dei carichi di lavoro hanno account separati e propri progetti contenuti in organizzazioni discrete, inaccessibili l'uno all'altro e mantenendo separati i dati riservati.

Confidential Space può interagire con molti dei servizi Google Cloud per produrre i suoi risultati, inclusi, a titolo esemplificativo:

Questa guida utilizza e presuppone una conoscenza di base di tutte queste funzionalità.

API obbligatorie

Devi abilitare le API seguenti nei progetti specificati per poter completare questa guida.

Nome API Titolo API Abilita in questi progetti
cloudkms.googleapis.com Cloud KMS Collaboratori di dati (progetti di Alex e Bola)
iamcredentials.googleapis.com API IAM Service Account Credentials

Collaboratori di dati (progetto di Alex)

In questa guida, solo Alex ha bisogno di abilitare questa API. Tuttavia, se sono coinvolte più di due parti, l'API IAM Service Account Credentials deve essere abilitata sul progetto di ogni collaboratore di dati che non ospita l'account di servizio del carico di lavoro.

artifactregistry.googleapis.com Artifact Registry Autore carico di lavoro (progetto Alex)
compute.googleapis.com Compute Engine Operatore carico di lavoro (progetto Bob)
confidentialcomputing.googleapis.com Confidential Computing Operatore carico di lavoro (progetto Bob)

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per completare questa guida, chiedi all'amministratore di concederti i seguenti ruoli IAM sul progetto:

  • Amministratore Cloud KMS (roles/cloudkms.admin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore pool Workload Identity IAM (roles/iam.workloadIdentityPoolAdmin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore utilizzo dei servizi (roles/serviceusage.serviceUsageAdmin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore account di servizio (roles/iam.serviceAccountAdmin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore spazio di archiviazione (roles/storage.admin) per i collaboratori dei dati (Alex e Bola) e per l'operatore del carico di lavoro (Bola).
  • Amministratore Compute (roles/compute.admin) per l'operatore del carico di lavoro (Bola).
  • Amministratore sicurezza (roles/securityAdmin) per l'operatore del carico di lavoro (Bola).
  • Amministratore Artifact Registry (roles/artifactregistry.admin) per l'autore del carico di lavoro (Alex).

Per maggiori informazioni sulla concessione dei ruoli, vedi Gestire l'accesso.

Potresti anche ottenere le autorizzazioni richieste tramite ruoli personalizzati o altri ruoli predefiniti.

Configurare le risorse per i collaboratori dei dati

Alex e Bola hanno bisogno di progetti indipendenti che contengano le seguenti risorse:

  • I dati riservati stessi.

  • Una chiave di crittografia per criptare questi dati e mantenerli riservati.

  • Un bucket Cloud Storage in cui archiviare i dati criptati.

  • Un account di servizio che ha accesso alla chiave di crittografia, in modo da poter decriptare i dati riservati.

  • Un pool di Workload Identity con quell'account di servizio connesso. Il carico di lavoro che elabora i dati riservati utilizza il pool per impersonare l'account di servizio e recuperare i dati non criptati.

Per iniziare, vai alla console Google Cloud:

Vai alla console Google Cloud

Configura le risorse di Alex

Per configurare le risorse per Alex, segui queste istruzioni.

  1. Fai clic su Attiva Cloud Shell.
  2. In Cloud Shell, inserisci questo comando per creare un progetto per Alex, sostituendo ALEX_PROJECT_ID con un nome a tua scelta:

    gcloud projects create ALEX_PROJECT_ID
  3. Passa al progetto appena creato:

    gcloud config set project ALEX_PROJECT_ID
  4. Se non lo hai già fatto, abilita le API richieste da Alex come collaboratore ai dati e autore del carico di lavoro:

    gcloud services enable cloudkms.googleapis.com artifactregistry.googleapis.com iamcredentials.googleapis.com
  5. Crea un keyring e una chiave di crittografia con 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. Concedi ad Alex il ruolo cloudkms.cryptoKeyEncrypter in modo che possa utilizzare la chiave di crittografia appena creata per criptare i dati:

    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. Crea un account di servizio utilizzato in seguito dal carico di lavoro per decriptare i dati:

    gcloud iam service-accounts create ALEX_SERVICE_ACCOUNT_NAME
  8. Concedi all'account di servizio il ruolo cloudkms.cryptoKeyDecrypter in modo che possa utilizzare la chiave di crittografia appena creata per decriptare i dati:

    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. Crea un pool di Workload Identity, quindi collega l'account di servizio al ruolo 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. Crea un bucket Cloud Storage per i dati di input e un altro per archiviare i risultati in:

    gsutil mb gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME
  11. Crea un file contenente solo lo stipendio di Alex:

    echo 123456 > ALEX_SALARY.txt
  12. Cripta il file, quindi caricalo nel bucket di Alex:

    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
    gsutil cp ALEX_ENCRYPTED_SALARY_FILE gs://ALEX_INPUT_BUCKET_NAME

Configurare le risorse di Bola

Per configurare le risorse per Bola, segui queste istruzioni.

  1. In Cloud Shell, inserisci il comando seguente per creare un progetto per Bola, sostituendo BOLA_PROJECT_ID con un nome a tua scelta:

    gcloud projects create BOLA_PROJECT_ID
  2. Passa al progetto appena creato:

    gcloud config set project BOLA_PROJECT_ID
  3. Se non lo hai già fatto, abilita le API richieste da Bola come collaboratore ai dati e operatore del carico di lavoro:

    gcloud services enable cloudkms.googleapis.com compute.googleapis.com confidentialcomputing.googleapis.com
  4. Crea un keyring e una chiave di crittografia con 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. Concedi a Bola il ruolo cloudkms.cryptoKeyEncrypter in modo che possa utilizzare la chiave di crittografia appena creata per criptare i dati:

    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. Crea un account di servizio utilizzato in seguito dal carico di lavoro per decriptare i dati:

    gcloud iam service-accounts create BOLA_SERVICE_ACCOUNT_NAME
  7. Concedi all'account di servizio il ruolo cloudkms.cryptoKeyDecrypter in modo che possa utilizzare la chiave di crittografia appena creata per decriptare i dati:

    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. Crea un pool di Workload Identity, quindi collega l'account di servizio al ruolo 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. Crea un bucket Cloud Storage per i dati di input e un altro per archiviare i risultati in:

    gsutil mb gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME
  10. Crea un numero contenente solo lo stipendio di Bola:

    echo 111111 > BOLA_SALARY.txt
  11. Cripta il file, quindi caricalo nel bucket Bola:

    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
    gsutil cp BOLA_ENCRYPTED_SALARY_FILE gs://BOLA_INPUT_BUCKET_NAME

Crea un account di servizio per il carico di lavoro

Oltre agli account di servizio configurati sia da Alex che da Bola per decriptare i propri dati, è necessario un altro account di servizio per eseguire il carico di lavoro. Poiché gli account di servizio vengono utilizzati per decriptare i dati riservati e per elaborarli, la visibilità dei dati è limitata ai relativi proprietari.

In questa guida, Bola opera ed esegue il carico di lavoro, ma chiunque può assumere questi ruoli, inclusa una terza parte.

Completa i seguenti passaggi nel progetto di Bola per configurare l'account di servizio:

  1. Crea un account di servizio per eseguire il carico di lavoro:

    gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAME
    
  2. Concedi a Bola il ruolo iam.serviceAccountUser per impersonare l'account di servizio, requisito necessario per poter creare una VM del carico di lavoro in un secondo momento:

    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. Concedi all'account di servizio il ruolo confidentialcomputing.workloadUser in modo che possa generare un token di attestazione:

    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. Concedi all'account di servizio il ruolo logging.logWriter per scrivere log in Cloud Logging, in modo da poter verificare l'avanzamento del carico di lavoro:

    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. Concedi all'account di servizio l'accesso in lettura ai bucket Alex e Bola, che contengono i loro dati criptati, e scrivi l'accesso a ciascun bucket dei risultati:

    gsutil iam ch \
        serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com:objectViewer \
        gs://ALEX_INPUT_BUCKET_NAME
    
    gsutil iam ch \
        serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com:objectViewer \
        gs://BOLA_INPUT_BUCKET_NAME
    
    gsutil iam ch \
        serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
        gs://ALEX_RESULTS_BUCKET_NAME
    
    gsutil iam ch \
        serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
        gs://BOLA_RESULTS_BUCKET_NAME
    

    Questa operazione presuppone che l'utente che concede l'accesso disponga del ruolo Amministratore di archiviazione (roles/storage.admin) per il progetto che contiene il bucket Cloud Storage su cui viene operato.

Crea il carico di lavoro

In questa guida, Alex fornisce il codice per il carico di lavoro e crea un'immagine Docker da contenere, ma chiunque può ricoprire questi ruoli, inclusa una terza parte.

Alex deve creare le seguenti risorse per il carico di lavoro:

  • Il codice che esegue il carico di lavoro.

  • Un repository Docker in Artifact Registry, a cui ha accesso l'account di servizio che esegue il carico di lavoro.

  • Un'immagine Docker che contiene ed esegue il codice del carico di lavoro.

Per creare e configurare le risorse, completa i seguenti passaggi nel progetto di Alex:

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Crea un repository Docker in Artifact Registry:

    gcloud artifacts repositories create REPOSITORY_NAME \
        --repository-format=docker \
        --location=us
    
  3. Concedi all'account di servizio che eseguirà il carico di lavoro il ruolo Lettore Artifact Registry (roles/artifactregistry.reader) in modo che possa leggere dal repository:

    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. Fai clic su Apri editor per aprire l'editor di Cloud Shell, quindi crea un nuovo file denominato salary.go. Copia il seguente codice nel file, quindi salvalo:

    // 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 keyring
    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 keyring
    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. Modifica USER VARIABLES SECTION nel codice sorgente, sostituendo i valori vuoti di const con i nomi delle risorse pertinenti, come descritto nei commenti del codice. Se hai modificato le variabili segnaposto come ALEX_PROJECT_ID mostrate in questa guida, i valori sono inclusi nel seguente esempio di codice, che puoi copiare e incollare sul codice esistente:

    // 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 keyring
    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 keyring
    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
    

    Assicurati di aggiornare anche i numeri del progetto sia per Alex che per Bola. Puoi recuperarli con il comando seguente:

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  6. Assicurati che tutte le parti leggano e controllino il codice sorgente.

  7. Fai clic su Terminale > Nuovo terminale per aprire un terminale nell'editor di Cloud Shell.

  8. Inserisci i seguenti comandi nel terminale per configurare l'ambiente Go:

    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. Inserisci il comando seguente per compilare il codice sorgente in un programma binario collegato in modo statico:

    CGO_ENABLED=0 go build -trimpath
    
  10. Crea un file denominato Dockerfile nell'editor di Cloud Shell con i seguenti contenuti:

    FROM alpine:latest
    WORKDIR /test
    COPY salary /test
    ENTRYPOINT ["/test/salary"]
    CMD []
    
  11. Aggiorna le tue credenziali Docker in modo da includere il nome di dominio us-docker.pkg.dev:

    gcloud auth configure-docker us-docker.pkg.dev
    
  12. Crea un'immagine Docker da Dockerfile inserendo il seguente comando nel terminale:

    docker build -t \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest .
    
  13. Esegui il push dell'immagine Docker ad Artifact Registry:

    docker push \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME
    
  14. Dalla risposta push di Docker, copia il digest dell'immagine Docker (incluso il codice SHA256:) da utilizzare in un luogo sicuro per un utilizzo futuro.

  15. Assicurati che tutte le parti esaminino l'immagine Docker e ne verifichino l'affidabilità prima di autorizzarne l'utilizzo.

Autorizza il carico di lavoro

Dopo che il carico di lavoro è stato approvato da entrambe le parti, Alex e Bola devono aggiungere il servizio di verifica dell'attestazione Confidential Space come provider ai propri pool di identità dei carichi di lavoro. Questo consente all'account di servizio collegato al carico di lavoro di impersonare gli account di servizio collegati ai propri pool e di accedere ai propri dati, a condizione che vengano soddisfatte determinate condizioni degli attributi. Ciò significa che le condizioni degli attributi fungono da criteri di attestazione.

Le condizioni degli attributi utilizzate in questa guida sono le seguenti:

  • Il digest dell'immagine Docker in esecuzione

  • L'indirizzo email dell'account di servizio che esegue il carico di lavoro

Se un utente malintenzionato cambia l'immagine Docker o è collegato un altro account di servizio al carico di lavoro, quest'ultimo non potrà accedere ai dati di Alex o Bolola.

Per visualizzare le condizioni disponibili per gli attributi, vedi Criteri di attestazione di Confidential Space.

Per configurare i provider per Alex e Bola con le condizioni richieste, procedi nel seguente modo:

  1. Inserisci il comando seguente per creare il provider per Alex:

    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. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  3. Inserisci il comando seguente per creare il provider per Bola:

    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"
    

Esegui il carico di lavoro

Una volta aggiunti i provider sia ai pool di Workload Identity di Alex che a Bola, e le risorse richieste, l'operatore del carico di lavoro deve eseguire il carico di lavoro.

Per eseguire il carico di lavoro, crea una nuova VM riservata nel progetto di Bola, che abbia le seguenti proprietà:

  • Un sistema operativo basato sull'immagine Confidential Space.
  • Avvio protetto abilitato.
  • L'immagine Docker allegata in precedenza creata da Alex.
  • L'account di servizio collegato che esegue il carico di lavoro.

Per visualizzare le opzioni disponibili per le VM di Confidential Space, consulta le opzioni di Confidential Space per le VM.

Inserisci il comando seguente in Cloud Shell di Bola per eseguire il carico di lavoro:

gcloud compute instances create WORKLOAD_VM_NAME \
    --confidential-compute \
    --shielded-secure-boot \
    --maintenance-policy=TERMINATE \
    --scopes=cloud-platform \
    --zone=us-west1-b \
    --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"

Per visualizzare l'avanzamento del carico di lavoro nel progetto Bola, vai a Esplora log.

Vai a Esplora log

Per trovare i log di Confidential Space, filtra in base ai seguenti campi di log, se disponibili:

  • Tipo di risorsa: istanza VM
  • ID istanza: l'ID istanza della VM
  • Nome log: Confidential-space-Avvio app

Per aggiornare il log, fai clic su Vai a più recenti.

Al termine del carico di lavoro, l'istanza VM si arresta. Se vuoi modificare i file criptati dello stipendio ed eseguire di nuovo il carico di lavoro, devi solo avviare la VM esistente:

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

Eseguire il debug del carico di lavoro

Puoi utilizzare Esplora log per risolvere problemi quali la mancata configurazione delle risorse o l'attribuzione delle condizioni nei provider che non corrispondono alle dichiarazioni effettuate dal carico di lavoro Confidential Space.

A questo scopo, devi apportare le seguenti modifiche:

  • Aggiorna i provider di pool di identità del carico di lavoro di Alex e Bola per rimuovere l'asserzione support_attributes. Devi utilizzare l'immagine di debug Confidential Space per eseguire una risoluzione più approfondita dei problemi e questa immagine non dispone di attributi di supporto da verificare.

  • Crea la VM del carico di lavoro utilizzando l'immagine di debug Confidential Space e imposta i metadati della VM per reindirizzare STDOUT e STDERR a Cloud Logging in modo da acquisire tutti gli output dal carico di lavoro.

Per apportare le modifiche:

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Aggiorna il provider di Alex per rimuovere l'asserzione support_attributes:

    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. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Aggiorna il provider di Bola per rimuovere l'asserzione support_attributes:

    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. Crea una nuova VM con l'immagine di debug Confidential Space e tee-container-log-redirect impostata su true nei metadati.

    gcloud compute instances create WORKLOAD_VM_2_NAME \
        --confidential-compute \
        --shielded-secure-boot \
        --maintenance-policy=TERMINATE \
        --scopes=cloud-platform \
        --zone=us-west1-b \
        --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"
    

A differenza dell'immagine di produzione, l'immagine di debug mantiene la VM in esecuzione al termine del carico di lavoro. Ciò significa che puoi utilizzare il protocollo SSH per connetterti alla tua VM per continuare il debug.

Visualizza i risultati

Una volta completato correttamente il carico di lavoro, sia Alex che Bola possono visualizzare i risultati nei rispettivi bucket di risultati:

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Elenca tutti i file nel bucket di risultati:

    gsutil ls gs://ALEX_RESULTS_BUCKET_NAME
    

    Quindi leggi il file più recente:

    gsutil cat gs://ALEX_RESULTS_BUCKET_NAME/ALEX_RESULTS_FILE_NAME
    
  3. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Per Bola, elenca tutti i file nel bucket dei risultati:

    gsutil ls gs://BOLA_RESULTS_BUCKET_NAME
    

    Quindi leggi il file più recente:

    gsutil cat gs://BOLA_RESULTS_BUCKET_NAME/BOLA_RESULTS_FILE_NAME
    

Leggendo i file, Alex e Bola scoprono chi guadagna di più senza mai rivelarsi la retribuzione.

Esegui la pulizia

Per rimuovere le risorse create in questa guida, segui le istruzioni riportate di seguito.

Esegui la pulizia delle risorse di Alex

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Elimina l'account di servizio che decripta i dati di Alex:

    gcloud iam service-accounts delete \
        ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com
    
  3. Elimina il pool di Workload Identity di Alex:

    gcloud iam workload-identity-pools delete ALEX_POOL_NAME \
        --location=global
    
  4. Elimina i bucket Cloud Storage di Alex:

    gsutil rb gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME
    
  5. Elimina i file dello stipendio di Alex e il codice Go:

    rm ALEX_SALARY.txt \
        ALEX_ENCRYPTED_SALARY_FILE \
        salary.go salary \
        go.mod go.sum
    
  6. (Facoltativo) Disattiva o elimina la chiave Cloud Key Management Service di Alex.

  7. (Facoltativo) Chiudi il progetto di Alex.

Esegui la pulizia delle risorse di Bola

  1. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  2. Elimina la VM del carico di lavoro:

    gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-b
    
  3. Elimina l'account di servizio che decripta i dati di Bola e l'account di servizio che esegue il carico di lavoro:

    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. Elimina il pool di Workload Identity di Bola:

    gcloud iam workload-identity-pools delete BOLA_POOL_NAME \
        --location=global
    
  5. Elimina i bucket Cloud Storage di Bola:

    gsutil rb gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME
    
  6. Elimina i file degli stipendi di Bola:

    rm BOLA_SALARY.txt \
        BOLA_ENCRYPTED_SALARY_FILE
    
  7. (Facoltativo) Disattiva o elimina la chiave Cloud Key Management Service di Roba.

  8. (Facoltativo) Chiudi il progetto di Bola.