handatのdatファイル

日頃の出来事を格納するdatファイル

Terraform CloudからGCPにOIDC認証で接続する

はじめに

最近、GCP(Google Cloud Platform)を少し触ろうと思い、せっかくならTerraformでリソース管理しようとしたのだが、Terraform CloudとGCPを接続する方法の記事が日本語だとあまり見つからなかった。
そもそも、「Terraform Cloud GCP」みたいな検索クエリだと検索意図を「Terraform Google Cloud Platform」とも解釈されてしまうため"非Terraform Cloud"の記事も多くヒットしてしまって目的の記事を探すのが難しいという課題もある。

そこで、一つでもTerraform CloudとGCPに関する記事を増やそうと、設定手順のログを記事として残しておく。

Terraform CloudとGCPを利用(認証)する2つの方法

Terraform Cloudの環境からrunしたときGCPの認証を行う方法は2種類ある

  • サービスアカウントのキーで認証を行う
  • Workload Identity連携を利用して動的クレデンシャル認証を行う
    • OIDCを利用してTerraform CloudとGCP間の認証を行う

この記事ではTerraform Cloud側にGOOGLE_CREDENTIALSのようなセンシティブな情報を保存する必要がないWorkload Identity連携を利用して動的認証を行う方法を紹介していく

手っ取り早く使いたい人向けの情報

Workload Identity連携を利用した認証ができれば何でも良いという人はこちらの記事を見て、Terraform CloudとGCPの設定をlocal等のTerraformで行う方法を見ていただくのが良いだろう。

zenn.dev

操作手順

ここから具体的な操作手順に入っていく。

目標

この記事では下記のことができる環境を用意することをゴールとする。

  • Terraform CloudのワークスペースGCPプロジェクトのリソースを作成できるようにする
  • Terraform CloudとGCP間はOIDCを利用した動的クレデンシャル認証を行う

事前準備

これらのリソースは既に存在している前提で手順は書いていく。

[GCP] Workload IdentityのIDプールとプロバイダを作成する

まず、Terraform CloudからGCPへOIDCで認証するためにGCPで「IAMと管理」内のWorkload Identity連携でIDプールとプロバイダを作成する。

1. IDプールの作成

  • プール名
  • 説明
    • 空欄でも問題ないが、Terraform CloudのOrganization名/Workspace名を入れておくと分かりやすいと思う

2. プールにプロバイダを追加

  • プロバイダの選択: OpenID Connect (OIDC)を選択
  • プロバイダ名: tfc-oidc-providerなど任意の名前を付ける
    • ベストプラクティスに沿うのであれば、IDプールにプロバイダは1つしか作られないので、プロバイダ名/IDはユニーク性を考慮する必要はない
  • 発行元 (URL): https://app.terraform.io
    • Terraform Cloudを利用するなら、この欄はhttps://app.terraform.ioで固定になる
  • オーディエンス: デフォルトのオーディエンスを選択
Info JWKファイルのアップロードが必要なUIに見えるが、アップロードしなかった場合は`/.well-known/openid-configuration`からJWKファイルを取得してくるので空欄のまま進めて問題ない

Terraform Cloudの場合は下記のURLのjwks_uriがJWKファイルとして取り込まれる。 https://app.terraform.io/.well-known/openid-configuration

参考: Workload Identity 連携  |  IAM のドキュメント  |  Google Cloud

3. プロバイダの属性を構成

属性マッピング

属性マッピングはこの後の手順があるサービスアカウントとプロバイダを関連付ける際のロールバインディングで使用するようだが、今回は使わないので最低限必要なマッピングだけを設定していく。

Google OIDC
google.subject assertion.sub

属性条件

assertion.terraform_full_workspace=='organization:${TFC_ORGANIZATION}:project:${TFC_PROJECT}:workspace:${TFC_WORKSPACE}'

${TFC_ORGANIZATION}, ${TFC_PROJECT}, ${TFC_WORKSPACE}は各自の環境で異なる値

Terraform Cloudの公式の例ではassertion.sub.startsWith(\”organization:my-org:project:my-project:workspace:my-workspace”\)という記述が用いられているがsub.startsWithだとmy-workspace2のように複数のワークスペースでOIDCトークンが認証されてしまうので、assertion.terraform_full_workspaceの完全一致で条件を指定したほうがより安心なはずである。

Warning 属性条件が不十分だと第三者がTerraform Cloudの他のワークスペースからGCPプロジェクトにアクセスできてしまう可能性があるため、属性条件またはサービスアカウントのロールバインディングを適切に設定する必要がある。

これで保存すれば、IDプールとプロバイダを作成することができる。

[GCP] Workload Identityプールにサービス アカウントへのアクセスを許可する

次にTerraform CloudからGoogle Cloudのリソースを操作を操作するためのサービスアカウントでWorkload Identityを利用できるようにする。

1. サービスアカウントを作成

まず、適切な権限を持ったサービスアカウントを作成しておく。 既にGOOGLE_CREDENTIALS認証で利用しているサービスアカウントがあればそれでも問題は無い。

2. プールにサービスアカウントのアクセス権を追加する

先ほど作成したプールの詳細画面を見に行くと「アクセス権を追加」という項目からアクセス権を追加する。

  • サービスアカウント: Terraform Cloudで使用するサービスアカウントを選択
  • プリンシパル(サービス アカウントにアクセスできる ID)の選択: プール内のすべてのID

追加の際に「アプリケーションの構成」というモーダルが表示されるが、これは不要なので「非表示」を押して閉じてしまって問題ない。

このモーダルは「非表示」で閉じてしまってよい

ここまで行えばGCP側の設定は完了となる。

[TFC] 認証用の環境変数を設定する

最後にTerraform CloudからGoogle Cloudへの接続時に作成したWorkload Identity経由で認証するようワークスペース環境変数を追加する。

Key Value
TFC_GCP_PROVIDER_AUTH true
TFC_GCP_RUN_SERVICE_ACCOUNT_EMAIL Workload Identityと連携させたサービスアカウントのメールアドレス
TFC_GCP_PROJECT_NUMBER GCPのダッシュボードに表示されているプロジェクト番号
TFC_GCP_WORKLOAD_POOL_ID 作成したプールのID
TFC_GCP_WORKLOAD_PROVIDER_ID 作成したプロバイダのID

変数の種類はすべてEnvironment variableを選択する。

Info Workload Identityプロバイダを指定する環境変数には上記で紹介した`TFC_GCP_PROJECT_NUMBER `, `TFC_GCP_WORKLOAD_POOL_ID`, `TFC_GCP_WORKLOAD_PROVIDER_ID`を使う方法の他に、統合した変数`TFC_GCP_WORKLOAD_PROVIDER_NAME`を使う方法がある。

TFC_GCP_WORKLOAD_PROVIDER_NAMEは下記のフォーマットになるが、変数一覧を見たときに各値が分かりやすいよう個別の変数を設定する方法で設定をおこなった。

projects/${TFC_GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${TFC_GCP_WORKLOAD_POOL_ID}/providers/${TFC_GCP_WORKLOAD_PROVIDER_ID}

ここまで設定すればWorkload Identity連携を用いた動的認証が使えるようになっているはず。

トラブルシューティング

実際にTerraform Cloudでrunしてみたところ下記のようなエラーに遭遇したので、対処方法を書いておく。

アクセストークンの生成失敗系のエラー (status code: 400)

Invalid resource name supplied as 'audience': parent resource 'projects/***' does not exist or has been disabled/deleted.

TFC_GCP_PROJECT_NUMBER環境変数の値が間違っているときに表示されるエラー
対処方法: GCPのプロジェクト番号をダッシュボードで確認して、TFC_GCP_PROJECT_NUMBERの値を変更する

The given credential is rejected by the attribute condition.

プロバイダ作成時の属性条件と実行したTerraform Cloudの環境が一致していないときに表示されるエラー 対処方法: Workload Identityプロバイダの属性条件を確認して、組織名/プロジェクト名/ワークスペース名などに間違いがないか確認する

Permission系のエラー (status code: 403)

IAM Service Account Credentials API has not been used in project *** before or it is disabled

OIDCトークンでの認証に必要なAPIが有効になっていないときに表示されるエラー
対処方法: APIとサービスの画面からIAM Service Account Credentials APIを有効にする

Permission '*******' denied on resource

サービスアカウントにリソースの作成・変更に必要な権限が付いていないときに表示されるエラー 対処方法: プロバイダと関連付けたサービスアカウントのプリンシパルに割り当てられているロールを変更する

参考ページ