Creare il primo ambiente Spazio riservato

In questa guida, Alex e Bola vogliono scoprire chi ha lo stipendio più alto senza rivelare i numeri l'uno all'altro. Decidono di utilizzare Confidential Space per mantenere i propri dati riservati e accettano di assumere i seguenti ruoli:

  • Alex: collaboratore di dati, autore del workload

  • Bola: collaboratore dei dati, operatore del carico di lavoro

Questa disposizione è pensata per semplificare al massimo la guida. Tuttavia, è possibile che l'autore e l'operatore del workload siano completamente indipendenti dai collaboratori dei dati e puoi avere tutti i collaboratori che vuoi.

Prima di iniziare

Questa guida mostra uno scenario di Confidential Space che utilizza un singolo account in una singola organizzazione con accesso a più progetti, in modo che tu possa sperimentare l'intero processo. In un deployment di produzione, collaboratori, autori di workload e operatori di workload hanno account separati e progetti propri contenuti in organizzazioni distinte, inaccessibili l'uno all'altro e che mantengono separati i dati riservati.

Confidential Space può interagire con molti servizi di Google Cloudper produrre i suoi risultati, tra cui:

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

API obbligatorie

Per completare questa guida, devi abilitare le seguenti API nei progetti specificati.

Nome API Titolo dell'API Attiva in questi progetti
cloudkms.googleapis.com Cloud Key Management Service Collaboratori dei dati (progetti di Alex e Bola)
iamcredentials.googleapis.com API IAM Service Account Credentials

Collaboratori dei dati (progetti di Alex e Bola)

artifactregistry.googleapis.com Artifact Registry Autore del workload (progetto di Alessandro)
compute.googleapis.com Compute Engine Operatore del workload (progetto di Bola)
confidentialcomputing.googleapis.com Confidential Computing Operatore del workload (progetto di Bola)

Ruoli obbligatori

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

  • Cloud KMS Admin (roles/cloudkms.admin) per i collaboratori dei dati (Alex e Bola).
  • IAM Workload Identity Pool Admin (roles/iam.workloadIdentityPoolAdmin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore Service Usage (roles/serviceusage.serviceUsageAdmin) per i collaboratori dei dati (Alex e Bola).
  • Amministratore dell'archiviazione (roles/storage.admin) per i collaboratori dei dati (Alex e Bola) e l'operatore del carico di lavoro (Bola).
  • Amministratore service account (roles/iam.serviceAccountAdmin) per l'operatore del workload (Bola).
  • Compute Admin (roles/compute.admin) per l'operatore del carico di lavoro (Bola).
  • Amministratore sicurezza (roles/securityAdmin) per l'operatore del workload (Bola).
  • Artifact Registry Administrator (roles/artifactregistry.admin) per l'autore del workload (Alex).

Per ulteriori informazioni sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

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

Configurare le risorse per i collaboratori dei dati

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

  • I dati riservati stessi.

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

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

  • Un pool di identità del workload. Il carico di lavoro che elabora i dati riservati utilizza il pool per accedere ai dati privati e decriptarli.

Per iniziare, vai alla console Google Cloud :

Vai alla console Google Cloud

Configurare le risorse di Alex

Per configurare le risorse per Alex, completa le seguenti istruzioni.

  1. Fai clic su Attiva Cloud Shell.
  2. In Cloud Shell, inserisci il comando seguente 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 l'hai ancora fatto, abilita le API richieste da Alex in qualità di collaboratore dei dati e autore del workload:

    gcloud services enable cloudkms.googleapis.com artifactregistry.googleapis.com iamcredentials.googleapis.com
  5. Crea un portachiavi 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 il pool di identità del workload di Alex:

    gcloud iam workload-identity-pools create ALEX_POOL_NAME \
        --location=global
  8. Crea un bucket Cloud Storage per i dati di input e un altro per archiviare i risultati:

    gcloud storage buckets create gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME
  9. Crea un file contenente solo lo stipendio di Alex come numero:

    echo 123456 > ALEX_SALARY.txt
  10. 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
    gcloud storage cp ALEX_ENCRYPTED_SALARY_FILE gs://ALEX_INPUT_BUCKET_NAME

Configurare le risorse di Bola

Per configurare le risorse per Bola, completa le seguenti 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 l'hai ancora fatto, attiva le API richieste da Bola come collaboratore dei dati e operatore del workload:

    gcloud services enable cloudkms.googleapis.com iamcredentials.googleapis.com compute.googleapis.com confidentialcomputing.googleapis.com
  4. Crea un portachiavi 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. Assegna 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 il pool di identità del workload di Bola:

    gcloud iam workload-identity-pools create BOLA_POOL_NAME \
        --location=global
  7. Crea un bucket Cloud Storage per i dati di input e un altro per archiviare i risultati:

    gcloud storage buckets create gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME
  8. Crea un file contenente solo lo stipendio di Bola come numero:

    echo 111111 > BOLA_SALARY.txt
  9. Cripta il file e poi caricalo nel bucket di 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
    gcloud storage cp BOLA_ENCRYPTED_SALARY_FILE gs://BOLA_INPUT_BUCKET_NAME

Crea un account di servizio per il workload

In questa guida, Bola gestisce ed esegue il carico di lavoro, ma chiunque può assumere questi ruoli, inclusa una terza parte. La VM creata da Bola per eseguire il workload ha un account di servizio collegato, che dispone dell'autorizzazione per generare token di attestazione, scrivere log, leggere i dati criptati di Alex e Bola e scrivere i risultati in bucket Cloud Storage specifici.

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

  1. Crea un account di servizio per eseguire il workload:

    gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAME
    
  2. Concedi a Bola il ruolo iam.serviceAccountUser, in modo che possa collegare il service account alla VM del workload 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 al 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 al account di servizio il ruolo logging.logWriter per scrivere log in Cloud Logging, in modo da poter controllare l'avanzamento del workload:

    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 di Alex e Bola che contengono i loro dati criptati e l'accesso in scrittura ai bucket dei risultati di ciascuno:

    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
    

    Ciò presuppone che l'utente che concede l'accesso disponga del ruolo Storage Admin (roles/storage.admin) per il progetto che contiene il bucket Cloud Storage su cui viene eseguita l'operazione.

Crea il workload

In questa guida, Alex fornisce il codice per il workload e crea un'immagine Docker per contenerlo, ma chiunque può assumere questi ruoli, inclusa una terza parte.

Alex deve creare le seguenti risorse per il workload:

  • Il codice che esegue il carico di lavoro.

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

  • Un'immagine Docker che contiene ed esegue il codice del workload.

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 workload 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. Modifica i valori nel seguente esempio di codice con i nomi delle risorse pertinenti per aggiornare il codice sorgente nel passaggio successivo. Se hai già modificato le variabili segnaposto in questa guida, ad esempio ALEX_PROJECT_ID, i valori vengono precompilati:

    // Alex's values
    ALEX_ENCRYPTED_SALARY_FILE // The name of Alex's encrypted salary file
    ALEX_INPUT_BUCKET_NAME // The name of the storage bucket that contains Alex's encrypted salary file
    ALEX_RESULTS_BUCKET_NAME // The name of the storage bucket to store Alex's results in
    ALEX_RESULTS_FILE_PREFIX // A prefix for Alex's results filename. The code adds a timestamp to this prefix.
    ALEX_KEYRING_NAME // Alex's Key Management Service key ring.
    ALEX_KEY_NAME // Alex's Key Management Service key.
    ALEX_PROJECT_ID // Alex's project ID.
    ALEX_PROJECT_NUMBER // Alex's project number.
    ALEX_POOL_NAME // Alex's workload identity pool name.
    
    // Bola's values
    BOLA_ENCRYPTED_SALARY_FILE // The name of Bola's encrypted salary file.
    BOLA_INPUT_BUCKET_NAME // The name of the storage bucket that contains Bola's encrypted salary file.
    BOLA_RESULTS_BUCKET_NAME // The name of the storage bucket to store Bola's results in.
    BOLA_RESULTS_FILE_PREFIX // A prefix for Bola's results filename. The code adds a timestamp to this prefix.
    BOLA_KEYRING_NAME // Bola's Key Management Service key ring.
    BOLA_KEY_NAME // Bola's Key Management Service key.
    BOLA_PROJECT_ID // Bola's project ID.
    BOLA_PROJECT_NUMBER // Bola's project number.
    BOLA_POOL_NAME // Bola's workload identity pool name.
    

    Per recuperare i numeri di progetto per Alex e Bola, esegui i seguenti comandi nei progetti pertinenti:

    gcloud projects describe ALEX_PROJECT_ID --format="value(projectNumber)"
    
    gcloud projects describe BOLA_PROJECT_ID --format="value(projectNumber)"
    
  5. Nel progetto di Alex, fai clic su Apri editor per aprire Cloud Shell Editor, quindi crea un nuovo file chiamato salary.go. Copia il seguente codice nel file e salvalo:

    // READ ME FIRST: Before compiling, customize the details in the USER VARIABLES
    // SECTION starting at line 30.
    
    package main
    
    import (
      "context"
      "fmt"
      "io"
      "strconv"
      "strings"
      "time"
    
      kms "cloud.google.com/go/kms/apiv1"
      kmspb "cloud.google.com/go/kms/apiv1/kmspb"
      "cloud.google.com/go/storage"
      "google.golang.org/api/option"
    )
    
    type collaborator struct {
      name         string
      wipName      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 = "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 collaborator1BucketOutputFilePrefix string = "ALEX_RESULTS_FILE_PREFIX" // A prefix for Alex's results filename. The code adds a timestamp to this prefix.
    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.
    
    // 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 collaborator2BucketOutputFilePrefix string = "BOLA_RESULTS_FILE_PREFIX" // A prefix for Bola's results filename. The code adds a timestamp to this prefix.
    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.
    
    // END USER VARIABLES SECTION
    // ==========================
    
    var collaborators = [2]collaborator{
      {
        collaborator1Name,
        "projects/" + collaborator1ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator1PoolName + "/providers/attestation-verifier",
        "projects/" + collaborator1ProjectName + "/locations/global/keyRings/" + collaborator1KMSKeyringName + "/cryptoKeys/" + collaborator1KMSKeyName,
        collaborator1BucketInputName,
        collaborator1EncryptedSalaryFileName,
        collaborator1BucketOutputName,
        collaborator1BucketOutputFilePrefix,
      },
      {
        collaborator2Name,
        "projects/" + collaborator2ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator2PoolName + "/providers/attestation-verifier",
        "projects/" + collaborator2ProjectName + "/locations/global/keyRings/" + collaborator2KMSKeyringName + "/cryptoKeys/" + collaborator2KMSKeyName,
        collaborator2BucketInputName,
        collaborator2EncryptedSalaryFileName,
        collaborator2BucketOutputName,
        collaborator2BucketOutputFilePrefix,
      },
    }
    
    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"
            }
            }`
    
    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.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, wippro string, encryptedData []byte) ([]byte, error) {
      cc := fmt.Sprintf(credentialConfig, wippro)
      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 := io.ReadAll(objectReader)
      if err != nil {
        return nil, err
      }
    
      return s, nil
    }
    
  6. Assicurati che tutte le parti leggano e controllino il codice sorgente.

  7. Crea un file denominato Dockerfile nell'editor di Cloud Shell contenente il seguente contenuto:

    # Compile the provided Go code to a statically linked binary
    FROM golang:latest AS build
    WORKDIR /build
    COPY salary.go .
    RUN go mod init salary
    RUN 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
    RUN CGO_ENABLED=0 go build -trimpath
    
    # Build the workload container image
    FROM alpine:latest AS run
    WORKDIR /test
    COPY --from=build /build/salary /test/salary
    ENTRYPOINT ["/test/salary"]
    CMD []
    

    Questo Dockerfile utilizza una build in più fasi per compilare prima il codice Go e poi copia la versione compilata del codice nel container Docker finale.

  8. Fai clic su Apri terminale per tornare a Cloud Shell o richiama il terminale integrato nell'editor di Cloud Shell dal menu Visualizza.

  9. Aggiorna le credenziali Docker per includere il nome di dominio us-docker.pkg.dev:

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

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

    docker push \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME
    
  12. La risposta al comando Docker push elenca il digest SHA256 dell'immagine, necessario in un secondo momento per autorizzare il workload. Il riepilogo è simile al seguente esempio:

    sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    

    Copia il digest dell'immagine (incluso il prefisso sha256:) in un punto in cui puoi farvi riferimento. Puoi anche inserire il digest nel seguente esempio di codice per precompilare il resto degli esempi di codice in questa guida che richiedono il valore:

    WORKLOAD_CONTAINER_IMAGE_DIGEST
    
  13. Prima di autorizzarne l'utilizzo, assicurati che tutte le parti controllino l'immagine Docker e verifichino che sia attendibile.

Autorizza il workload

Con il workload approvato da entrambe le parti, Alex e Bola devono aggiungere Google Cloud Attestation come provider ai loro pool di identità dei workload. Il fornitore specifica il servizio di attestazione da utilizzare e le proprietà che il carico di lavoro deve corrispondere per poter operare sui dati di Alex o Bola. Se un malintenzionato modifica l'immagine Docker o altera un'altra proprietà misurata, l'accesso al workload viene negato.

Questa guida utilizza le mappature degli attributi per fornire l'accesso diretto alle risorse al workload in base al digest dell'immagine. Tuttavia, in altre situazioni potresti preferire utilizzare l'imitazione del account di servizio per accedere alle risorse. Per saperne di più, consulta la sezione Accesso ai workload esterni.

Per configurare i fornitori per Alex e Bola con le condizioni richieste, completa i seguenti passaggi:

  1. Inserisci questo comando per creare il fornitore 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=\"gcpcs::\"+assertion.submods.container.image_digest+\"::\"+assertion.submods.gce.project_number+\"::\"+assertion.submods.gce.instance_id,attribute.image_digest=assertion.submods.container.image_digest" \
        --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' \
            && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    
  2. Concedi all'identità federata definita dal provider di Alex il ruolo cloudkms.cryptoKeyDecrypter, specificando l'attributo image_digest in modo che solo i container dei workload con il digest specificato possano decriptare le chiavi KMS:

    gcloud kms keys add-iam-policy-binding \
        projects/ALEX_PROJECT_ID/locations/global/keyRings/ALEX_KEYRING_NAME/cryptoKeys/ALEX_KEY_NAME \
        --member="principalSet://iam.googleapis.com/projects/ALEX_PROJECT_NUMBER/locations/global/workloadIdentityPools/ALEX_POOL_NAME/attribute.image_digest/WORKLOAD_CONTAINER_IMAGE_DIGEST" \
        --role=roles/cloudkms.cryptoKeyDecrypter
    
  3. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Inserisci questo comando 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=\"gcpcs::\"+assertion.submods.container.image_digest+\"::\"+assertion.submods.gce.project_number+\"::\"+assertion.submods.gce.instance_id,attribute.image_digest=assertion.submods.container.image_digest" \
        --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' \
            && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    
  5. Concedi all'identità federata definita dal provider di Bola il ruolo cloudkms.cryptoKeyDecrypter, specificando l'attributo image_digest in modo che solo i container dei workload con il digest specificato possano decriptare le chiavi KMS:

    gcloud kms keys add-iam-policy-binding \
        projects/BOLA_PROJECT_ID/locations/global/keyRings/BOLA_KEYRING_NAME/cryptoKeys/BOLA_KEY_NAME \
        --member="principalSet://iam.googleapis.com/projects/BOLA_PROJECT_NUMBER/locations/global/workloadIdentityPools/BOLA_POOL_NAME/attribute.image_digest/WORKLOAD_CONTAINER_IMAGE_DIGEST" \
        --role=roles/cloudkms.cryptoKeyDecrypter
    

Esegui il deployment del workload

Con i provider aggiunti ai pool di identità del workload di Alex e Bola e le risorse richieste disponibili, è il momento che l'operatore del workload esegua il workload.

Per eseguire il deployment del workload, crea una nuova istanza Confidential VM nel progetto di Bola con le seguenti proprietà:

  • Una configurazione supportata per un'istanza Confidential VM con AMD SEV, Intel TDX o Intel TDX con NVIDIA Confidential Computing (anteprima).

  • Un sistema operativo basato sull'immagine di Confidential Space.

  • Avvio protetto abilitato.

  • L'immagine Docker allegata che Alex ha creato in precedenza.

  • Il account di servizio collegato che esegue il workload.

Inserisci il seguente comando nella Cloud Shell di Bola per eseguire il deployment del workload:

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

Puoi visualizzare l'avanzamento del carico di lavoro nel progetto di Bola andando 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-launcher

Per aggiornare il log, fai clic su Vai a ora.

Al termine del workload, l'istanza VM si arresta. Se vuoi modificare i file delle buste paga criptate e distribuire di nuovo il workload, devi solo avviare la VM esistente:

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

Visualizza i risultati

Una volta completato correttamente il workload, sia Alex che Bola possono visualizzare i risultati nei rispettivi bucket dei risultati:

  1. Passa al progetto di Alex:

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

    gcloud storage ls gs://ALEX_RESULTS_BUCKET_NAME
    

    Quindi, leggi l'ultimo file elencato, sostituendo ALEX_RESULTS_CLOUD_STORAGE_PATH con il percorso del file, incluso gs://:

    gcloud storage cat ALEX_RESULTS_CLOUD_STORAGE_PATH
    
  3. Passa al progetto di Bola:

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

    gcloud storage ls gs://BOLA_RESULTS_BUCKET_NAME
    

    Quindi, leggi l'ultimo file elencato, sostituendo BOLA_RESULTS_CLOUD_STORAGE_PATH con il percorso del file, incluso gs://:

    gcloud storage cat BOLA_RESULTS_CLOUD_STORAGE_PATH
    

Leggendo i file, Alex e Bola scoprono chi guadagna di più senza mai rivelare i rispettivi stipendi.

Esegui il debug del carico di lavoro

Puoi utilizzare Esplora log per risolvere problemi come la configurazione errata delle risorse o le condizioni degli attributi nei provider che non corrispondono alle attestazioni effettuate dal workload Confidential Space.

Per farlo, devi apportare le seguenti modifiche:

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

  • Crea la VM del workload utilizzando l'immagine di debug di Confidential Space e imposta i metadati della VM per reindirizzare STDOUT e STDERR a Cloud Logging per acquisire tutto l'output del workload.

Per apportare le modifiche, completa i seguenti passaggi:

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Aggiorna il fornitore 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=\"gcpcs::\"+assertion.submods.container.image_digest+\"::\"+assertion.submods.gce.project_number+\"::\"+assertion.submods.gce.instance_id,attribute.image_digest=assertion.submods.container.image_digest" \
        --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  3. Passa al progetto di Bola:

    gcloud config set project BOLA_PROJECT_ID
    
  4. Aggiorna il fornitore 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=\"gcpcs::\"+assertion.submods.container.image_digest+\"::\"+assertion.submods.gce.project_number+\"::\"+assertion.submods.gce.instance_id,attribute.image_digest=assertion.submods.container.image_digest" \
        --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  5. Crea una nuova VM con l'immagine di debug di Confidential Space e imposta tee-container-log-redirect su true nei metadati.

    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"
    

A differenza dell'immagine di produzione, l'immagine di debug mantiene la VM in esecuzione dopo il completamento del workload. Ciò significa che puoi utilizzare SSH per connetterti alla VM e continuare il debug.

Esegui la pulizia

Per rimuovere le risorse create in questa guida, completa le seguenti istruzioni.

Esegui la pulizia delle risorse di Alessandro

  1. Passa al progetto di Alex:

    gcloud config set project ALEX_PROJECT_ID
    
  2. Elimina il pool di identità del workload di Alex:

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

    gcloud storage rm gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME --recursive
    
  4. Elimina i file della busta paga di Alex e il codice Go:

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

  6. (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 workload:

    gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-b
    
  3. Elimina il account di servizio che esegue il carico di lavoro:

    gcloud iam service-accounts delete \
        WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com
    
  4. (Facoltativo) Se hai creato una VM di debug, eliminala:

    gcloud compute instances delete WORKLOAD_VM_2_NAME --zone=us-west1-b
    
  5. Elimina il pool di identità del workload di Bola:

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

    gcloud storage rm gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME --recursive
    
  7. Elimina i file della busta paga di Bola:

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

  9. (Facoltativo) Chiudi il progetto di Bola.