วิธีทำธุรกรรมเนื้อหาดิจิทัลด้วยการประมวลผลจากหลายฝ่ายและพื้นที่ลับ

1. ภาพรวม

ก่อนจะเริ่มต้น แม้ว่าจะไม่ใช่สิ่งจําเป็นทั้งหมด แต่ความรู้เกี่ยวกับฟีเจอร์และแนวคิดต่อไปนี้จะเป็นประโยชน์ในโค้ดแล็บนี้

4670cd5427aa39a6.png

สิ่งที่คุณจะได้เรียนรู้

ห้องทดลองนี้แสดงการใช้งานอ้างอิงสำหรับการลงนามบล็อกเชนที่เป็นไปตามข้อกำหนด MPC โดยใช้พื้นที่ส่วนบุคคล เราจะอธิบายแนวคิดนี้โดยใช้สถานการณ์สมมติที่บริษัท Primus ต้องการโอนเนื้อหาดิจิทัลไปยังบริษัท Secundus ในกรณีนี้ บริษัท Primus ใช้รูปแบบที่เป็นไปตาม MPC ซึ่งหมายความว่าจะใช้ส่วนแบ่งคีย์ที่กระจายแทนการใช้คีย์ส่วนตัวแต่ละรายการ บุคคลหลายฝ่ายจะถือครองส่วนแบ่งคีย์เหล่านี้ ซึ่งในกรณีนี้ได้แก่ ขวัญใจและบัญชา แนวทางนี้ให้ประโยชน์หลายประการแก่ Company Primus ซึ่งรวมถึงประสบการณ์การใช้งานที่ง่ายขึ้น ประสิทธิภาพการปฏิบัติงาน และการควบคุมคีย์ส่วนตัว

เราจะอธิบายแง่มุมพื้นฐานของกระบวนการนี้โดยละเอียด รวมถึงอธิบายการตั้งค่าทางเทคนิคและแนะนำขั้นตอนอนุมัติและการลงนามที่เริ่มต้นการโอนเนื้อหาดิจิทัลจากบริษัท Primus ไปยังบริษัท Secundus โปรดทราบว่า Bob และ Alice ซึ่งเป็นพนักงานของบริษัท Primus จะต้องอนุมัติธุรกรรม

แม้ว่าการใช้งานอ้างอิงนี้จะสาธิตการดำเนินการเกี่ยวกับลายเซ็น แต่ก็ไม่ได้ครอบคลุมทุกแง่มุมของการจัดการคีย์ MPC ตัวอย่างเช่น เราไม่พูดถึงการสร้างคีย์ นอกจากนี้ ยังมีแนวทางอื่นๆ ที่ใช้ร่วมกันได้ เช่น การใช้บริการที่ไม่ใช่ Google Cloud เพื่อสร้างลายเซ็นร่วม หรือให้ผู้ร่วมลงนามสร้างลายเซ็นบล็อกเชนในสภาพแวดล้อมของตนเอง ซึ่งเป็นสถาปัตยกรรมแบบกระจายอำนาจมากขึ้น เราหวังว่าห้องทดลองนี้จะสร้างแรงบันดาลใจให้ใช้แนวทางต่างๆ กับ MPC ใน Google Cloud

คุณจะต้องทำงานกับเวิร์กโหลดง่ายๆ ที่ลงนามในธุรกรรม Ethereum ในพื้นที่ทำงานที่เป็นความลับโดยใช้วัสดุคีย์ของผู้ร่วมลงนาม การรับรองธุรกรรม Ethereum คือกระบวนการที่ผู้ใช้สามารถให้สิทธิ์ธุรกรรมในบล็อกเชน Ethereum หากต้องการส่งธุรกรรม Ethereum คุณต้องลงนามด้วยคีย์ส่วนตัว ซึ่งจะพิสูจน์ว่าคุณเป็นเจ้าของบัญชีและได้รับอนุญาตให้ทำธุรกรรม ขั้นตอนการลงนามมีดังนี้

  1. ผู้ส่งจะสร้างออบเจ็กต์ธุรกรรมที่ระบุที่อยู่ผู้รับ จำนวน ETH ที่จะส่ง และข้อมูลอื่นๆ ที่เกี่ยวข้อง
  2. ระบบจะใช้คีย์ส่วนตัวของผู้ส่งเพื่อแฮชข้อมูลธุรกรรม
  3. จากนั้นจึงใช้คีย์ส่วนตัวลงนามแฮช
  4. ลายเซ็นจะแนบอยู่กับออบเจ็กต์ธุรกรรม
  5. ระบบจะออกอากาศธุรกรรมไปยังเครือข่าย Ethereum

เมื่อโหนดในเครือข่ายได้รับธุรกรรม โหนดจะยืนยันลายเซ็นเพื่อให้แน่ใจว่าธุรกรรมดังกล่าวลงนามโดยเจ้าของบัญชี หากลายเซ็นถูกต้อง โหนดจะเพิ่มธุรกรรมลงในบล็อกเชน

ในการเริ่มต้น คุณจะต้องกำหนดค่าทรัพยากร Cloud ที่จำเป็น จากนั้นคุณจะเรียกใช้เวิร์กโหลดในพื้นที่ทำงานที่ปลอดภัย โค้ดแล็บนี้จะแนะนำขั้นตอนระดับสูงต่อไปนี้

  • วิธีกำหนดค่าทรัพยากรในระบบคลาวด์ที่จำเป็นสำหรับเรียกใช้พื้นที่ทำงานที่มีข้อมูลลับ
  • วิธีให้สิทธิ์เข้าถึงทรัพยากรที่มีการป้องกันตามแอตทริบิวต์ของสิ่งต่อไปนี้
  • สิ่งที่ต้องระบุ: คอนเทนเนอร์ของภาระงาน
  • ตำแหน่ง: สภาพแวดล้อมของพื้นที่ทำงานที่เป็นความลับ (อิมเมจพื้นที่ทำงานที่เป็นความลับใน Confidential VM)
  • ผู้ใช้: บัญชีที่ใช้งานเวิร์กโหลด
  • วิธีเรียกใช้เวิร์กโหลดใน VM ที่เป็นความลับซึ่งใช้รูปภาพ VM ของพื้นที่ทำงานที่เป็นความลับ

API ที่จำเป็น

คุณต้องเปิดใช้ API ต่อไปนี้ในโปรเจ็กต์ที่ระบุจึงจะทําตามคู่มือนี้ได้

ชื่อ API

ชื่อ 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. ตั้งค่าทรัพยากรระบบคลาวด์

ก่อนเริ่มต้น

  • โคลน ที่เก็บนี้โดยใช้คําสั่งด้านล่างเพื่อรับสคริปต์ที่จําเป็นซึ่งใช้ในโค้ดแล็บนี้
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • เปลี่ยนไดเรกทอรีของ Codelab นี้
cd confidential-space/codelabs/digital_asset_transaction_codelab/scripts
  • ตรวจสอบว่าคุณได้ตั้งค่าตัวแปรสภาพแวดล้อมของโปรเจ็กต์ที่จําเป็นดังที่แสดงด้านล่าง ดูข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าโปรเจ็กต์ GCP ได้ที่ โค้ดแล็บนี้ โปรดดูรายละเอียดเกี่ยวกับวิธีเรียกข้อมูลรหัสโปรเจ็กต์และความแตกต่างระหว่างรหัสโปรเจ็กต์กับชื่อโปรเจ็กต์และหมายเลขโปรเจ็กต์ได้ที่นี่ .
export PRIMUS_PROJECT_ID=<GCP project id>
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
  • หากต้องการตั้งค่าตัวแปรสําหรับชื่อทรัพยากร ให้ใช้คําสั่งต่อไปนี้ โปรดทราบว่าการดำเนินการนี้จะลบล้างชื่อทรัพยากรเฉพาะสำหรับโปรเจ็กต์ GCP ของบริษัท ก เช่น export PRIMUS_INPUT_STORAGE_BUCKET='primus-input-bucket'
  • คุณสามารถตั้งค่าตัวแปรต่อไปนี้สําหรับโปรเจ็กต์ GCP ในบริษัท ก

$PRIMUS_INPUT_STORAGE_BUCKET

ที่เก็บข้อมูลซึ่งจัดเก็บคีย์ที่เข้ารหัส

$PRIMUS_RESULT_STORAGE_BUCKET

ที่เก็บข้อมูลที่จัดเก็บผลลัพธ์ธุรกรรม MPC

$PRIMUS_KEY

คีย์ KMS ที่ใช้เข้ารหัสข้อมูลที่จัดเก็บไว้ใน $PRIMUS_INPUT_STORAGE_BUCKET สำหรับ Primus Bank

$PRIMUS_KEYRING

กระเป๋าสตางค์ KMS ที่จะใช้สําหรับสร้างคีย์การเข้ารหัส $PRIMUS_KEY สําหรับ Primus Bank

$PRIMUS_WIP_PROVIDER

ผู้ให้บริการพูล Workload Identity ซึ่งมีเงื่อนไขแอตทริบิวต์ที่จะใช้กับโทเค็นที่บริการเวิร์กโหลด MPC ลงนาม

$PRIMUS_SERVICEACCOUNT

บัญชีบริการที่ $PRIMUS_WORKLOAD_IDENTITY_POOL ใช้เข้าถึงทรัพยากรที่ได้รับการปกป้อง บัญชีบริการนี้จะมีสิทธิ์ดูคีย์ที่เข้ารหัสซึ่งจัดเก็บอยู่ในที่เก็บข้อมูล $PRIMUS_INPUT_STORAGE_BUCKET

$PRIMUS_ARTIFACT_REPOSITORY

ที่เก็บอาร์ติแฟกต์สำหรับจัดเก็บอิมเมจคอนเทนเนอร์ของภาระงาน

$WORKLOAD_SERVICEACCOUNT

บัญชีบริการที่มีสิทธิ์เข้าถึง VM ข้อมูลที่เป็นความลับซึ่งเรียกใช้ภาระงาน

$WORKLOAD_CONTAINER

คอนเทนเนอร์ Docker ที่เรียกใช้เวิร์กโหลด

$WORKLOAD_IMAGE_NAME

ชื่อของรูปภาพคอนเทนเนอร์ภาระงาน

$WORKLOAD_IMAGE_TAG

แท็กของอิมเมจคอนเทนเนอร์ของภาระงาน

  • เรียกใช้สคริปต์ต่อไปนี้เพื่อตั้งค่าชื่อตัวแปรที่เหลือเป็นค่าตามรหัสโปรเจ็กต์สำหรับชื่อทรัพยากร
source config_env.sh

ตั้งค่าทรัพยากรระบบคลาวด์

ในขั้นตอนนี้ คุณจะต้องตั้งค่าทรัพยากรระบบคลาวด์ที่จําเป็นสําหรับการคํานวณแบบหลายฝ่าย คุณจะใช้สําคัญส่วนตัว 0000000000000000000000000000000000000000000000000000000000000001 ต่อไปนี้ในชั้นเรียนนี้

ในสภาพแวดล้อมที่ใช้งานจริง คุณจะต้องสร้างคีย์ส่วนตัวของคุณเอง อย่างไรก็ตาม เราจะแบ่งคีย์ส่วนตัวนี้ออกเป็น 2 ส่วนและเข้ารหัสแต่ละส่วนเพื่อวัตถุประสงค์ของห้องทดลองนี้ ในสถานการณ์ที่ใช้งานจริง คุณไม่ควรจัดเก็บคีย์ไว้ในไฟล์ข้อความธรรมดา แต่ให้สร้างคีย์ส่วนตัวนอก Google Cloud (หรือข้ามการสร้างคีย์ MPC ที่กำหนดเองไปเลย) แล้วเข้ารหัสเพื่อให้ไม่มีใครเข้าถึงคีย์ส่วนตัวหรือส่วนแบ่งคีย์ได้ เราจะใช้ Gcloud CLI ในการทดสอบนี้

เรียกใช้สคริปต์ต่อไปนี้เพื่อตั้งค่าทรัพยากรระบบคลาวด์ที่จําเป็น ขั้นตอนเหล่านี้จะสร้างทรัพยากรที่ระบุไว้ด้านล่าง

  • ที่เก็บข้อมูล Cloud Storage ($PRIMUS_INPUT_STORAGE_BUCKET) เพื่อจัดเก็บการแชร์คีย์ส่วนตัวที่เข้ารหัส
  • ที่เก็บข้อมูล Cloud Storage ($PRIMUS_RESULT_STORAGE_BUCKET) เพื่อจัดเก็บผลลัพธ์ของธุรกรรมเนื้อหาดิจิทัล
  • คีย์การเข้ารหัส ($PRIMUS_KEY) และพวงกุญแจ ($PRIMUS_KEYRING) ใน KMS เพื่อเข้ารหัสการแชร์คีย์ส่วนตัว
  • Workload Identity Pool ($PRIMUS_WORKLOAD_IDENTITY_POOL) เพื่อตรวจสอบการอ้างสิทธิ์ตามเงื่อนไขแอตทริบิวต์ที่กำหนดค่าไว้ภายใต้ผู้ให้บริการ
  • บัญชีบริการ ($PRIMUS_SERVICEACCOUNT) ที่แนบกับพูล Workload Identity ที่กล่าวถึงข้างต้น ($PRIMUS_WORKLOAD_IDENTITY_POOL) ซึ่งมีสิทธิ์เข้าถึง IAM ดังต่อไปนี้
  • roles/cloudkms.cryptoKeyDecrypter เพื่อถอดรหัสข้อมูลโดยใช้คีย์ KMS
  • objectViewer เพื่ออ่านข้อมูลจากที่เก็บข้อมูล Cloud Storage
  • roles/iam.workloadIdentityUser สำหรับการเชื่อมต่อบัญชีบริการนี้กับ Workload Identity Pool
./setup_resources.sh

3. สร้างภาระงาน

สร้างบัญชีบริการของเวิร์กโหลด

ตอนนี้คุณจะต้องสร้างบัญชีบริการสำหรับเวิร์กโหลดที่มีบทบาทและสิทธิ์ที่จำเป็น โดยให้เรียกใช้สคริปต์ต่อไปนี้ ซึ่งจะสร้างบัญชีบริการของเวิร์กโหลดสำหรับบริษัท ก. VM ที่เรียกใช้เวิร์กโหลดจะใช้บัญชีบริการนี้

บัญชีบริการของเวิร์กโหลด ($WORKLOAD_SERVICEACCOUNT) จะมีบทบาทต่อไปนี้

  • confidentialcomputing.workloadUser เพื่อรับโทเค็นการรับรอง
  • logging.logWriter เพื่อเขียนบันทึกไปยัง Cloud Logging
  • objectViewer เพื่ออ่านข้อมูลจากที่เก็บข้อมูล Cloud Storage ของ $PRIMUS_INPUT_STORAGE_BUCKET
  • objectUser เพื่อเขียนผลลัพธ์ของภาระงานไปยังที่เก็บข้อมูล Cloud Storage ของ $PRIMUS_RESULT_STORAGE_BUCKET
./create_workload_service_account.sh

สร้างภาระงาน

ขั้นตอนนี้เกี่ยวข้องกับการสร้างอิมเมจ Docker ของภาระงาน เวิร์กโหลดในโค้ดแล็บนี้เป็นแอปพลิเคชัน MPC ของ Node.js แบบง่ายที่ลงนามธุรกรรมดิจิทัลสำหรับการโอนเนื้อหาโดยใช้ส่วนแบ่งคีย์ส่วนตัวที่เข้ารหัส นี่คือรหัสโปรเจ็กต์ภาระงาน โปรเจ็กต์ภาระงานจะมีไฟล์ต่อไปนี้

package.json: ไฟล์นี้มีรายการแพ็กเกจที่ควรใช้สำหรับแอปพลิเคชัน MPC ของเวิร์กโหลด ในกรณีนี้ เราใช้ไลบรารี @google-cloud/kms, @google-cloud/storage, ethers และ fast-crc32c นี่คือไฟล์ package.json ที่เราจะใช้สำหรับโค้ดแล็บนี้

index.js: นี่คือจุดแรกเข้าของแอปพลิเคชันเวิร์กโหลด และระบุคำสั่งที่ควรเรียกใช้เมื่อคอนเทนเนอร์เวิร์กโหลดเริ่มต้นขึ้น นอกจากนี้ เรายังได้แนบตัวอย่างธุรกรรมที่ไม่มีการรับรองซึ่งโดยปกติแล้วแอปพลิเคชันที่ไม่น่าเชื่อถือซึ่งขอให้ผู้ใช้ลงนามจะเป็นผู้ระบุ ไฟล์ index.js นี้จะนําเข้าฟังก์ชันจาก mpc.js ด้วย ซึ่งเราจะสร้างในลำดับถัดไป ด้านล่างนี้คือเนื้อหาของไฟล์ index.js และคุณดูเนื้อหานี้ได้ที่นี่

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: ไฟล์นี้คือที่ที่การเซ็นสัญญาธุรกรรมเกิดขึ้น โดยจะนําเข้าฟังก์ชันจาก kms-decrypt และ credential-config ซึ่งเราจะพูดถึงในลำดับถัดไป ด้านล่างนี้คือเนื้อหาของไฟล์ mpc.js และคุณยังดูเนื้อหานี้ได้ที่นี่

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: ไฟล์นี้มีโค้ดสำหรับการถอดรหัสโดยใช้คีย์ที่จัดการใน KMS ด้านล่างนี้คือเนื้อหาของไฟล์ kms-decrypt.js และคุณยังดูเนื้อหานี้ได้ที่นี่

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: ไฟล์จะจัดเก็บเส้นทางและรายละเอียดของ Workload Identity Pool สำหรับการแอบอ้างเป็นบัญชีบริการ ที่นี่คือไฟล์ credential-config.js ที่เราจะใช้สําหรับโค้ดแล็บนี้

Dockerfile: สุดท้าย เราจะสร้าง Dockerfile ที่จะใช้ในการสร้างอิมเมจ Docker ของภาระงาน โดยกำหนด Dockerfile ตามที่ระบุไว้ที่นี่

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" ]

หมายเหตุ: LABEL "tee.launch_policy.allow_cmd_override"="true" ใน Dockerfile คือนโยบายการเริ่มที่นักเขียนอิมเมจกำหนด ซึ่งช่วยให้ผู้ดำเนินการลบล้าง CMD ได้เมื่อเรียกใช้เวิร์กโหลด โดยค่าเริ่มต้น ระบบจะตั้งค่า allow_cmd_override เป็นเท็จ ป้ายกํากับ "tee.launch_policy.allow_env_override" จะบอกพื้นที่ทำงานแบบจำกัดว่าผู้ใช้รูปภาพตัวแปรสภาพแวดล้อมใดบ้างที่ใช้ได้

เรียกใช้สคริปต์ต่อไปนี้เพื่อสร้างภาระงานที่จะทำตามขั้นตอนต่อไปนี้

  • สร้าง Artifact Registry($PRIMUS_ARTIFACT_REPOSITORY) เพื่อจัดเก็บอิมเมจ Docker ของ Workload
  • อัปเดตโค้ดภาระงานด้วยชื่อทรัพยากรที่จำเป็น ที่นี่คือรหัสเวิร์กโหลดที่ใช้สำหรับ Codelab นี้
  • สร้าง Dockerfile สำหรับการสร้างอิมเมจ Docker ของโค้ดภาระงาน ดู Dockerfile ได้ที่นี่
  • สร้างและเผยแพร่อิมเมจ Docker ไปยัง Artifact Registry ($PRIMUS_ARTIFACT_REPOSITORY) ที่สร้างขึ้นในขั้นตอนก่อนหน้า
  • ให้สิทธิ์อ่าน $PRIMUS_ARTIFACT_REPOSITORY แก่ $WORKLOAD_SERVICEACCOUNT ซึ่งจําเป็นเพื่อให้คอนเทนเนอร์ภาระงานดึงอิมเมจ Docker ของภาระงานจาก Artifact Registry ได้
./create_workload.sh

สร้างโหนด Blockchain

โหนด Ganache Ethereum

เราต้องสร้างอินสแตนซ์ Ethereum Ganache ก่อนจึงจะให้สิทธิ์เวิร์กโหลดได้ ระบบจะส่งธุรกรรมที่ลงนามแล้วไปยังอินสแตนซ์ Ganache นี้ โปรดจดที่อยู่ IP ของอินสแตนซ์นี้ไว้ หลังจากเรียกใช้คําสั่งด้านล่าง คุณอาจต้องป้อน y เพื่อเปิดใช้ 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. ให้สิทธิ์และเรียกใช้ภาระงาน

ให้สิทธิ์ภาระงาน

ในขั้นตอนนี้ เราจะตั้งค่าผู้ให้บริการ Workload Identity Pool ภายใต้ Workload Identity Pool ($PRIMUS_WORKLOAD_IDENTITY_POOL) โดยจะมีการกำหนดค่าเงื่อนไขแอตทริบิวต์สำหรับ Workload Identity ดังที่แสดงด้านล่าง เงื่อนไขอย่างหนึ่งคือการตรวจสอบว่ามีการดึงข้อมูลอิมเมจเวิร์กโหลดจากที่เก็บอาร์ติแฟกต์ที่คาดไว้

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"

เรียกใช้ภาระงาน

ส่วนนี้จะอธิบายวิธีเรียกใช้เวิร์กโหลดใน VM ข้อมูลที่เป็นความลับ โดยเราจะส่งอาร์กิวเมนต์ TEE ที่จำเป็นโดยใช้ Flag ข้อมูลเมตา นอกจากนี้ เราจะตั้งค่าตัวแปรสภาพแวดล้อมสำหรับคอนเทนเนอร์ของภาระงานโดยใช้ Flag "tee-env-*" รูปภาพมีตัวแปรต่อไปนี้

  • NODE_URL: URL ของโหนด Ethereum ที่จะประมวลผลธุรกรรมที่ลงนาม
  • RESULTS_BUCKET: ที่เก็บข้อมูลผลลัพธ์ธุรกรรม mpc
  • KEY_BUCKET: ที่เก็บข้อมูลซึ่งจัดเก็บคีย์ที่เข้ารหัส mpc
  • PRIMUS_PROJECT_NUMBER: หมายเลขโปรเจ็กต์ที่ใช้สำหรับไฟล์การกําหนดค่าข้อมูลเข้าสู่ระบบ
  • PRIMUS_PROJECT_ID: รหัสโปรเจ็กต์ที่ใช้สำหรับไฟล์การกําหนดค่าข้อมูลเข้าสู่ระบบ ระบบจะเผยแพร่ผลลัพธ์ของการดำเนินการเวิร์กโหลดไปยัง $PRIMUS_RESULT_STORAGE_BUCKET
  • PRIMUS_WORKLOAD_IDENTITY_POOL: พูล Workload Identity ที่ใช้ตรวจสอบการอ้างสิทธิ์
  • PRIMUS_WIP_POROVIDER: ผู้ให้บริการพูล Workload Identity ซึ่งมีเงื่อนไขแอตทริบิวต์ที่จะใช้ตรวจสอบโทเค็นที่แสดงโดยเวิร์กโหลด
  • WORKLOAD_SERVICEACCOUNT: บัญชีบริการของเวิร์กโหลด
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}"

ตรวจสอบผลลัพธ์ใน Cloud Storage

คุณดูใบเสร็จธุรกรรมได้ใน Cloud Storage ระบบอาจใช้เวลา 2-3 นาทีจึงจะบูตพื้นที่ทำงานที่ปลอดภัยและแสดงผลลัพธ์ คุณจะทราบว่าคอนเทนเนอร์เสร็จแล้วเมื่อ VM อยู่ในสถานะ "หยุดทำงาน"

  1. ไปที่หน้าเบราว์เซอร์ Cloud Storage
  2. คลิก $PRIMUS_RESULT_STORAGE_BUCKET
  3. คลิกไฟล์ transaction_receipt
  4. คลิก "ดาวน์โหลด" เพื่อดาวน์โหลดและดูการตอบกลับธุรกรรม

หรือจะเรียกใช้คําสั่งต่อไปนี้เพื่อดูผลลัพธ์ก็ได้

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

หมายเหตุ: หากผลลัพธ์ไม่ปรากฏ ให้ไปที่ $WORKLOAD_VM ในหน้า Cloud Console ของ Compute Engine แล้วคลิก "พอร์ตซีเรียล 1 (คอนโซล)" เพื่อดูบันทึก

ตรวจสอบธุรกรรม Blockchain ของ Ganache

นอกจากนี้ คุณยังดูธุรกรรมในบันทึกบล็อกเชนได้

  1. ไปที่หน้า Cloud Compute Engine
  2. คลิก ${ETHEREUM_NODE} VM
  3. คลิก SSH เพื่อเปิดหน้าต่าง SSH ในเบราว์เซอร์
  4. ในหน้าต่าง SSH ให้ป้อน sudo docker ps เพื่อดูคอนเทนเนอร์ Ganache ที่ทำงานอยู่
  5. ค้นหารหัสคอนเทนเนอร์สำหรับ trufflesuite/ganache:v7.7.3
  6. ป้อน sudo docker logs CONTAINER_ID โดยแทนที่ CONTAINER_ID ด้วยรหัสของ trufflesuite/ganache:v7.7.3
  7. ดูบันทึกของ Ganache และยืนยันว่ามีธุรกรรมแสดงอยู่ในบันทึก

5. ล้างข้อมูล

ที่นี่เป็นสคริปต์ที่ใช้ล้างทรัพยากรที่เราสร้างขึ้นเป็นส่วนหนึ่งของ Codelab นี้ ในการล้างข้อมูลนี้ ระบบจะลบทรัพยากรต่อไปนี้

  • ใส่ที่เก็บข้อมูลที่ใช้เพื่อจัดเก็บการแชร์คีย์ที่เข้ารหัส ($PRIMUS_INPUT_STORAGE_BUCKET)
  • คีย์การเข้ารหัส ($PRIMUS_KEY)
  • บัญชีบริการที่ใช้เข้าถึงทรัพยากรที่ได้รับการปกป้อง ($PRIMUS_SERVICEACCOUNT)
  • พูล Workload Identity ($PRIMUS_WORKLOAD_IDENTITY_POOL)
  • บัญชีบริการของภาระงาน ($WORKLOAD_SERVICEACCOUNT)
  • Workload Compute Instance ($WORKLOAD_VM และ $ETHEREUM_NODE)
  • ที่เก็บข้อมูลผลลัพธ์ที่ใช้จัดเก็บผลลัพธ์ธุรกรรม ($PRIMUS_RESULT_STORAGE_BUCKET)
  • Artifact Registry ที่ใช้ในการจัดเก็บรูปภาพภาระงาน ($PRIMUS_ARTIFACT_REPOSITORY)
./cleanup.sh

หากสำรวจเสร็จแล้ว โปรดพิจารณาลบโปรเจ็กต์

ขั้นตอนถัดไป

ลองดู Codelab ที่คล้ายกันเหล่านี้...

อ่านเพิ่มเติม