Cómo realizar transacciones de recursos digitales con computación de varias partes y Confidential Space

1. Descripción general

Antes de comenzar, aunque no es del todo necesario, te será útil tener conocimientos prácticos de las siguientes funciones y conceptos en este codelab.

4670cd5427aa39a6.png

Qué aprenderás

En este lab, se proporciona una implementación de referencia para realizar la firma de cadenas de bloques que cumpla con MPC con el uso del espacio confidencial. Para ilustrar los conceptos, analizaremos una situación en la que la empresa Primus quiere transferir activos digitales a la empresa Secundus. En esta situación, la empresa Primus usa un modelo compatible con MPC, lo que significa que, en lugar de usar claves privadas individuales, usa partes de claves distribuidas. Estas partes clave están en manos de varias partes, en este caso, Alicia y Roberto. Este enfoque le brinda a la empresa Primus varios beneficios, como una experiencia del usuario simplificada, eficiencia operativa y control sobre sus claves privadas.

Para explicar los aspectos fundamentales de este proceso, detallaremos la configuración técnica y te guiaremos por el proceso de aprobación y firma que inicia la transferencia de activos digitales de la Empresa Primus a la Empresa Secundus. Ten en cuenta que Roberto y Alicia, que son empleados de la empresa Primus, deben aprobar la transacción.

Si bien esta implementación de referencia demuestra operaciones de firma, no abarca todos los aspectos de la administración de claves de MPC. Por ejemplo, no hablamos de la generación de claves. Además, existen enfoques alternativos y complementarios, como usar servicios que no son de Google Cloud para generar cofirmas o hacer que los cosignatarios construyan firmas de cadena de bloques en sus propios entornos, que es una arquitectura más descentralizada. Esperamos que este lab inspire diferentes enfoques para la MPC en Google Cloud.

Trabajarás con una carga de trabajo simple que firme una transacción de Ethereum en Confidential Space con materiales de claves de cofirmatario. La firma de transacciones de Ethereum es un proceso mediante el cual un usuario puede autorizar una transacción en la cadena de bloques de Ethereum. Para enviar una transacción de Ethereum, debes firmarla con tu clave privada. De esta manera, demuestras que eres el propietario de la cuenta y autorizas la transacción. El proceso de firma es el siguiente:

  1. El remitente crea un objeto de transacción que especifica la dirección del destinatario, la cantidad de ETH que se enviará y cualquier otro dato relevante.
  2. La clave privada del remitente se usa para generar un hash de los datos de la transacción.
  3. Luego, el hash se firma con la clave privada.
  4. La firma se adjunta al objeto de transacción.
  5. La transacción se transmite a la red de Ethereum.

Cuando un nodo de la red recibe una transacción, verifica la firma para asegurarse de que el propietario de la cuenta la haya firmado. Si la firma es válida, el nodo agregará la transacción a la cadena de bloques.

Para comenzar, configurarás los recursos de Cloud necesarios. Luego, ejecutarás la carga de trabajo en Confidential Space. En este codelab, se te guiará a través de los siguientes pasos de alto nivel:

  • Cómo configurar los recursos de Cloud necesarios para ejecutar Confidential Space
  • Cómo autorizar el acceso a recursos protegidos según los atributos de lo siguiente:
  • Qué: El contenedor de la carga de trabajo
  • Dónde: el entorno de Confidential Space (la imagen de Confidential Space en la Confidential VM)
  • Quién: La cuenta que ejecuta la carga de trabajo
  • Cómo ejecutar la carga de trabajo en una Confidential VM que ejecuta la imagen de VM de Confidential Space

APIs requeridas

Debes habilitar las siguientes APIs en los proyectos especificados para poder completar esta guía.

Nombre de la API

Título de la API

cloudkms.googleapis.com

Cloud KMS

compute.googleapis.com

Compute Engine

confidentialcomputing.googleapis.com

Confidential Computing

iamcredentials.googleapis.com

IAM

artifactregistry.googleapis.com

Artifact Registry

2. Configura recursos de Cloud

Antes de comenzar

  • Clona este repositorio con el siguiente comando para obtener las secuencias de comandos necesarias que se usan como parte de este codelab.
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • Cambia el directorio de este codelab.
cd confidential-space/codelabs/digital_asset_transaction_codelab/scripts
  • Asegúrate de haber configurado las variables de entorno del proyecto requeridas como se muestra a continuación. Para obtener más información sobre cómo configurar un proyecto de GCP, consulta este codelab. Puedes consultar este artículo para obtener detalles sobre cómo recuperar el ID del proyecto y en qué se diferencia del nombre y el número del proyecto. .
export PRIMUS_PROJECT_ID=<GCP project id>
  • Habilita la facturación para tus proyectos.
  • Habilita la API de Confidential Computing y las siguientes APIs para ambos proyectos.
gcloud services enable \
   cloudapis.googleapis.com \
    cloudkms.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    iam.googleapis.com \
    confidentialcomputing.googleapis.com
  • Para establecer las variables de los nombres de los recursos, puedes usar el siguiente comando. Ten en cuenta que esto anulará los nombres de recursos específicos de tu proyecto de GCP para la empresa A, por ejemplo, export PRIMUS_INPUT_STORAGE_BUCKET='primus-input-bucket'.
  • Puedes configurar las siguientes variables para tu proyecto de GCP en la Empresa A:

$PRIMUS_INPUT_STORAGE_BUCKET

Es el bucket que almacena las claves encriptadas.

$PRIMUS_RESULT_STORAGE_BUCKET

Es el bucket que almacena el resultado de la transacción de MPC.

$PRIMUS_KEY

La clave de KMS que se usa para encriptar los datos almacenados en $PRIMUS_INPUT_STORAGE_BUCKET para Primus Bank.

$PRIMUS_KEYRING

El llavero de KMS que se usará para crear la clave de encriptación $PRIMUS_KEY para Primus Bank.

$PRIMUS_WIP_PROVIDER

El proveedor del grupo de Workload Identity, que incluye la condición de atributo que se usará para los tokens firmados por el servicio de carga de trabajo de MPC

$PRIMUS_SERVICEACCOUNT

Es la cuenta de servicio que usa $PRIMUS_WORKLOAD_IDENTITY_POOL para acceder a los recursos protegidos. Esta cuenta de servicio tendrá permiso para ver las claves encriptadas que se almacenan en el bucket $PRIMUS_INPUT_STORAGE_BUCKET.

$PRIMUS_ARTIFACT_REPOSITORY

El repositorio de artefactos para almacenar la imagen del contenedor de la carga de trabajo

$WORKLOAD_SERVICEACCOUNT

La cuenta de servicio que tiene permiso para acceder a la VM confidencial que ejecuta la carga de trabajo.

$WORKLOAD_CONTAINER

El contenedor de Docker que ejecuta la carga de trabajo

$WORKLOAD_IMAGE_NAME

Es el nombre de la imagen del contenedor de la carga de trabajo.

$WORKLOAD_IMAGE_TAG

Es la etiqueta de la imagen del contenedor de la carga de trabajo.

  • Ejecuta la siguiente secuencia de comandos para establecer los nombres de las variables restantes en valores basados en el ID de tu proyecto para los nombres de los recursos.
source config_env.sh

Configura los recursos de Cloud

Como parte de este paso, configurarás los recursos de la nube necesarios para el procesamiento multipartido. En este lab, usarás la siguiente clave privada: 0000000000000000000000000000000000000000000000000000000000000001

En un entorno de producción, generarás tu propia clave privada. Sin embargo, para los fines de este lab, dividiremos esta clave privada en dos partes y encriptaremos cada una. En un entorno de producción, las claves nunca deben almacenarse en archivos de texto simple. En su lugar, la clave privada se puede generar fuera de Google Cloud (o se puede omitir por completo y reemplazar con la creación de fragmentos de claves de MPC personalizados) y, luego, encriptar para que nadie tenga acceso a la clave privada ni a los fragmentos de clave. Para los fines de este lab, usaremos la CLI de Gcloud.

Ejecuta la siguiente secuencia de comandos para configurar los recursos de nube necesarios. Como parte de estos pasos, se crearán los siguientes recursos:

  • Un bucket de Cloud Storage ($PRIMUS_INPUT_STORAGE_BUCKET) para almacenar los permisos de clave privada encriptados
  • Un bucket de Cloud Storage ($PRIMUS_RESULT_STORAGE_BUCKET) para almacenar el resultado de la transacción de activos digitales
  • Una clave de encriptación ($PRIMUS_KEY) y un llavero ($PRIMUS_KEYRING) en KMS para encriptar los fragmentos de clave privada
  • Un grupo de Workload Identity ($PRIMUS_WORKLOAD_IDENTITY_POOL) para validar los reclamos en función de las condiciones de los atributos configurados en su proveedor
  • Una cuenta de servicio ($PRIMUS_SERVICEACCOUNT) adjunta al grupo de identidades para cargas de trabajo ($PRIMUS_WORKLOAD_IDENTITY_POOL) mencionado anteriormente con el siguiente acceso de IAM:
  • roles/cloudkms.cryptoKeyDecrypter para desencriptar los datos con la clave de KMS.
  • objectViewer para leer datos del bucket de Cloud Storage
  • roles/iam.workloadIdentityUser para conectar esta cuenta de servicio al grupo de identidades para cargas de trabajo.
./setup_resources.sh

3. Crear carga de trabajo

Crea una cuenta de servicio de la carga de trabajo

Ahora, crearás una cuenta de servicio para la carga de trabajo con los roles y permisos necesarios. Para ello, ejecuta la siguiente secuencia de comandos, que creará una cuenta de servicio de carga de trabajo para la Empresa A. La VM que ejecuta la carga de trabajo usará esta cuenta de servicio.

La cuenta de servicio de la carga de trabajo ($WORKLOAD_SERVICEACCOUNT) tendrá los siguientes roles:

  • confidentialcomputing.workloadUser para obtener un token de certificación
  • logging.logWriter para escribir registros en Cloud Logging.
  • objectViewer para leer datos del bucket de Cloud Storage $PRIMUS_INPUT_STORAGE_BUCKET
  • objectUser para escribir el resultado de la carga de trabajo en el bucket de Cloud Storage $PRIMUS_RESULT_STORAGE_BUCKET.
./create_workload_service_account.sh

Cómo crear una carga de trabajo

Este paso implica crear una imagen de Docker de la carga de trabajo. La carga de trabajo de este codelab es una aplicación MPC simple de Node.js que firma transacciones digitales para transferir activos con partes de claves privadas encriptadas. Aquí se muestra el código del proyecto de carga de trabajo. El proyecto de carga de trabajo incluye los siguientes archivos.

package.json: Este archivo contiene la lista de paquetes que se deben usar para la aplicación de MPC de la carga de trabajo. En este caso, usamos las bibliotecas @google-cloud/kms, @google-cloud/storage, ethers y fast-crc32c. Este es el archivo package.json que usaremos para este codelab.

index.js: Es un punto de entrada de la aplicación de la carga de trabajo y especifica qué comandos se deben ejecutar cuando se inicia el contenedor de la carga de trabajo. También incluimos una transacción sin firmar de muestra que, por lo general, proporcionaría una aplicación no confiable que les solicita a los usuarios su firma. Este archivo index.js también importa funciones de mpc.js, que crearemos a continuación. A continuación, se muestra el contenido del archivo index.js, que también puedes encontrar aquí.

import {signTransaction, submitTransaction, uploadFromMemory} from './mpc.js';

const signAndSubmitTransaction = async () => {
  try {
    // Create the unsigned transaction object
    const unsignedTransaction = {
      nonce: 0,
      gasLimit: 21000,
      gasPrice: '0x09184e72a000',
      to: '0x0000000000000000000000000000000000000000',
      value: '0x00',
      data: '0x',
    };

    // Sign the transaction
    const signedTransaction = await signTransaction(unsignedTransaction);

    // Submit the transaction to Ganache
    const transaction = await submitTransaction(signedTransaction);

    // Write the transaction receipt
    uploadFromMemory(transaction);

    return transaction;
  } catch (e) {
    console.log(e);
    uploadFromMemory(e);
  }
};

await signAndSubmitTransaction();

mpc.js: Aquí es donde se realiza la firma de la transacción. Importa funciones de kms-decrypt y credential-config, que analizaremos a continuación. A continuación, se muestra el contenido del archivo mpc.js, que también puedes encontrar aquí.

import {Storage} from '@google-cloud/storage';
import {ethers} from 'ethers';

import {credentialConfig} from './credential-config.js';
import {decryptSymmetric} from './kms-decrypt.js';

const providers = ethers.providers;
const Wallet = ethers.Wallet;

// The ID of the GCS bucket holding the encrypted keys
const bucketName = process.env.KEY_BUCKET;

// Name of the encrypted key files.
const encryptedKeyFile1 = 'alice_encrypted_key_share';
const encryptedKeyFile2 = 'bob_encrypted_key_share';

// Create a new storage client with the credentials
const storageWithCreds = new Storage({
  credentials: credentialConfig,
});

// Create a new storage client without the credentials
const storage = new Storage();

const downloadIntoMemory = async (keyFile) => {
  // Downloads the file into a buffer in memory.
  const contents =
      await storageWithCreds.bucket(bucketName).file(keyFile).download();

  return contents;
};

const provider =
    new providers.JsonRpcProvider(`http://${process.env.NODE_URL}:80`);

export const signTransaction = async (unsignedTransaction) => {
  /* Check if Alice and Bob have both approved the transaction
  For this example, we're checking if their encrypted keys are available. */
  const encryptedKey1 =
      await downloadIntoMemory(encryptedKeyFile1).catch(console.error);
  const encryptedKey2 =
      await downloadIntoMemory(encryptedKeyFile2).catch(console.error);

  // For each key share, make a call to KMS to decrypt the key
  const privateKeyshare1 = await decryptSymmetric(encryptedKey1[0]);
  const privateKeyshare2 = await decryptSymmetric(encryptedKey2[0]);

  /* Perform the MPC calculations
  In this example, we're combining the private key shares
  Alternatively, you could import your mpc calculations here */
  const wallet = new Wallet(privateKeyshare1 + privateKeyshare2);

  // Sign the transaction
  const signedTransaction = await wallet.signTransaction(unsignedTransaction);

  return signedTransaction;
};

export const submitTransaction = async (signedTransaction) => {
  // This can now be sent to Ganache
  const hash = await provider.sendTransaction(signedTransaction);
  return hash;
};

export const uploadFromMemory = async (contents) => {
  // Upload the results to the bucket without service account impersonation
  await storage.bucket(process.env.RESULTS_BUCKET)
      .file('transaction_receipt_' + Date.now())
      .save(JSON.stringify(contents));
};

kms-decrypt.js: Este archivo contiene el código para la desencriptación con claves administradas en KMS. A continuación, se muestra el contenido del archivo kms-decrypt.js, que también puedes encontrar aquí.

import {KeyManagementServiceClient} from '@google-cloud/kms';
import crc32c from 'fast-crc32c';

import {credentialConfig} from './credential-config.js';

const projectId = process.env.PRIMUS_PROJECT_ID;
const locationId = process.env.PRIMUS_LOCATION;
const keyRingId = process.env.PRIMUS_ENC_KEYRING;
const keyId = process.env.PRIMUS_ENC_KEY;

// Instantiates a client
const client = new KeyManagementServiceClient({
  credentials: credentialConfig,
});

// Build the key name
const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

export const decryptSymmetric = async (ciphertext) => {
  const ciphertextCrc32c = crc32c.calculate(ciphertext);
  const [decryptResponse] = await client.decrypt({
    name: keyName,
    ciphertext,
    ciphertextCrc32c: {
      value: ciphertextCrc32c,
    },
  });

  // Optional, but recommended: perform integrity verification on
  // decryptResponse. For more details on ensuring E2E in-transit integrity to
  // and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (crc32c.calculate(decryptResponse.plaintext) !==
      Number(decryptResponse.plaintextCrc32c.value)) {
    throw new Error('Decrypt: response corrupted in-transit');
  }

  const plaintext = decryptResponse.plaintext.toString();

  return plaintext;
};

credential-config.js: El archivo almacena las rutas de acceso y los detalles del grupo de identidades de la carga de trabajo para la suplantación de identidad de la cuenta de servicio. Este es el archivo credential-config.js que usaremos para este codelab.

Dockerfile: Por último, crearemos nuestro Dockerfile que se usará para compilar la imagen de Docker de la carga de trabajo. Define el Dockerfile como se especifica aquí.

FROM node:16.18.0

ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

LABEL "tee.launch_policy.allow_cmd_override"="true"
LABEL "tee.launch_policy.allow_env_override"="NODE_URL,RESULTS_BUCKET,KEY_BUCKET,PRIMUS_PROJECT_NUMBER,PRIMUS_PROJECT_ID,PRIMUS_WORKLOAD_IDENTITY_POOL,PRIMUS_WIP_PROVIDER,PRIMUS_SERVICEACCOUNT,PRIMUS_ENC_KEYRING,PRIMUS_ENC_KEY"

CMD [ "node", "index.js" ]

Nota: LABEL "tee.launch_policy.allow_cmd_override"="true" en el Dockerfile es una política de inicio establecida por el autor de la imagen. Permite que el operador anule el CMD cuando ejecuta la carga de trabajo. De forma predeterminada, allow_cmd_override se establece como falso. La etiqueta "tee.launch_policy.allow_env_override" le indica a Confidential Space qué variables de entorno pueden usar los usuarios de la imagen .

Ejecuta la siguiente secuencia de comandos para crear una carga de trabajo en la que se realicen los siguientes pasos:

  • Crea Artifact Registry($PRIMUS_ARTIFACT_REPOSITORY) para almacenar la imagen de Docker de la carga de trabajo.
  • Actualiza el código de la carga de trabajo con los nombres de los recursos necesarios. Aquí se muestra el código de la carga de trabajo que se usa en este codelab.
  • Crea un Dockerfile para compilar una imagen de Docker del código de la carga de trabajo. Puedes encontrar el Dockerfile aquí.
  • Compila y publica la imagen de Docker en Artifact Registry ($PRIMUS_ARTIFACT_REPOSITORY) que creaste en el paso anterior.
  • Otorga permiso de lectura a $WORKLOAD_SERVICEACCOUNT para $PRIMUS_ARTIFACT_REPOSITORY. Esto es necesario para que el contenedor de la carga de trabajo extraiga la imagen de Docker de la carga de trabajo de Artifact Registry.
./create_workload.sh

Crea el nodo de cadena de bloques

Nodo de Ethereum de Ganache

Antes de autorizar la carga de trabajo, debemos crear la instancia de Ethereum Ganache. La transacción firmada se enviará a esta instancia de Ganache. Anota la dirección IP de esta instancia. Después de ejecutar el siguiente comando, es posible que debas ingresar y para habilitar la API.

gcloud compute instances create-with-container ${ETHEREUM_NODE} \
  --zone=${PRIMUS_PROJECT_ZONE} \
  --tags=http-server \
  --project=${PRIMUS_PROJECT_ID} \
  --shielded-secure-boot \
  --shielded-vtpm \
  --shielded-integrity-monitoring \
  --container-image=docker.io/trufflesuite/ganache:v7.7.3 \
--container-arg=--wallet.accounts=\"0x0000000000000000000000000000000000000000000000000000000000000001,0x21E19E0C9BAB2400000\" \
  --container-arg=--port=80

4. Autoriza y ejecuta la carga de trabajo

Autoriza la carga de trabajo

Como parte de este paso, configuraremos el proveedor del grupo de identidades para cargas de trabajo en el grupo de identidades para cargas de trabajo ($PRIMUS_WORKLOAD_IDENTITY_POOL). Hay condiciones de atributos configuradas para la identidad de carga de trabajo, como se muestra a continuación. Una de las condiciones es validar que la imagen de la carga de trabajo se extraiga del repositorio de artefactos esperado.

gcloud config set project $PRIMUS_PROJECT_ID
gcloud iam workload-identity-pools providers create-oidc ${PRIMUS_WIP_PROVIDER} \
 --location="${PRIMUS_PROJECT_LOCATION}" \
 --workload-identity-pool="$PRIMUS_WORKLOAD_IDENTITY_POOL" \
 --issuer-uri="https://confidentialcomputing.googleapis.com/" \
 --allowed-audiences="https://sts.googleapis.com" \
 --attribute-mapping="google.subject='assertion.sub'" \
 --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' && 'STABLE' in assertion.submods.confidential_space.support_attributes && assertion.submods.container.image_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' && '$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"

Ejecutar carga de trabajo

En esta sección, se explica cómo ejecutar la carga de trabajo en Confidential VM. Para ello, pasaremos los argumentos de TEE necesarios con la marca de metadatos. Además, configuraremos las variables de entorno para el contenedor de carga de trabajo con la marca "tee-env-*". La imagen tiene las siguientes variables:

  • NODE_URL: Es la URL del nodo de Ethereum que procesará la transacción firmada.
  • RESULTS_BUCKET: Es el bucket que almacena el resultado de la transacción de mpc.
  • KEY_BUCKET: Es el bucket que almacena las claves encriptadas de mpc.
  • PRIMUS_PROJECT_NUMBER: Es el número de proyecto que se usa para el archivo de configuración de credenciales.
  • PRIMUS_PROJECT_ID: Es el ID del proyecto que se usa para el archivo de configuración de credenciales. El resultado de la ejecución de la carga de trabajo se publicará en $PRIMUS_RESULT_STORAGE_BUCKET.
  • PRIMUS_WORKLOAD_IDENTITY_POOL: Es el grupo de identidades para cargas de trabajo que se usa para validar los reclamos.
  • PRIMUS_WIP_POROVIDER: Es el proveedor de grupos de identidades para cargas de trabajo que incluye las condiciones de atributo que se usarán para validar los tokens que presenta la carga de trabajo.
  • WORKLOAD_SERVICEACCOUNT: Es la cuenta de servicio de la carga de trabajo.
gcloud compute instances create $WORKLOAD_VM \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform \
 --zone=${PRIMUS_PROJECT_ZONE} \
 --project=${PRIMUS_PROJECT_ID} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
 --service-account=$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com \
 --metadata "^~^tee-image-reference=${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG~tee-restart-policy=Never~tee-env-NODE_URL=$(gcloud compute instances describe ${ETHEREUM_NODE} --format='get(networkInterfaces[0].networkIP)' --zone=${PRIMUS_PROJECT_ZONE})~tee-env-RESULTS_BUCKET=$PRIMUS_RESULT_STORAGE_BUCKET~tee-env-KEY_BUCKET=$PRIMUS_INPUT_STORAGE_BUCKET~tee-env-PRIMUS_PROJECT_ID=$PRIMUS_PROJECT_ID~tee-env-PRIMUS_PROJECT_NUMBER=$(gcloud projects describe $PRIMUS_PROJECT_ID --format="value(projectNumber)")~tee-env-PRIMUS_WORKLOAD_IDENTITY_POOL=$PRIMUS_WORKLOAD_IDENTITY_POOL~tee-env-PRIMUS_PROJECT_LOCATION=${PRIMUS_PROJECT_LOCATION}~tee-env-PRIMUS_WIP_PROVIDER=$PRIMUS_WIP_PROVIDER~tee-env-PRIMUS_SERVICEACCOUNT=$PRIMUS_SERVICEACCOUNT~tee-env-PRIMUS_KEY=${PRIMUS_KEY}~tee-env-PRIMUS_KEYRING=${PRIMUS_KEYRING}"

Verifica los resultados de Cloud Storage

Puedes ver el recibo de la transacción en Cloud Storage. Es posible que el Espacio confidencial tarde unos minutos en iniciarse y que los resultados tarden en aparecer. Sabrás que el contenedor está listo cuando la VM esté en estado detenido.

  1. Ve a la página Navegador de Cloud Storage.
  2. Haz clic en $PRIMUS_RESULT_STORAGE_BUCKET.
  3. Haz clic en el archivo transaction_receipt.
  4. Haz clic en Descargar para descargar y ver la respuesta de la transacción.

Como alternativa, puedes ejecutar los siguientes comandos para ver el resultado.

gcloud config set project $PRIMUS_PROJECT_ID
gsutil cat gs://$PRIMUS_RESULT_STORAGE_BUCKET/transaction_receipt

Nota: Si no aparecen los resultados, puedes ir a $WORKLOAD_VM en la página de la consola de Cloud de Compute Engine y hacer clic en "Puerto serie 1 (consola)" para ver los registros.

Verifica la transacción de cadena de bloques de Ganache

También puedes ver la transacción en el registro de la cadena de bloques.

  1. Ve a la página Compute Engine de Cloud.
  2. Haz clic en ${ETHEREUM_NODE} VM.
  3. Haz clic en SSH para abrir la ventana SSH en el navegador.
  4. En la ventana de SSH, ingresa sudo docker ps para ver el contenedor de Ganache en ejecución.
  5. Busca el ID del contenedor de trufflesuite/ganache:v7.7.3
  6. Ingresa sudo docker logs CONTAINER_ID reemplazando CONTAINER_ID por el ID de trufflesuite/ganache:v7.7.3.
  7. Consulta los registros de Ganache y confirma que haya una transacción en ellos.

5. Realiza una limpieza

Aquí tienes la secuencia de comandos que se puede usar para limpiar los recursos que creamos como parte de este codelab. Como parte de esta limpieza, se borrarán los siguientes recursos:

  • Bucket de almacenamiento de entrada que se usa para almacenar partes de claves encriptadas ($PRIMUS_INPUT_STORAGE_BUCKET).
  • Clave de encriptación ($PRIMUS_KEY).
  • Cuenta de servicio que se usa para acceder a recursos protegidos ($PRIMUS_SERVICEACCOUNT).
  • Grupo de identidades para cargas de trabajo ($PRIMUS_WORKLOAD_IDENTITY_POOL).
  • Cuenta de servicio de la carga de trabajo ($WORKLOAD_SERVICEACCOUNT).
  • Instancias de procesamiento de cargas de trabajo ($WORKLOAD_VM y $ETHEREUM_NODE)
  • Bucket de almacenamiento de resultados que se usa para almacenar el resultado de la transacción ($PRIMUS_RESULT_STORAGE_BUCKET).
  • Es el registro de artefactos que se usa para almacenar la imagen de la carga de trabajo ($PRIMUS_ARTIFACT_REPOSITORY).
./cleanup.sh

Si ya terminaste de explorar, considera borrar tu proyecto.

  • Ve a la consola de Cloud Platform.
  • Selecciona el proyecto que deseas cerrar y, luego, haz clic en “Borrar” en la parte superior. Esta acción programa la eliminación del proyecto.

¿Qué sigue?

Consulta algunos de estos codelabs similares…

Lecturas adicionales