En esta guía, Alex y Bola quieren saber quién tiene el salario más alto sin revelar números entre sí. Eligen usar Confidential Space para mantener la confidencialidad de sus datos y aceptan asumir los siguientes roles:
Alex: Colaborador de datos y autor de cargas de trabajo
Bola: Colaborador de datos, operador de carga de trabajo
Esta disposición está diseñada para que esta guía sea lo más sencilla posible. Sin embargo, es posible que el autor y el operador de la carga de trabajo sean completamente independientes de los colaboradores de datos, y puedes tener tantos colaboradores como desees.
Antes de comenzar
En esta guía, se muestra una situación de Confidential Space con una sola cuenta en una sola organización con acceso a varios proyectos, para que puedas experimentar todo el proceso. En una implementación de producción, los colaboradores, los autores de cargas de trabajo y los operadores de cargas de trabajo tienen cuentas separadas y sus propios proyectos contenidos en organizaciones discretas, inaccesibles entre sí y que mantienen separados sus datos confidenciales.
Confidential Space puede interactuar con muchos de los servicios de Google Cloudpara producir sus resultados, incluidos, sin limitaciones, los siguientes:
En esta guía, se utilizan todas estas funciones y se supone que tienes un conocimiento básico de ellas.
Roles obligatorios
Si quieres obtener los permisos que necesitas para completar esta guía, pídele a tu administrador que te otorgue los siguientes roles de IAM en el proyecto:
-
Administrador de Cloud KMS (
roles/cloudkms.admin) para los colaboradores de datos (Alex y Bola). -
Administrador de grupos de Workload Identity de IAM (
roles/iam.workloadIdentityPoolAdmin) para los colaboradores de datos (Alex y Bola). -
Administrador de Service Usage (
roles/serviceusage.serviceUsageAdmin) para los colaboradores de datos (Alex y Bola). -
Administrador de almacenamiento (
roles/storage.admin) para los colaboradores de datos (Alex y Bola) y el operador de carga de trabajo (Bola). -
Administrador de cuenta de servicio (
roles/iam.serviceAccountAdmin) para el operador de la carga de trabajo (Bola). -
Administrador de Compute (
roles/compute.admin) para el operador de la carga de trabajo (Bola). -
Administrador de seguridad (
roles/securityAdmin) para el operador de la carga de trabajo (Bola). -
Administrador de Artifact Registry (
roles/artifactregistry.admin) para el autor de la carga de trabajo (Alex).
Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.
También puedes obtener los permisos necesarios a través de roles personalizados o cualquier otro rol predefinido.
Configura los recursos de colaborador de datos
Tanto Alex como Bola necesitan proyectos independientes que contengan los siguientes recursos:
Son los datos confidenciales en sí.
Una clave de encriptación para encriptar esos datos y mantenerlos confidenciales
Es un bucket de Cloud Storage en el que se almacenarán los datos encriptados.
Un grupo de identidades para cargas de trabajo La carga de trabajo que procesa los datos confidenciales usa el grupo para acceder a los datos privados y desencriptarlos.
Para comenzar, ve a la consola de Google Cloud :
Ir a la consola de Google Cloud
Configura los recursos de Alex
Para configurar los recursos de Alex, completa las siguientes instrucciones.
- Haz clic en Activar Cloud Shell.
-
En Cloud Shell, ingresa el comando siguiente a fin de crear un proyecto para Alex y reemplaza ALEX_PROJECT_ID por el nombre que elijas:
gcloud projects create ALEX_PROJECT_ID -
Cambia al proyecto recién creado:
gcloud config set project ALEX_PROJECT_ID -
Habilita las APIs que Alex requiere como colaborador de datos y autor de cargas de trabajo:
gcloud services enable \ artifactregistry.googleapis.com \ cloudkms.googleapis.com \ iamcredentials.googleapis.com -
Crea un llavero de claves y una clave de encriptación 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 -
Otorga a Alex el rol
cloudkms.cryptoKeyEncrypterpara que pueda usar la clave de encriptación recién creada a fin de encriptar datos: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 -
Crea el grupo de identidades para cargas de trabajo de Alex:
gcloud iam workload-identity-pools create ALEX_POOL_NAME \ --location=global -
Crea un bucket de Cloud Storage para los datos de entrada y otro para almacenar los resultados:
gcloud storage buckets create gs://ALEX_INPUT_BUCKET_NAME \ gs://ALEX_OUTPUT_BUCKET_NAME -
Crea un archivo que solo contenga el salario de Alex como un número:
echo 123456 > ALEX_SALARY.txt -
Encripta el archivo y, luego, súbelo al bucket de 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
Configura los recursos de Bola
A fin de configurar los recursos para Bola, completa las siguientes instrucciones.
-
En Cloud Shell, ingresa el siguiente comando a fin de crear un proyecto para Bola y reemplaza BOLA_PROJECT_ID por el nombre que elijas:
gcloud projects create BOLA_PROJECT_ID -
Cambia al proyecto recién creado:
gcloud config set project BOLA_PROJECT_ID -
Habilita las APIs que Bola requiere como colaborador de datos y operador de carga de trabajo:
gcloud services enable \ cloudkms.googleapis.com \ compute.googleapis.com \ confidentialcomputing.googleapis.com \ iamcredentials.googleapis.com -
Crea un llavero de claves y una clave de encriptación 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 -
Otorga a Bola el rol
cloudkms.cryptoKeyEncrypterpara que pueda usar la clave de encriptación recién creada para encriptar datos: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 -
Crea el grupo de identidades para cargas de trabajo de Bola:
gcloud iam workload-identity-pools create BOLA_POOL_NAME \ --location=global -
Crea un bucket de Cloud Storage para los datos de entrada y otro para almacenar los resultados:
gcloud storage buckets create gs://BOLA_INPUT_BUCKET_NAME \ gs://BOLA_OUTPUT_BUCKET_NAME -
Crea un archivo que solo contenga el salario de Bola como un número:
echo 111111 > BOLA_SALARY.txt -
Encripta el archivo y, luego, súbelo al bucket de 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 una cuenta de servicio para la carga de trabajo
En esta guía, Bola opera y ejecuta la carga de trabajo, pero cualquier persona puede asumir estos roles, incluido un tercero. La instancia de VM que crea Bola para ejecutar la carga de trabajo tiene adjunta una cuenta de servicio que tiene permiso para generar tokens de certificación, escribir registros, leer los datos encriptados de Alex y Bola, y escribir los resultados en buckets específicos de Cloud Storage.
Completa los siguientes pasos en el proyecto de Bola para configurar la cuenta de servicio:
Crea una cuenta de servicio para ejecutar la carga de trabajo:
gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAMEOtorga a Bola el rol
iam.serviceAccountUserpara que pueda adjuntar la cuenta de servicio a la VM de carga de trabajo más adelante: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.serviceAccountUserOtorga a la cuenta de servicio la función
confidentialcomputing.workloadUserpara que pueda generar un token de certificación:gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/confidentialcomputing.workloadUserOtorga a la cuenta de servicio el rol
logging.logWriterpara escribir registros en Cloud Logging, de modo que puedas verificar el progreso de la carga de trabajo:gcloud projects add-iam-policy-binding BOLA_PROJECT_ID \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/logging.logWriterOtorga a la cuenta de servicio acceso de lectura a los buckets de Alex y Bola que contienen sus datos encriptados, y acceso de escritura a cada uno de sus buckets de resultados:
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://ALEX_OUTPUT_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_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_OUTPUT_BUCKET_NAME \ --member=serviceAccount:WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \ --role=roles/storage.objectAdminEsto supone que el usuario que otorga el acceso tiene el rol de administrador de almacenamiento (
roles/storage.admin) para el proyecto que contiene el bucket de Cloud Storage en el que se opera.
Crea la carga de trabajo
En esta guía, Alex proporciona el código para la carga de trabajo y compila una imagen de Docker que la contiene, pero cualquiera puede asumir estos roles, incluido un tercero.
Alex necesita crear los siguientes recursos para la carga de trabajo:
Es el código que ejecuta la carga de trabajo.
Un repositorio de Docker en Artifact Registry al que tiene acceso la cuenta de servicio que ejecuta la carga de trabajo.
Una imagen de Docker que contiene y ejecuta el código de la carga de trabajo.
Para crear y configurar los recursos, completa los siguientes pasos en el proyecto de Alex:
Cambia al proyecto de Alex:
gcloud config set project ALEX_PROJECT_IDHaz clic en Abrir editor para abrir el editor de Cloud Shell y, luego, crea un archivo nuevo llamado
salary.go. Copia el siguiente código en el archivo y guárdalo:package main import ( "context" "fmt" "io" "os" "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 } // The following values are pulled from environment variables // Alex's values var collaborator1Name string = os.Getenv("COLLAB_1_NAME") // Alex's name var collaborator1EncryptedSalaryFileName string = os.Getenv("COLLAB_1_ENCRYPTED_SALARY") // The name of Alex's encrypted salary file. var collaborator1BucketInputName string = os.Getenv("COLLAB_1_INPUT_BUCKET") // The name of the storage bucket that contains Alex's encrypted salary file. var collaborator1BucketOutputName string = os.Getenv("COLLAB_1_OUTPUT_BUCKET") // The name of the storage bucket to store Alex's results in. var collaborator1KMSKeyringName string = os.Getenv("COLLAB_1_KEYRING_NAME") // Alex's Key Management Service key ring. var collaborator1KMSKeyName string = os.Getenv("COLLAB_1_KEY_NAME") // Alex's Key Management Service key. var collaborator1ProjectName string = os.Getenv("COLLAB_1_PROJECT_ID") // Alex's project ID. var collaborator1ProjectNumber string = os.Getenv("COLLAB_1_PROJECT_NUMBER") // Alex's project number. var collaborator1PoolName string = os.Getenv("COLLAB_1_POOL_NAME") // Alex's workload identity pool name. // Bola's values var collaborator2Name string = os.Getenv("COLLAB_2_NAME") // Bola's name var collaborator2EncryptedSalaryFileName string = os.Getenv("COLLAB_2_ENCRYPTED_SALARY") // The name of Bola's encrypted salary file. var collaborator2BucketInputName string = os.Getenv("COLLAB_2_INPUT_BUCKET") // The name of the storage bucket that contains Bola's encrypted salary file. var collaborator2BucketOutputName string = os.Getenv("COLLAB_2_OUTPUT_BUCKET") // The name of the storage bucket to store Bola's results in. var collaborator2KMSKeyringName string = os.Getenv("COLLAB_2_KEYRING_NAME") // Bola's Key Management Service key ring. var collaborator2KMSKeyName string = os.Getenv("COLLAB_2_KEY_NAME") // Bola's Key Management Service key. var collaborator2ProjectName string = os.Getenv("COLLAB_2_PROJECT_ID") // Bola's project ID. var collaborator2ProjectNumber string = os.Getenv("COLLAB_2_PROJECT_NUMBER") // Bola's project number. var collaborator2PoolName string = os.Getenv("COLLAB_2_POOL_NAME") // Bola's workload identity pool name. 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, }, { collaborator2Name, "projects/" + collaborator2ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator2PoolName + "/providers/attestation-verifier", "projects/" + collaborator2ProjectName + "/locations/global/keyRings/" + collaborator2KMSKeyringName + "/cryptoKeys/" + collaborator2KMSKeyName, collaborator2BucketInputName, collaborator2EncryptedSalaryFileName, collaborator2BucketOutputName, }, } 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 = "You earn the same!\n" } now := time.Now() for _, cw := range collaborators { outputWriter := storageClient.Bucket(cw.outputBucket).Object(fmt.Sprintf("comparison-result-%d", 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 }Asegúrate de que todas las partes lean y auditen el código fuente.
Crea un archivo llamado
Dockerfileen el editor de Cloud Shell que incluya el siguiente contenido:# 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 [] # Allow the workload to access the following environment variables LABEL "tee.launch_policy.allow_env_override"="\ COLLAB_1_NAME,\ COLLAB_2_NAME,\ COLLAB_1_ENCRYPTED_SALARY,\ COLLAB_2_ENCRYPTED_SALARY,\ COLLAB_1_INPUT_BUCKET,\ COLLAB_2_INPUT_BUCKET,\ COLLAB_1_OUTPUT_BUCKET,\ COLLAB_2_OUTPUT_BUCKET,\ COLLAB_1_KEYRING_NAME,\ COLLAB_2_KEYRING_NAME,\ COLLAB_1_KEY_NAME,\ COLLAB_2_KEY_NAME,\ COLLAB_1_PROJECT_ID,\ COLLAB_2_PROJECT_ID,\ COLLAB_1_PROJECT_NUMBER,\ COLLAB_2_PROJECT_NUMBER,\ COLLAB_1_POOL_NAME,\ COLLAB_2_POOL_NAME"Este
Dockerfileusa una compilación de varias etapas para compilar primero el código de Go y, luego, copiar la versión compilada de ese código en el contenedor de carga de trabajo final. También permite usar variables de entorno específicas en ese contenedor de carga de trabajo. Los valores de estas variables de entorno se asignan más adelante a los recursos específicos en los que debe operar la carga de trabajo.Haz clic en Abrir terminal para volver a Cloud Shell o invoca la terminal integrada en el Editor de Cloud Shell desde el menú Ver.
Crea un repositorio de Docker en Artifact Registry:
gcloud artifacts repositories create REPOSITORY_NAME \ --repository-format=docker \ --location=usOtorga a la cuenta de servicio que ejecutará la carga de trabajo el rol de lector de Artifact Registry (
roles/artifactregistry.reader) para que pueda leer desde el repositorio: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.readerActualiza tus credenciales de Docker para incluir el nombre de dominio
us-docker.pkg.dev:gcloud auth configure-docker us-docker.pkg.devPara crear una imagen de Docker a partir de
Dockerfile, ingresa el siguiente comando en la terminal:docker build -t \ "us-docker.pkg.dev/ALEX_PROJECT_ID/\ REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest" .Envía la imagen de Docker a Artifact Registry:
docker push \ us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAMELa respuesta de Docker push enumera el resumen SHA256 de la imagen, que se necesita más adelante para autorizar la carga de trabajo. El resumen es similar al siguiente ejemplo:
sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Copia el resumen de la imagen (incluido el prefijo
sha256:) en un lugar donde puedas consultarlo. También puedes ingresar el resumen en la siguiente muestra de código para completar previamente el resto de las muestras de código de esta guía que necesiten el valor:WORKLOAD_CONTAINER_IMAGE_DIGESTAsegúrate de que todas las partes auditen la imagen de Docker y verifiquen que sea confiable antes de autorizar su uso.
Autoriza la carga de trabajo
Con la carga de trabajo aprobada por ambas partes, Alex y Bola deben agregar la certificación de Google Cloud como proveedor a sus grupos de Workload Identity. El proveedor especifica el servicio de certificación que se usará y las propiedades que la carga de trabajo debe cumplir para que se le permita operar con los datos de Alex o Bola. Si un actor malicioso cambia la imagen de Docker o altera otra propiedad medida, se deniega el acceso a la carga de trabajo.
En esta guía, se usan asignaciones de atributos para proporcionar acceso directo a los recursos a la carga de trabajo según el resumen de la imagen. Sin embargo, en otras situaciones, es posible que prefieras usar la identidad temporal como cuenta de servicio para acceder a los recursos. Consulta Acceso a cargas de trabajo externas para obtener más información.
Para configurar los proveedores de Alex y Bola con las condiciones requeridas, completa los siguientes pasos:
Ingresa el siguiente comando para crear el proveedor de 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'"Obtén el número de proyecto de Alex para el siguiente comando:
gcloud projects describe ALEX_PROJECT_ID --format="value(projectNumber)"Otorga a la identidad federada definida por el proveedor de Alex el rol
cloudkms.cryptoKeyDecryptery especifica el atributoimage_digestpara que solo los contenedores de cargas de trabajo con el resumen especificado puedan desencriptar sus claves de 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.cryptoKeyDecrypterCambia al proyecto de Bola:
gcloud config set project BOLA_PROJECT_IDIngresa el siguiente comando para crear el proveedor de 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'"Obtén el número de proyecto de Bola para el siguiente comando:
gcloud projects describe BOLA_PROJECT_ID --format="value(projectNumber)"Otorga a la identidad federada definida por el proveedor de Bola el rol
cloudkms.cryptoKeyDecryptery especifica el atributoimage_digestpara que solo los contenedores de cargas de trabajo con el resumen especificado puedan descifrar sus claves de 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
Prueba la carga de trabajo
Con los proveedores agregados a los grupos de identidades de cargas de trabajo de Alex y Bola, y los recursos necesarios, es momento de que el operador de la carga de trabajo pruebe la carga de trabajo.
Para probar la carga de trabajo, crearás una instancia de Confidential VM nueva en el proyecto de Bola que tenga las siguientes propiedades:
Una configuración compatible con SEV de AMD, TDX de Intel o TDX de Intel con NVIDIA Confidential Computing (vista previa).
El inicio seguro está habilitado.
Un SO basado en la imagen de depuración de Confidential Space para facilitar la solución de problemas
Es una referencia a la imagen de Docker que Alex creó anteriormente. Se carga sobre la imagen de Confidential Space.
Una cuenta de servicio que Bola creó anteriormente y que ejecuta la carga de trabajo.
STDOUTySTDERRse redireccionan a Cloud Logging y a la consola serie.Son los detalles del recurso que necesita la carga de trabajo, configurados como variables de entorno.
Ingresa el siguiente comando en Cloud Shell de Bola para probar la carga de trabajo:
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\
~tee-env-COLLAB_1_NAME=Alex\
~tee-env-COLLAB_2_NAME=Bola\
~tee-env-COLLAB_1_ENCRYPTED_SALARY=ALEX_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_2_ENCRYPTED_SALARY=BOLA_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_1_INPUT_BUCKET=ALEX_INPUT_BUCKET_NAME\
~tee-env-COLLAB_2_INPUT_BUCKET=BOLA_INPUT_BUCKET_NAME\
~tee-env-COLLAB_1_OUTPUT_BUCKET=ALEX_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_2_OUTPUT_BUCKET=BOLA_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_1_KEYRING_NAME=ALEX_KEYRING_NAME\
~tee-env-COLLAB_2_KEYRING_NAME=BOLA_KEYRING_NAME\
~tee-env-COLLAB_1_KEY_NAME=ALEX_KEY_NAME\
~tee-env-COLLAB_2_KEY_NAME=BOLA_KEY_NAME\
~tee-env-COLLAB_1_PROJECT_ID=ALEX_PROJECT_ID\
~tee-env-COLLAB_2_PROJECT_ID=BOLA_PROJECT_ID\
~tee-env-COLLAB_1_PROJECT_NUMBER=ALEX_PROJECT_NUMBER\
~tee-env-COLLAB_2_PROJECT_NUMBER=BOLA_PROJECT_NUMBER\
~tee-env-COLLAB_1_POOL_NAME=ALEX_POOL_NAME\
~tee-env-COLLAB_2_POOL_NAME=BOLA_POOL_NAME"
Ver progreso
Puedes ver el progreso de la carga de trabajo en el proyecto de Bola en el Explorador de registros.
Para mostrar solo las entradas de registro de Confidential Space, filtra por los siguientes Campos de registro, si están disponibles:
Tipo de recurso: Instancia de VM
ID de instancia: El ID de instancia de VM
Nombre del registro: confidential-space-launcher
Para actualizar el registro, haz clic en Pasar a los más recientes. También puedes desplazarte a resultados anteriores y, luego, volver a desplazarte al final del registro para cargar las entradas más recientes.
Vea los resultados
Si la tarea de la carga de trabajo finaliza y devuelve 0, significa que no se produjeron errores y es hora de verificar el resultado en los buckets de salida de Alex y Bola:
Cambia al proyecto de Alex:
gcloud config set project ALEX_PROJECT_IDEnumera todos los archivos en su bucket de resultados:
gcloud storage ls gs://ALEX_OUTPUT_BUCKET_NAMELee el archivo más reciente que se muestra en la lista y reemplaza
ALEX_OUTPUT_CLOUD_STORAGE_PATHpor la ruta de acceso del archivo, incluido elgs://:gcloud storage cat ALEX_OUTPUT_CLOUD_STORAGE_PATHSi no hay ningún archivo, debes depurar tu carga de trabajo.
Cambia al proyecto de Bola:
gcloud config set project BOLA_PROJECT_IDEnumera todos los archivos en su bucket de resultados:
gcloud storage ls gs://BOLA_OUTPUT_BUCKET_NAMELee el archivo más reciente que aparece en la lista y reemplaza
BOLA_RESULTS_CLOUD_STORAGE_PATHpor la ruta de acceso del archivo, incluido elgs://:gcloud storage cat BOLA_RESULTS_CLOUD_STORAGE_PATHSi no hay ningún archivo, debes depurar tu carga de trabajo.
Después de leer los resultados correctamente, detén la instancia de VM:
gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b
Al leer los archivos, Alex y Bola descubren quién gana más sin revelar sus salarios entre sí.
Depura y reinicia la carga de trabajo
Un entorno de Confidential Space tiene muchas partes, y es posible que algo se haya configurado de forma incorrecta, lo que provoca que la carga de trabajo falle.
A diferencia de la imagen de Confidential Space de producción, la imagen de depuración mantiene la instancia de VM en ejecución después de que finaliza la carga de trabajo. Esto significa que, si los registros no revelan suficiente información para resolver el problema, el siguiente paso es conectarte a tu instancia de VM a través de SSH y continuar con la depuración.
Después de terminar la depuración, detén la instancia de VM:
gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b
Para ejecutar la carga de trabajo en el entorno depurado, reinicia la VM:
gcloud compute instances start WORKLOAD_VM_2_NAME --zone=us-west1-b
Protege el entorno para la producción
Después de probar la carga de trabajo correctamente, es hora de proteger el entorno de Confidential Space para la implementación en producción. Alex y Bola deben agregar una aserción support_attributes a sus proveedores para verificar que se use la imagen de Confidential Space de producción para la carga de trabajo:
Cambia al proyecto de Alex:
gcloud config set project ALEX_PROJECT_IDIngresa el siguiente comando para actualizar el proveedor de Alex:
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' \ && 'STABLE' in assertion.submods.confidential_space.support_attributes"Cambia al proyecto de Bola:
gcloud config set project BOLA_PROJECT_IDIngresa el siguiente comando para actualizar el proveedor de Bola:
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' \ && 'STABLE' in assertion.submods.confidential_space.support_attributes"
Implementa la carga de trabajo de producción
Bola necesita crear una instancia de VM independiente para ejecutar la carga de trabajo de producción. Las siguientes características son diferentes en comparación con la carga de trabajo de prueba:
El SO se basa en la imagen de Confidential Space de producción. Tiene SSH inhabilitado y la instancia de VM se detiene después de que finaliza la carga de trabajo.
Se quitó el redireccionamiento de registros. En Cloud Logging, solo se muestran los registros básicos que no exponen información sensible.
Ingresa el siguiente comando en Cloud Shell de Bola para implementar la carga de trabajo de producción:
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\
~tee-env-COLLAB_1_NAME=Alex\
~tee-env-COLLAB_2_NAME=Bola\
~tee-env-COLLAB_1_ENCRYPTED_SALARY=ALEX_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_2_ENCRYPTED_SALARY=BOLA_ENCRYPTED_SALARY_FILE\
~tee-env-COLLAB_1_INPUT_BUCKET=ALEX_INPUT_BUCKET_NAME\
~tee-env-COLLAB_2_INPUT_BUCKET=BOLA_INPUT_BUCKET_NAME\
~tee-env-COLLAB_1_OUTPUT_BUCKET=ALEX_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_2_OUTPUT_BUCKET=BOLA_OUTPUT_BUCKET_NAME\
~tee-env-COLLAB_1_KEYRING_NAME=ALEX_KEYRING_NAME\
~tee-env-COLLAB_2_KEYRING_NAME=BOLA_KEYRING_NAME\
~tee-env-COLLAB_1_KEY_NAME=ALEX_KEY_NAME\
~tee-env-COLLAB_2_KEY_NAME=BOLA_KEY_NAME\
~tee-env-COLLAB_1_PROJECT_ID=ALEX_PROJECT_ID\
~tee-env-COLLAB_2_PROJECT_ID=BOLA_PROJECT_ID\
~tee-env-COLLAB_1_PROJECT_NUMBER=ALEX_PROJECT_NUMBER\
~tee-env-COLLAB_2_PROJECT_NUMBER=BOLA_PROJECT_NUMBER\
~tee-env-COLLAB_1_POOL_NAME=ALEX_POOL_NAME\
~tee-env-COLLAB_2_POOL_NAME=BOLA_POOL_NAME"
La forma en que ves el progreso y ves los resultados es la misma que cuando probaste la carga de trabajo.
Cuando finaliza la carga de trabajo de producción, la instancia de VM se detiene. Para ver resultados diferentes, puedes cambiar los salarios, volver a encriptarlos, volver a subirlos a los buckets de Cloud Storage respectivos y, luego, reiniciar la instancia de VM para volver a ejecutar la carga de trabajo:
gcloud compute instances start WORKLOAD_VM_NAME --zone=us-west1-b
Limpieza
Para quitar los recursos creados en esta guía, completa las siguientes instrucciones.
Limpia los recursos de Alex
Cambia al proyecto de Alex:
gcloud config set project ALEX_PROJECT_IDBorra el grupo de Workload Identity de Alex:
gcloud iam workload-identity-pools delete ALEX_POOL_NAME \ --location=globalBorra los buckets de Cloud Storage de Alex:
gcloud storage rm gs://ALEX_INPUT_BUCKET_NAME \ gs://ALEX_OUTPUT_BUCKET_NAME --recursiveBorra los archivos de salario de Alex, el código de Go y el archivo
Dockerfile:rm ALEX_SALARY.txt \ ALEX_ENCRYPTED_SALARY_FILE \ salary.go \ DockerfileOpcional: Inhabilita o destruye la clave de Cloud Key Management Service de Alex.
Opcional: Cierra el proyecto de Alex.
Limpia los recursos de Bola
Cambia al proyecto de Bola:
gcloud config set project BOLA_PROJECT_IDBorra la VM que ejecutó el flujo de trabajo de prueba:
gcloud compute instances delete WORKLOAD_VM_2_NAME --zone=us-west1-bBorra la VM que ejecutó el flujo de trabajo de producción:
gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-bBorra la cuenta de servicio que ejecutó la carga de trabajo:
gcloud iam service-accounts delete \ WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.comBorra el grupo de Workload Identity de Bola:
gcloud iam workload-identity-pools delete BOLA_POOL_NAME \ --location=globalBorra los buckets de Cloud Storage de Bola:
gcloud storage rm gs://BOLA_INPUT_BUCKET_NAME \ gs://BOLA_OUTPUT_BUCKET_NAME --recursiveBorra los archivos de salario de Bola:
rm BOLA_SALARY.txt \ BOLA_ENCRYPTED_SALARY_FILEOpcional: Inhabilita o destruye la clave de Cloud Key Management Service de Bola.
Opcional: Cierra el proyecto de Bola.