NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    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 を有効にします。

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

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

    Workload Identity設定

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

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

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

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

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

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

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

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

    {
      "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は無効にしておきます。

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

    どうやら認証の仕組みとして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ファイルとは別の場所でも大丈夫です)

    これで準備完了なので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側にも作成できていることが確認できます。

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

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

    検証は以上です。

    まとめ

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

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

    執筆者上野史瑛

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