最初の Confidential Space 環境を作成する


このガイドでは、互いに自身の給与額を明らかにすることなく、Alex と Bola がどちらの給与がより高額であるかを調べる必要があります。データの機密性を保持するために Confidential Space を使用することを決定し、次のロールを引き受けることに同意します。

  • Alex: データ共同編集者、ワークロード作成者

  • Bola: データ共同編集者、ワークロード オペレーター

この構成は、このガイドで可能な限りわかりやすくするために設計されています。ただし、ワークロードの作成者とオペレーターが、データ共同編集者から完全に独立した状態にし、必要な数の共同編集者を配置することが可能です。

始める前に

このガイドでは、1 つの組織で複数のプロジェクトにアクセスできる単一のアカウントを使用して、プロセス全体を体験できる Confidential Space のシナリオについて説明します。本番環境デプロイでは、共同編集者、ワークロードの作成者、ワークロードのオペレーターは、それぞれ個別のアカウントと独自のプロジェクトを個別の組織に持ち、互いにアクセスできず、機密データを別々に保持します。

Confidential Space は Google Cloudのさまざまなサービスとやり取りして、結果を出すことができます。サービスには以下のものがありますが、これらに限定されません。

このガイドでは、これらの機能のすべてを使用し、基本的な理解があることを前提としています。

必要な API

このガイドを完了するには、指定されたプロジェクトで次の API を有効にする必要があります。

API 名 API タイトル 次のプロジェクトで有効にする
cloudkms.googleapis.com Cloud KMS データ共同編集者(Alex と Bola のプロジェクト)
iamcredentials.googleapis.com IAM Service Account Credentials API

データ共同編集者(Alex と Bola のプロジェクト)

artifactregistry.googleapis.com Artifact Registry ワークロード作成者(Alex のプロジェクト)
compute.googleapis.com Compute Engine ワークロード オペレーター(Bola のプロジェクト)
confidentialcomputing.googleapis.com Confidential Computing ワークロード オペレーター(Bola のプロジェクト)

必要なロール

このガイドで必要になる権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。

  • データ共同編集者(Alex と Bola)の Cloud KMS 管理者(roles/cloudkms.admin)。
  • データ共同編集者(Alex と Bola)の IAM Workload Identity プール管理者(roles/iam.workloadIdentityPoolAdmin)。
  • データ共同編集者(Alex と Bola)の Service Usage 管理者(roles/serviceusage.serviceUsageAdmin)。
  • データ共同編集者のサービス アカウント管理者(roles/iam.serviceAccountAdmin)。
  • データ共同編集者(Alex と Bola)とワークロード オペレーター(Bola)のストレージ管理者(roles/storage.admin)。
  • ワークロード オペレーター(Bola)の Compute 管理者(roles/compute.admin)。
  • ワークロード オペレーター(Bola)のセキュリティ管理者(roles/securityAdmin)。
  • ワークロード作成者(Alex)の Artifact Registry 管理者(roles/artifactregistry.admin)。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

データ コラボレータのリソースを設定する

Alex と Bola の両方には、次のリソースを含む独立したプロジェクトが必要です。

  • 機密データ自体。

  • データを暗号化して機密性を維持するための暗号鍵。

  • 暗号化されたデータを保存する Cloud Storage バケット。

  • 暗号鍵にアクセスできるサービス アカウント。機密データを復号できます。

  • そのサービス アカウントが接続されている Workload Identity プール。機密データを処理するワークロードは、プールを使用してサービス アカウントの権限を借用し、暗号化されていないデータを取得します。

使用を開始するには、Google Cloud コンソールに移動します。

Google Cloud コンソールに移動

Alex のリソースを設定する

Alex のリソースを設定するには、次の手順を完了します。

  1. [Cloud Shell をアクティブにする] をクリックします。
  2. Cloud Shell で次のコマンドを入力して、Alex のプロジェクトを作成します。ALEX_PROJECT_ID は任意の名前に置き換えます。

    gcloud projects create ALEX_PROJECT_ID
  3. 新しく作成したプロジェクトに切り替えます。

    gcloud config set project ALEX_PROJECT_ID
  4. まだ行っていない場合は、データ共同編集者およびワークロード 設定者として、Alex が必要とする API を有効にします。

    gcloud services enable cloudkms.googleapis.com artifactregistry.googleapis.com iamcredentials.googleapis.com
  5. 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. 新しく作成された暗号鍵を使用してデータを暗号化できるように、Alex に cloudkms.cryptoKeyEncrypter ロールを付与します。

    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. 後でワークロードがデータの復号に使用するサービス アカウントを作成します。

    gcloud iam service-accounts create ALEX_SERVICE_ACCOUNT_NAME
  8. 作成した暗号鍵を使用してデータを復号できるように、サービス アカウントに cloudkms.cryptoKeyDecrypter ロールを付与します。

    gcloud kms keys add-iam-policy-binding \
        projects/ALEX_PROJECT_ID/locations/global/keyRings/ALEX_KEYRING_NAME/cryptoKeys/ALEX_KEY_NAME \
        --member=serviceAccount:ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/cloudkms.cryptoKeyDecrypter
  9. Workload Identity プールを作成し、iam.workloadIdentityUser のロールを使用してサービス アカウントを接続します。

    gcloud iam workload-identity-pools create ALEX_POOL_NAME \
        --location=global
    gcloud iam service-accounts add-iam-policy-binding \
        ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com \
        --member="principalSet://iam.googleapis.com/projects/"$(gcloud projects describe ALEX_PROJECT_ID \
            --format="value(projectNumber)")"/locations/global/workloadIdentityPools/ALEX_POOL_NAME/*" \
        --role=roles/iam.workloadIdentityUser
  10. 入力データ用の Cloud Storage バケットと、結果を保存する別のバケットを作成します。

    gcloud storage buckets create gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME
  11. Alex の給与のみを数値として含むファイルを作成します。

    echo 123456 > ALEX_SALARY.txt
  12. ファイルを暗号化して、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

Bola のリソースを設定する

Bola のリソースを設定するには、次の手順を完了します。

  1. Cloud Shell で次のコマンドを入力して、Bola のプロジェクトを作成します。BOLA_PROJECT_ID は任意の名前に置き換えます。

    gcloud projects create BOLA_PROJECT_ID
  2. 新しく作成したプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
  3. まだ行っていない場合は、データ共同編集者およびワークロード オペレーターとして、Bola が必要とする API を有効にします。

    gcloud services enable cloudkms.googleapis.com iamcredentials.googleapis.com compute.googleapis.com confidentialcomputing.googleapis.com
  4. 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. 新しく作成された暗号鍵を使用してデータを暗号化できるように、Bola に cloudkms.cryptoKeyEncrypter ロールを付与します。

    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. 後でワークロードがデータの復号に使用するサービス アカウントを作成します。

    gcloud iam service-accounts create BOLA_SERVICE_ACCOUNT_NAME
  7. 作成した暗号鍵を使用してデータを復号できるように、サービス アカウントに cloudkms.cryptoKeyDecrypter ロールを付与します。

    gcloud kms keys add-iam-policy-binding \
        projects/BOLA_PROJECT_ID/locations/global/keyRings/BOLA_KEYRING_NAME/cryptoKeys/BOLA_KEY_NAME \
        --member=serviceAccount:BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --role=roles/cloudkms.cryptoKeyDecrypter
  8. Workload Identity プールを作成し、iam.workloadIdentityUser のロールを使用してサービス アカウントを接続します。

    gcloud iam workload-identity-pools create BOLA_POOL_NAME \
        --location=global
    gcloud iam service-accounts add-iam-policy-binding \
        BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com \
        --member="principalSet://iam.googleapis.com/projects/"$(gcloud projects describe BOLA_PROJECT_ID \
            --format="value(projectNumber)")"/locations/global/workloadIdentityPools/BOLA_POOL_NAME/*" \
        --role=roles/iam.workloadIdentityUser
  9. 入力データ用の Cloud Storage バケットと、結果を保存する別のバケットを作成します。

    gcloud storage buckets create gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME
  10. Bola の給与のみを数値として含むファイルを作成します。

    echo 111111 > BOLA_SALARY.txt
  11. ファイルを暗号化して、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

ワークロードのサービス アカウントを作成する

Alex と Bola の両方がデータを復号するために設定したサービス アカウントに加えて、ワークロードを実行するために別のサービス アカウントが必要です。サービス アカウントは機密データの復号と処理の両方に使用されるため、データの公開設定はオーナーに制限されます。

このガイドでは、Bola がワークロードを運用および実行しますが、サードパーティを含む誰でもこれらのロールを引き継ぐことができます。

Bola のプロジェクトで次の手順を完了して、サービス アカウントを設定します。

  1. ワークロードを実行するサービス アカウントを作成します。

    gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAME
    
  2. サービス アカウントの権限を借用するための iam.serviceAccountUser のロールを Bola に付与します。これは後でワークロード VM を作成するために必要です。

    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. サービス アカウントに confidentialcomputing.workloadUser ロールを付与して、構成証明トークンを生成できるようにします。

    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. サービス アカウントに Cloud Logging にログを書き込むための logging.logWriter ロールを付与して、ワークロードの進捗状況を確認できるようにします。

    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. サービス アカウントに、暗号化されたデータを含む Alex と Bola のバケットに対する読み取りアクセス権と、各結果バケットへの書き込みアクセス権を付与します。

    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
    

    これは、アクセス権を付与するユーザーが、オペレーションの対象となる Cloud Storage バケットを含むプロジェクトに対するストレージ管理者(roles/storage.admin)ロールを持っていることを前提としています。

ワークロードを作成する

このガイドでは、Alex はワークロードのコードを指定し、コードを格納する Docker イメージをビルドしていますが、サードパーティを含む誰でもこれらのロールを引き継ぐことができます。

Alex は、ワークロードに次のリソースを作成する必要があります。

  • ワークロードを実行するコード。

  • ワークロードを実行するサービス アカウントがアクセスできる Artifact Registry の Docker リポジトリ。

  • ワークロード コードを含む Docker イメージ。

リソースを作成して設定するには、Alex のプロジェクトで次の手順を完了します。

  1. Alex のプロジェクトに切り替えます。

    gcloud config set project ALEX_PROJECT_ID
    
  2. Artifact Registry で Docker リポジトリを作成します。

    gcloud artifacts repositories create REPOSITORY_NAME \
        --repository-format=docker \
        --location=us
    
  3. ワークロードを実行するサービス アカウントに Artifact Registry の読み取り(roles/artifactregistry.reader)ロールを付与し、リポジトリから読み取れるようにします。

    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. [エディタを開く] をクリックして Cloud Shell エディタを開き、salary.go という新しいファイルを作成します。次のコードをファイルにコピーして保存します。

    // READ ME FIRST: Before compiling, customize the details in the USER VARIABLES
    // SECTION starting at line 30.
    
    package main
    
    import (
      kms "cloud.google.com/go/kms/apiv1"
      "cloud.google.com/go/storage"
      "context"
      "fmt"
      "google.golang.org/api/option"
      kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
      "io/ioutil"
      "strconv"
      "strings"
      "time"
    )
    
    type collaborator struct {
      name         string
      wipName      string
      sa           string
      keyName      string
      inputBucket  string
      inputFile    string
      outputBucket string
      outputFile   string
    }
    
    // ============================
    // START USER VARIABLES SECTION
    // You need to customize this section, replacing each const's value with your
    // own.
    
    // To get a project number, use the following command, and substitute
    // <PROJECT_ID> for the data collaborator's project ID.
    // gcloud projects describe <PROJECT_ID> --format="value(projectNumber)"
    
    // Alex's values
    const collaborator1Name string = "Alex"                // Alex's name
    const collaborator1EncryptedSalaryFileName string = "" // The name of Alex's encrypted salary file
    const collaborator1BucketInputName string = ""         // The name of the storage bucket that contains Alex's encrypted salary file
    const collaborator1BucketOutputName string = ""        // The name of the storage bucket to store Alex's results in
    const collaborator1BucketOutputFileName string = ""    // The name of Alex's output file that contains the results
    const collaborator1KMSKeyringName string = ""          // Alex's Key Management Service key ring
    const collaborator1KMSKeyName string = ""              // Alex's Key Management Service key
    const collaborator1ProjectName string = ""             // Alex's project ID
    const collaborator1ProjectNumber string = ""           // Alex's project number
    const collaborator1PoolName string = ""                // Alex's workload identity pool name
    const collaborator1ServiceAccountName string = ""      // The name of Alex's service account that can decrypt their salary
    
    // Bola's values
    const collaborator2Name string = "Bola"                // Bola's name
    const collaborator2EncryptedSalaryFileName string = "" // The name of Bola's encrypted salary file
    const collaborator2BucketInputName string = ""         // The name of the storage bucket that contains Bola's encrypted salary file
    const collaborator2BucketOutputName string = ""        // The name of the storage bucket to store Bola's results in
    const collaborator2BucketOutputFileName string = ""    // The name of Bola's output file that contains the results
    const collaborator2KMSKeyringName string = ""          // Bola's Key Management Service key ring
    const collaborator2KMSKeyName string = ""              // Bola's Key Management Service key
    const collaborator2ProjectName string = ""             // Bola's project ID
    const collaborator2ProjectNumber string = ""           // Bola's project number
    const collaborator2PoolName string = ""                // Bola's workload identity pool name
    const collaborator2ServiceAccountName string = ""      // The name of Bola's service account that can decrypt their salary
    
    // END USER VARIABLES SECTION
    // ==========================
    
    var collaborators = [2]collaborator{
      {
        collaborator1Name,
        "projects/" + collaborator1ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator1PoolName + "/providers/attestation-verifier",
        collaborator1ServiceAccountName + "@" + collaborator1ProjectName + ".iam.gserviceaccount.com",
        "projects/" + collaborator1ProjectName + "/locations/global/keyRings/" + collaborator1KMSKeyringName + "/cryptoKeys/" + collaborator1KMSKeyName,
        collaborator1BucketInputName,
        collaborator1EncryptedSalaryFileName,
        collaborator1BucketOutputName,
        collaborator1BucketOutputFileName,
      },
      {
        collaborator2Name,
        "projects/" + collaborator2ProjectNumber + "/locations/global/workloadIdentityPools/" + collaborator2PoolName + "/providers/attestation-verifier",
        collaborator2ServiceAccountName + "@" + collaborator2ProjectName + ".iam.gserviceaccount.com",
        "projects/" + collaborator2ProjectName + "/locations/global/keyRings/" + collaborator2KMSKeyringName + "/cryptoKeys/" + collaborator2KMSKeyName,
        collaborator2BucketInputName,
        collaborator2EncryptedSalaryFileName,
        collaborator2BucketOutputName,
        collaborator2BucketOutputFileName,
      },
    }
    
    const credentialConfig = `{
            "type": "external_account",
            "audience": "//iam.googleapis.com/%s",
            "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
            "token_url": "https://sts.googleapis.com/v1/token",
            "credential_source": {
              "file": "/run/container_launcher/attestation_verifier_claims_token"
            },
            "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:generateAccessToken"
            }`
    
    func main() {
      fmt.Println("workload started")
      ctx := context.Background()
    
      storageClient, err := storage.NewClient(ctx) // using the default credential on the Compute Engine VM
      if err != nil {
        panic(err)
      }
    
      // get and decrypt
      s0, err := getSalary(ctx, storageClient, collaborators[0])
      if err != nil {
        panic(err)
      }
    
      s1, err := getSalary(ctx, storageClient, collaborators[1])
      if err != nil {
        panic(err)
      }
    
      res := ""
      if s0 > s1 {
        res = fmt.Sprintf("%s earns more!\n", collaborators[0].name)
      } else if s1 < s0 {
        res = fmt.Sprintf("%s earns more!\n", collaborators[1].name)
      } else {
        res = "earns same\n"
      }
    
      now := time.Now()
      for _, cw := range collaborators {
        outputWriter := storageClient.Bucket(cw.outputBucket).Object(fmt.Sprintf("%s-%d", cw.outputFile, now.Unix())).NewWriter(ctx)
    
        _, err = outputWriter.Write([]byte(res))
        if err != nil {
          fmt.Printf("Could not write: %v", err)
          panic(err)
        }
        if err = outputWriter.Close(); err != nil {
          fmt.Printf("Could not close: %v", err)
          panic(err)
        }
      }
    }
    
    func getSalary(ctx context.Context, storageClient *storage.Client, cw collaborator) (float64, error) {
      encryptedBytes, err := getFile(ctx, storageClient, cw.inputBucket, cw.inputFile)
      if err != nil {
        return 0.0, err
      }
      decryptedByte, err := decryptByte(ctx, cw.keyName, cw.sa, cw.wipName, encryptedBytes)
      if err != nil {
        return 0.0, err
      }
      decryptedNumber := strings.TrimSpace(string(decryptedByte))
      num, err := strconv.ParseFloat(decryptedNumber, 64)
      if err != nil {
        return 0.0, err
      }
      return num, nil
    }
    
    func decryptByte(ctx context.Context, keyName, trustedServiceAccountEmail, wippro string, encryptedData []byte) ([]byte, error) {
      cc := fmt.Sprintf(credentialConfig, wippro, trustedServiceAccountEmail)
      kmsClient, err := kms.NewKeyManagementClient(ctx, option.WithCredentialsJSON([]byte(cc)))
      if err != nil {
        return nil, fmt.Errorf("creating a new KMS client with federated credentials: %w", err)
      }
    
      decryptRequest := &kmspb.DecryptRequest{
        Name:       keyName,
        Ciphertext: encryptedData,
      }
      decryptResponse, err := kmsClient.Decrypt(ctx, decryptRequest)
      if err != nil {
        return nil, fmt.Errorf("could not decrypt ciphertext: %w", err)
      }
    
      return decryptResponse.Plaintext, nil
    }
    
    func getFile(ctx context.Context, c *storage.Client, bucketName string, objPath string) ([]byte, error) {
      bucketHandle := c.Bucket(bucketName)
      objectHandle := bucketHandle.Object(objPath)
    
      objectReader, err := objectHandle.NewReader(ctx)
      if err != nil {
        return nil, err
      }
      defer objectReader.Close()
    
      s, err := ioutil.ReadAll(objectReader)
      if err != nil {
        return nil, err
      }
    
      return s, nil
    }
    
  5. ソースコードの USER VARIABLES SECTION を変更し、コードコメントに記載されているように、空の const 値を関連するリソース名に置き換えます。このガイドに示されている ALEX_PROJECT_ID のようなプレースホルダ変数を編集した場合、次のコードサンプルに値が含まれます。このサンプルはコピーして、既存に上書きできます。

    // Alex's values
    const collaborator1Name string = "Alex"                                            // Alex's name
    const collaborator1EncryptedSalaryFileName string = "ALEX_ENCRYPTED_SALARY_FILE" // The name of Alex's encrypted salary file
    const collaborator1BucketInputName string = "ALEX_INPUT_BUCKET_NAME"             // The name of the storage bucket that contains Alex's encrypted salary file
    const collaborator1BucketOutputName string = "ALEX_RESULTS_BUCKET_NAME"          // The name of the storage bucket to store Alex's results in
    const collaborator1BucketOutputFileName string = "ALEX_RESULTS_FILE_NAME"        // The name of Alex's output file that contains the results
    const collaborator1KMSKeyringName string = "ALEX_KEYRING_NAME"                   // Alex's Key Management Service 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
    const collaborator1ServiceAccountName string = "ALEX_SERVICE_ACCOUNT_NAME"       // The name of Alex's service account that can decrypt their salary
    
    // Bola's values
    const collaborator2Name string = "Bola"                                            // Bola's name
    const collaborator2EncryptedSalaryFileName string = "BOLA_ENCRYPTED_SALARY_FILE" // The name of Bola's encrypted salary file
    const collaborator2BucketInputName string = "BOLA_INPUT_BUCKET_NAME"             // The name of the storage bucket that contains Bola's encrypted salary file
    const collaborator2BucketOutputName string = "BOLA_RESULTS_BUCKET_NAME"          // The name of the storage bucket to store Bola's results in
    const collaborator2BucketOutputFileName string = "BOLA_RESULTS_FILE_NAME"        // The name of Bola's output file that contains the results
    const collaborator2KMSKeyringName string = "BOLA_KEYRING_NAME"                   // Bola's Key Management Service 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
    const collaborator2ServiceAccountName string = "BOLA_SERVICE_ACCOUNT_NAME"       // The name of Bola's service account that can decrypt their salary
    

    Alex と Bola の両方のプロジェクト番号も更新してください。次のコマンドを使用して取得できます。

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  6. すべての関係者がソースコードを読み、監査していることを確認します。

  7. [Terminal > New Terminal] をクリックして、Cloud Shell エディタ内でターミナルを開きます。

  8. ターミナルで次のコマンドを入力して、Go 環境を設定します。

    go mod init salary
    go get cloud.google.com/go/kms/apiv1 cloud.google.com/go/storage google.golang.org/api/option google.golang.org/genproto/googleapis/cloud/kms/v1
    
  9. 次のコマンドを入力して、ソースコードを静的にリンクされたバイナリにコンパイルします。

    CGO_ENABLED=0 go build -trimpath
    
  10. Cloud Shell エディタで、次の内容を含む Dockerfile という名前のファイルを作成します。

    FROM alpine:latest
    WORKDIR /test
    COPY salary /test
    ENTRYPOINT ["/test/salary"]
    CMD []
    
  11. Docker 認証情報を更新して、us-docker.pkg.dev ドメイン名を追加します。

    gcloud auth configure-docker us-docker.pkg.dev
    
  12. ターミナルで次のコマンドを入力して、Dockerfile から Docker イメージを作成します。

    docker build -t \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME:latest .
    
  13. Docker イメージを Artifact Registry に push します。

    docker push \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME
    
  14. Docker の push レスポンスから、後で使用するために安全な場所に Docker イメージのダイジェスト(sha256: 接頭辞を含む)をコピーします。

  15. すべての関係者が Docker イメージを監査し、使用を許可する前に信頼できることを確認するようにしてください。

ワークロードを承認する

両者からワークロードが承認されたら、Alex と Bola は Google Cloud 構成証明をプロバイダとして Workload Identity プールに追加する必要があります。これにより、ワークロードに接続されているサービス アカウントがプールに接続されているサービス アカウントの権限を借用してデータにアクセスできるようになります。ただし、特定の属性条件が満たされている必要があります。つまり、属性条件は構成証明ポリシーとして機能します。

このガイドで使用する属性条件は次のとおりです。

  • 実行中の Docker イメージのダイジェスト

  • ワークロードを実行するサービス アカウントのメールアドレス

悪意のある行為者が Docker イメージを変更した場合、または別のサービス アカウントがワークロードに接続された場合、ワークロードは Alex または Bola のデータにアクセスできなくなります。

使用可能な属性条件については、構成証明アサーションをご覧ください。

必要な条件で Alex と Bola のプロバイダを設定するには、次の操作を行います。

  1. 次のコマンドを入力して、Alex のプロバイダを作成します。

    gcloud iam workload-identity-pools providers create-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=ALEX_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE' \
    && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    
  2. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  3. 次のコマンドを入力して、Bola のプロバイダを作成します。

    gcloud iam workload-identity-pools providers create-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=BOLA_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE' \
    && 'STABLE' in assertion.submods.confidential_space.support_attributes"
    

ワークロードをデプロイする

プロバイダが Alex と Bola の Workload Identity プールと必要なリソースの両方に追加されたら、ワークロード オペレーターがワークロードを実行します。

ワークロードをデプロイするには、Bola のプロジェクトに次のプロパティを持つ新しい Confidential VM インスタンスを作成します。

  • AMD SEV または Intel TDX Confidential VM インスタンスのサポートされている構成

  • Confidential Space イメージに基づく OS。

  • セキュアブートが有効になっています。

  • Alex が以前に作成した添付されている Docker イメージ。

  • ワークロードを実行するサービス アカウント。

Bola の Cloud Shell で次のコマンドを入力して、ワークロードをデプロイします。

gcloud compute instances create WORKLOAD_VM_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 \
    --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"

Bola のプロジェクトでワークロードの進行状況を確認するには、ログ エクスプローラに移動します。

[ログ エクスプローラ] に移動

Confidential Space ログを検索するには、次のログフィールド(利用可能な場合)でフィルタします。

  • リソースタイプ: VM インスタンス

  • インスタンス ID: VM のインスタンス ID

  • ログ名: confidential-space-launcher

ログを更新するには、 [現在の位置に移動] をクリックします。

ワークロードが完了すると、VM インスタンスが停止します。暗号化された給与ファイルを変更してワークロードを再度デプロイする場合に必要なのは、既存の VM を起動することのみです。

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

ワークロードをデバッグする

ログ エクスプローラを使用して、リソースが正しく設定されていない、またはプロバイダに Confidential Space ワークロードによって行われたクレームと一致しない属性条件があるなどの問題をトラブルシューティングすることができます。

そのためには、次の変更を行う必要があります。

  • Alex と Bola の Workload Identity プール プロバイダを更新して、support_attributes アサーションを削除します。詳細なトラブルシューティングを行うには、Confidential Space デバッグ イメージを使用する必要があります。このイメージには、検証するサポート属性がありません。

  • Confidential Space デバッグ イメージを使用してワークロード VM を作成し、VM メタデータを設定して STDOUTSTDERR を Cloud Logging にリダイレクトし、ワークロードからのすべての出力をキャプチャします。

変更を行う手順は次のとおりです。

  1. Alex のプロジェクトに切り替えます。

    gcloud config set project ALEX_PROJECT_ID
    
  2. Alex のプロバイダを更新して、support_attributes アサーションを削除します。

    gcloud iam workload-identity-pools providers update-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=ALEX_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  3. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  4. Bola のプロバイダを更新して、support_attributes アサーションを削除します。

    gcloud iam workload-identity-pools providers update-oidc attestation-verifier \
        --location=global \
        --workload-identity-pool=BOLA_POOL_NAME \
        --issuer-uri="https://confidentialcomputing.googleapis.com/" \
        --allowed-audiences="https://sts.googleapis.com" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.submods.container.image_digest == 'DOCKER_IMAGE_DIGEST' \
    && 'WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts \
    && assertion.swname == 'CONFIDENTIAL_SPACE'"
    
  5. Confidential Space デバッグ イメージを使用して新しい VM を作成し、メタデータで tee-container-log-redirecttrue に設定します。

    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"
    

本番環境イメージとは異なり、デバッグイメージはワークロードの完了後に VM を実行し続けます。つまり、SSH を使用して VM に接続し、デバッグを続行できます。

結果を見る

ワークロードが正常に完了すると、Alex と Bola の両方がそれぞれの結果バケットで結果を表示できます。

  1. Alex のプロジェクトに切り替えます。

    gcloud config set project ALEX_PROJECT_ID
    
  2. 結果バケット内のすべてのファイルを一覧表示します。

    gcloud storage ls gs://ALEX_RESULTS_BUCKET_NAME
    

    次に、最新のファイルを読み取ります。

    gcloud storage cat gs://ALEX_RESULTS_BUCKET_NAME/ALEX_RESULTS_FILE_NAME
    
  3. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  4. Bola の場合は、結果バケット内のすべてのファイルを一覧表示します。

    gcloud storage ls gs://BOLA_RESULTS_BUCKET_NAME
    

    次に、最新のファイルを読み取ります。

    gcloud storage cat gs://BOLA_RESULTS_BUCKET_NAME/BOLA_RESULTS_FILE_NAME
    

ファイルを読み取ることで、Alex と Bola は互いに自身の給与について明らかにすることなく、2 人のうちいずれの給与がより高額であるかを調べることができます。

クリーンアップ

このガイドで作成したリソースを削除するには、次の操作を行います。

アレックスのリソースをクリーンアップする

  1. Alex のプロジェクトに切り替えます。

    gcloud config set project ALEX_PROJECT_ID
    
  2. Alex のデータを復号するサービス アカウントを削除します。

    gcloud iam service-accounts delete \
        ALEX_SERVICE_ACCOUNT_NAME@ALEX_PROJECT_ID.iam.gserviceaccount.com
    
  3. Alex の Workload Identity プールを削除します。

    gcloud iam workload-identity-pools delete ALEX_POOL_NAME \
        --location=global
    
  4. Alex の Cloud Storage バケットを削除します。

    gcloud storage rm gs://ALEX_INPUT_BUCKET_NAME \
        gs://ALEX_RESULTS_BUCKET_NAME --recursive
    
  5. Alex の給与ファイルと Go コードを削除します。

    rm ALEX_SALARY.txt \
        ALEX_ENCRYPTED_SALARY_FILE \
        salary.go salary \
        go.mod go.sum
    
  6. (省略可)Alex の Cloud Key Management Service 鍵を無効化または破棄します。

  7. 省略可: Alex のプロジェクトをシャットダウンします。

Bola のリソースをクリーンアップする

  1. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  2. ワークロード VM を削除します。

    gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-b
    
  3. Bola のデータを復号するサービス アカウントと、ワークロードを実行するサービス アカウントを削除します。

    gcloud iam service-accounts delete \
        BOLA_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com
    
    gcloud iam service-accounts delete \
        WORKLOAD_SERVICE_ACCOUNT_NAME@BOLA_PROJECT_ID.iam.gserviceaccount.com
    
  4. Bola の Workload Identity プールを削除します。

    gcloud iam workload-identity-pools delete BOLA_POOL_NAME \
        --location=global
    
  5. Bola の Cloud Storage バケットを削除します。

    gcloud storage rm gs://BOLA_INPUT_BUCKET_NAME \
        gs://BOLA_RESULTS_BUCKET_NAME --recursive
    
  6. Bola の給与ファイルを削除します。

    rm BOLA_SALARY.txt \
        BOLA_ENCRYPTED_SALARY_FILE
    
  7. (省略可)Bola の Cloud Key Management Service 鍵を無効化または破棄します。

  8. 省略可: Bola のプロジェクトをシャットダウンします。