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

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

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

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

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

始める前に

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

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

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

必要なロール

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

  • データ共同編集者(Alex と Bola)の Cloud KMS 管理者(roles/cloudkms.admin)。
  • データ共同編集者(Alex と Bola)の IAM Workload Identity プール管理者(roles/iam.workloadIdentityPoolAdmin)。
  • データ共同編集者(Alex と Bola)の Service Usage 管理者(roles/serviceusage.serviceUsageAdmin)。
  • データ共同編集者(Alex と Bola)とワークロード オペレーター(Bola)のストレージ管理者(roles/storage.admin)。
  • ワークロード オペレーター(Bola)のサービス アカウント管理者(roles/iam.serviceAccountAdmin)。
  • ワークロード オペレーター(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 のリソースを設定するには、次の手順を行います。

  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 \
        artifactregistry.googleapis.com \
        cloudkms.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. Alex の Workload Identity プールを作成します。

    gcloud iam workload-identity-pools create ALEX_POOL_NAME \
        --location=global
  8. 入力データ用の Cloud Storage バケットと、結果を保存するための別のバケットを作成します。

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

    echo 123456 > ALEX_SALARY.txt
  10. ファイルを暗号化して、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 \
        compute.googleapis.com \
        confidentialcomputing.googleapis.com \
        iamcredentials.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. Bola の Workload Identity プールを作成します。

    gcloud iam workload-identity-pools create BOLA_POOL_NAME \
        --location=global
  7. 入力データ用の Cloud Storage バケットと、結果を保存するための別のバケットを作成します。

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

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

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

このガイドでは、Bola がワークロードを運用していますが、サードパーティを含む誰でもこれらのロールを引き継ぐことができます。ワークロードを実行するために Bola が作成する VM インスタンスには、構成証明トークンの生成、ログの書き込み、Alex と Bola の暗号化されたデータの読み取り、特定の結果バケットへの結果の書き込みを行う権限を持つサービス アカウントが関連付けられています。

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

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

    gcloud iam service-accounts create WORKLOAD_SERVICE_ACCOUNT_NAME
    
  2. サービス アカウントを後でワークロード VM に関連付けることができるように、Bola に iam.serviceAccountUser ロールを付与します。

    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://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.objectAdmin
    

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

ワークロードを作成する

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

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

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

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

  • ワークロード コードを含み、実行する Docker イメージ。

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

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

    gcloud config set project ALEX_PROJECT_ID
    
  2. [エディタを開く] をクリックして Cloud Shell エディタを開き、salary.go という名前の新しいファイルを作成します。ファイルに次のコードをコピーし、保存します。

    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
    }
    
  3. すべての関係者がソースコードを読み取り、監査していることを確認します。

  4. Cloud Shell エディタで、次の内容を含む Dockerfile という名前のファイルを作成します。

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

    この Dockerfile は、マルチステージ ビルドを使用して、まず Go コードをコンパイルし、そのコードのコンパイル済みバージョンを最終的なワークロード コンテナにコピーします。また、そのワークロード コンテナで特定の環境変数を使用することもできます。これらの環境変数の値は、ワークロードが動作するために必要な特定のリソースに後でマッピングされます。

  5. [ターミナルを開く] をクリックして Cloud Shell に戻るか、[表示] メニューから Cloud Shell エディタに組み込まれているターミナルを呼び出します。

  6. Artifact Registry で Docker リポジトリを作成します。

    gcloud artifacts repositories create REPOSITORY_NAME \
        --repository-format=docker \
        --location=us
    
  7. ワークロードを実行するサービス アカウントに 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
    
  8. Docker 認証情報を更新して、us-docker.pkg.dev ドメイン名を含めます。

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

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

    docker push \
        us-docker.pkg.dev/ALEX_PROJECT_ID/REPOSITORY_NAME/WORKLOAD_CONTAINER_NAME
    
  11. Docker の push レスポンスには、イメージの SHA256 ダイジェストがリストされます。これは、後でワークロードを承認するために必要になります。ダイジェストは次の例のようになります。

    sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    

    イメージのダイジェスト(sha256: 接頭辞を含む)を、参照できる場所にコピーします。次のコードサンプルにダイジェストを入力して、このガイドの残りのコードサンプルで値が必要な箇所を事前入力することもできます。

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

ワークロードを承認する

ワークロードが両当事者によって承認されたら、Alex と Bola は Google Cloud Attestation をワークロード ID プールのプロバイダとして追加する必要があります。プロバイダは、使用する構成証明サービスと、Alex または Bola のデータで動作できるようにワークロードが一致する必要があるプロパティを指定します。悪意のあるユーザーが Docker イメージを変更したり、別の測定されたプロパティを変更したりすると、ワークロードはアクセスを拒否されます。

このガイドでは、属性マッピングを使用して、イメージ ダイジェストに基づいてワークロードにリソースへの直接アクセスを提供します。ただし、他の状況では、サービス アカウントの権限借用を使用してリソースにアクセスすることをおすすめします。詳細については、外部ワークロード アクセスをご覧ください。

必要な条件で 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=\"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'"
    
  2. 次のコマンドで使用する Alex のプロジェクト番号を取得します。

    gcloud projects describe ALEX_PROJECT_ID --format="value(projectNumber)"
    
  3. Alex のプロバイダで定義されたフェデレーション ID に cloudkms.cryptoKeyDecrypter ロールを付与し、image_digest 属性を指定して、指定されたダイジェストを持つワークロード コンテナのみが KMS 鍵を復号できるようにします。

    gcloud kms keys add-iam-policy-binding \
        "projects/ALEX_PROJECT_ID/locations/global/\
    keyRings/ALEX_KEYRING_NAME/\
    cryptoKeys/ALEX_KEY_NAME" \
        --member="principalSet://iam.googleapis.com/\
    projects/ALEX_PROJECT_NUMBER/locations/global/\
    workloadIdentityPools/ALEX_POOL_NAME/\
    attribute.image_digest/WORKLOAD_CONTAINER_IMAGE_DIGEST" \
        --role=roles/cloudkms.cryptoKeyDecrypter
    
  4. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  5. 次のコマンドを入力して、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'"
    
  6. 次のコマンドで使用する Bola のプロジェクト番号を取得します。

    gcloud projects describe BOLA_PROJECT_ID --format="value(projectNumber)"
    
  7. Bola のプロバイダで定義されたフェデレーション ID に cloudkms.cryptoKeyDecrypter ロールを付与し、image_digest 属性を指定して、指定されたダイジェストを持つワークロード コンテナのみが 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
    

ワークロードをテストする

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

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

Bola の Cloud Shell に次のコマンドを入力して、ワークロードをテストします。

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"

進行状況を表示

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

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

Confidential Space のログエントリのみを表示するには、次のログのフィールド(使用可能な場合)でフィルタします。

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

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

  • ログ名: confidential-space-launcher

ログを更新するには、 [現在の位置に移動] をクリックします。以前の結果までスクロールしてから、ログの末尾までスクロールして最新のエントリを読み込むこともできます。

結果を見る

ワークロード タスクが終了して 0 が返された場合、エラーが発生していないことを意味します。この時点で、Alex と Bola の出力バケットの出力を確認します。

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

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

    gcloud storage ls gs://ALEX_OUTPUT_BUCKET_NAME
    
  3. リストされている最新のファイルを読み取ります。ALEX_OUTPUT_CLOUD_STORAGE_PATH は、gs:// を含むファイルのパスに置き換えます。

    gcloud storage cat ALEX_OUTPUT_CLOUD_STORAGE_PATH
    

    ファイルが存在しない場合は、ワークロードをデバッグする必要があります。

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

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

    gcloud storage ls gs://BOLA_OUTPUT_BUCKET_NAME
    
  6. リストに表示されている最新のファイルを読み取ります。BOLA_RESULTS_CLOUD_STORAGE_PATH は、gs:// を含むファイルのパスに置き換えます。

    gcloud storage cat BOLA_RESULTS_CLOUD_STORAGE_PATH
    

    ファイルが存在しない場合は、ワークロードをデバッグする必要があります。

  7. 結果を正常に読み取ったら、VM インスタンスを停止します。

    gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b
    

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

ワークロードをデバッグして再起動する

Confidential Space 環境には多くの部分があり、ワークロードが失敗する原因となる構成ミスが発生している可能性があります。

本番環境の Confidential Space イメージとは異なり、デバッグ イメージはワークロードの終了後も VM インスタンスを実行し続けます。つまり、ログから問題の解決に必要な情報が得られない場合は、次のステップとして SSH 経由で VM インスタンスに接続し、デバッグを続行します。

デバッグが完了したら、VM インスタンスを停止します。

gcloud compute instances stop WORKLOAD_VM_2_NAME --zone=us-west1-b

デバッグされた環境に対してワークロードを実行するには、VM を再度起動します。

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

本番環境用に環境を強化する

ワークロードのテストが正常に完了したら、本番環境へのデプロイ用に Confidential Space 環境を強化します。Alex と Bola は、本番環境の Confidential Space イメージがワークロードに使用されていることを確認するために、プロバイダに support_attributes アサーションを追加する必要があります。

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

    gcloud config set project ALEX_PROJECT_ID
    
  2. 次のコマンドを入力して、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"
    
  3. Bola のプロジェクトに切り替えます。

    gcloud config set project BOLA_PROJECT_ID
    
  4. 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"
    

本番環境のワークロードをデプロイする

Bola は、本番環境のワークロードを実行するために、別の VM インスタンスを作成する必要があります。次の点は、テスト ワークロードとは異なります。

  • OS は、本番環境の Confidential Space イメージに基づいています。この場合、SSH は無効になり、ワークロードの完了後に VM インスタンスが停止します。

  • ロギング リダイレクトが削除されます。機密情報が公開されていない基本ログのみが Cloud Logging に表示されます。

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

進行状況の確認結果の確認の方法は、ワークロードをテストしたときと同じです。

本番環境ワークロードが完了すると、VM インスタンスは停止します。別の結果を表示するには、給与を変更して再暗号化し、それぞれの Cloud Storage バケットに再度アップロードしてから、VM インスタンスを再起動してワークロードを再度実行します。

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

クリーンアップ

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

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

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

    gcloud config set project ALEX_PROJECT_ID
    
  2. Alex の Workload Identity プールを削除します。

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

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

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

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

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

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

    gcloud config set project BOLA_PROJECT_ID
    
  2. テスト ワークフローを実行した VM を削除します。

    gcloud compute instances delete WORKLOAD_VM_2_NAME --zone=us-west1-b
    
  3. 本番環境のワークフローを実行した VM を削除します。

    gcloud compute instances delete WORKLOAD_VM_NAME --zone=us-west1-b
    
  4. ワークロードを実行したサービス アカウントを削除します。

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

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

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

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

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