Workload Identityを使用して、AWS環境からGoogle Cloudリソースを作成する

こんにちは、上野です。

今回はGoogle Cloud関連の内容です。みなさまGoogle CloudのリソースをTerraformなどのIaCでデプロイする場合、どのように実行されていますか?

AWSがメイン処理+Google Cloud(BigQueryなど一部)という構成を取ることがあり、AWS側でデプロイ管理もしようとすることも我々の現場では多いです。 Google CloudのリソースをAWSからデプロイする場合、Google Cloud側にサービスアカウント+キーを作成してそれを使用することもあるかと思います。 ただ、この場合永続的なキー情報になるため、この漏えいが心配になります。

Workload Identity 連携を使用すると、永続的なキーを使用せずAWSからアクセスできるとのことなので、今回はそれを試してみます。次のような構成イメージです。

AWS 側のIAM Roleを使用して、Google Cloud側のサービスアカウントにID連携を行います。永続的なキーを使用しないのが嬉しいポイントですね。

やってみる

今回はAWS環境のCloud9(EC2)からTerraformを実行し、Google Cloud上にCloud Storageバケットを作成するサンプルを実行してみます。

こちらの手順に従って実施していきます。わかりやすさ重視で、Console(GUI)中心でやっていきます。

今回は組織に属さないプロジェクト単体の環境で試しています。

前準備

API有効ページからIAM, Resource Manager, Service Account Credentials, and Security Token Service (STS) API を有効にします。

f:id:fu3ak1:20210626113903p:plain

GCP側で使用する、サービスアカウントを作成しておきます。今回はGCSバケットの作成を試すため、Storage Adminの権限を付与して作成しておきます。

f:id:fu3ak1:20210627233547p:plain

AWS側の設定(Cloud9+IAM Role)は、後ほどTerraform実行時の説明に記載します。

Workload Identity設定

新しいワークロード プロバイダとプール ページから、Identity poolの作成と設定をしていきます。

任意のPool IDを設定します。

f:id:fu3ak1:20210626115040p:plain

Provider name、Provider ID、接続するAWS Accout IDを入力します。

f:id:fu3ak1:20210627232453p:plain

provider attributesは今回はデフォルトのまま設定しておきます。

f:id:fu3ak1:20210627232805p:plain

作成したWorkload Identity プールに、アクセス許可を追加していきます。

f:id:fu3ak1:20210627233208p:plain

前準備で作成したバケット作成が可能なサービスアカウントを設定します。 Select members のところは、今回はプール内のすべての IDがアクセスできるように設定しておきます。

f:id:fu3ak1:20210628224948p:plain

認証情報ファイル(json)が取得できるので、ダウンロードしておきます。

f:id:fu3ak1:20210628225312p:plain

認証情報ファイルの内容は以下のとおりで、特にキー情報が含まれていません。

{
  "type": "external_account",
  "audience": "//iam.googleapis.com/projects/[ProjectNumber]/locations/global/workloadIdentityPools/fromaws/providers/awstogcp",
  "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/createbucket@[ProjectID].iam.gserviceaccount.com:generateAccessToken",
  "token_url": "https://sts.googleapis.com/v1/token",
  "credential_source": {
    "environment_id": "aws1",
    "region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
    "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
    "regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
  }
}

AWS環境からデプロイ

AWSアカウント上のCloud9から、Google Cloudへデプロイしてみます。

Cloud9にはIAMロールを付与し、cloud9のtemporary credentialは無効にしておきます。

f:id:fu3ak1:20210628232326p:plain

Cloud9に付与するロールはポリシー無し(権限無し)で問題ありませんでした。(NullRoleと命名)

f:id:fu3ak1:20210628232511p:plain

どうやら認証の仕組みとしてIAMロール名を使用しているようで、temporary credentialではロール名が正しく取得できずエラーとなりました。よってAWS側の権限は不要でも、IAMロールを付与する必要があるようです。

次のようなGCSバケットを作成するだけのTerraformコード(gcs.tf)を用意します。
※プロジェクトIDとバケット名は適宜置き換えてください

provider "google" {
  project     = "[プロジェクトID]"
}

resource "google_storage_bucket" "test" {
  name          = "test-bucket-fu3ak1-20210628"
  location      = "ASIA"
}

先ほどGCP側でダウンロードした認証情報ファイル「clientLibraryConfig-awstogcp.json」も、Cloud9上にアップロードしておきます。 次のようなファイル構成にしました。(認証情報ファイルはtfファイルとは別の場所でも大丈夫です)

f:id:fu3ak1:20210628233001p:plain

これで準備完了なのでapplyしていきます。

Google Cloudの認証情報ファイルを環境変数GOOGLE_APPLICATION_CREDENTIALSに設定します。

TerraformのGoogle Cloud認証方法は、公式ドキュメントにも記載があります。

export GOOGLE_APPLICATION_CREDENTIALS=~/environment/terraform-gcs/clientLibraryConfig-awstogcp.json

あとはtfファイルがあるterraform-gcsフォルダに移動して、terraform applyを実行するだけです。 次のようにapplyが成功します。

$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # google_storage_bucket.test will be created
  + resource "google_storage_bucket" "test" {
      + bucket_policy_only          = (known after apply)
      + force_destroy               = false
      + id                          = (known after apply)
      + location                    = "ASIA"
      + name                        = "test-bucket-fu3ak1-20210628"
      + project                     = (known after apply)
      + self_link                   = (known after apply)
      + storage_class               = "STANDARD"
      + uniform_bucket_level_access = (known after apply)
      + url                         = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_storage_bucket.test: Creating...
google_storage_bucket.test: Creation complete after 2s [id=test-bucket-fu3ak1-20210628]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Google Cloud側にも作成できていることが確認できます。

f:id:fu3ak1:20210628233601p:plain

参考までに、他のAWSアカウントからterraform applyを実行すると次のエラーとなります。
許可されたAWSアカウントのみデプロイできることがわかります。

{"error":"unauthorized_client","error_description":"Specified aws account id xxxxxxxxxxxx not found in the configured identity providers."}

検証は以上です。

まとめ

Google Cloudでサービスアカウントキーを発行せずに、外部からTerraformでリソースの作成ができました。 今回は検証用途で特にロール名による制限はしませんでしたが、設定次第では特定のロールにアクセスも限定できそうなので、 本番運用時は検討してみたいと思います。

同じ検討をされている方、参考になれば幸いです!

f:id:fu3ak1:20210325095452j:plain

執筆者上野史瑛

Japan APN Ambassador 2020
AWSを中心としたクラウドの導入、最適化を専門に行っています。