Google Cloud Terraform IAM リソースの説明を試みる
どれを使うべきかよくわからん、というのはよく言われている話ですが、こういうメンタルモデルを持てばスッと分かるんじゃないかという説明を試みたい。
Terraform Google Provider の IAM 設定リソースは、google_{対象リソース}_iam_{付与の仕方} という命名になっています。
(ここでの "対象リソース" は Google Cloud のリソースの方、Terraform の Resrouce ではない)
よく使う google_{対象リソース}_iam_member の話として進めるとしましょう。
対象リソース
google_{対象リソース}_iam_member のような Terraform Resource がいろいろ定義されてます。
google_project_iam_member
google_secret_manager_secret_iam_member
google_storage_bucket_iam_member
google_bigquery_dataset_iam_member
...
これらは例えばこんな感じに使うんですが、
code:secret_manager.tf
resource "google_secret_manager_secret_iam_member" "member" {
secret_id = google_secret_manager_secret.secret_foo.secret_id # 対象
role = "roles/secretmanager.secretAccessor"
member = "user:jane@example.com"
}
これは、member に 対象リソース(ここでは secret_id) についての role を付与しています
この roles/secretmanager.secretAccessor ロール自体は、 google_project_iam_member を使っても付与できます。
code:secret_manager.tf
resource "google_project_iam_member" "secret_accessor" {
project = var.project
role = "roles/secretmanager.secretAccessor"
member = "user:jane@example.com"
}
何が違うのかというと、対象リソース が違います。
google_project_iam_member を使って付与する = (ユーザー, プロジェクト) の組に対して付与する
google_secret_manager_secret_iam_member を付与する = (ユーザー, 特定のシークレット) の組に対して略
https://gyazo.com/db69bb6063c98837a53fea95dff2e65e
特定のサービスアカウントにアクセス権を与えたい場合、大抵は特定のシークレットに絞って与えたいので google_secret_manager_secret_iam_member を使うことになります(記事の通り)。
プロジェクト全体のシークレットを読ませたい場合なんてあるの? と思うかもしれないけど、それは俺らプロジェクトを操作するユーザに権限がついていて、コンソールを通してシークレットを読み書きできるわけです (roles/editor 等に入っている)
なので「シークレットのアクセスは別の Terraform リソース」「統一されていない」というわけではなく、ユースケースに応じて付与する対象が異なり、terraform resource を使い分けている、という認識を持つとよさそう。
(余談)プロジェクトも対象リソースであるという点はなんとなく resrouce 定義の省略可能性からも読み取れて、
google_secret_manager_secret_iam_member や google_bigquery_dataset_iam_member などにおいては project attribute は省略可能なのに対し、google_project_iam_member においては省略不可になってます。
Google Cloud プロバイダの認証情報的を使って いる段階で大抵1つプロジェクトが決まっているわけですが、それをデフォルト値として使っていません。~secret_iam_member で secret_id を省略できないように、ロールを与える対象リソースを指定するんだから省略できない、と捉えると一貫しているし自然ですね。
サービスアカウントを利用できるようにする
一般的にこの用途で登場するロールが2つあります
roles/iam.serviceAccountUser サービスアカウントユーザー (あんまり意識しない)
サービスアカウントをリソースに関連付けるための権限
roles/iam.serviceAccountTokenCreator トークン作成者 (ちょくちょく使う)
サービスアカウントに成り代わって操作するための権限
サービスアカウントユーザー roles/iam.serviceAccountUser
サービスアカウントをリソースにアタッチするための権限
アタッチとはなんぞやというのは具体的に考えると
https://gyazo.com/2563cb49a835322be1914b551de8758b
ユーザー(サービスアカウントユーザー)は Cloud Run にアプリケーションをデプロイする際に SA を指定(アタッチ)する
Cloud Run 上で動くアプリケーションは SA の権限で CloudSQL や Cloud Storage にアクセスする
アタッチ = 元のユーザの手を離れて "誰" として動作するかを指定すること
サービスアカウントユーザー = 特定の SA を指定するための権限
これはリソースの設定時やデプロイ時に必要なロールであるものの、role/editor に含まれているので、普段人間が設定したり Terraform を実行する上ではあまり出番はないけど、SA を介して設定をしたいシチュエーションで必要になる。
もしこの権限チェックが無いと仮定すると、Cloud Run をデプロイできるユーザは、デプロイの際にプロジェクト内に存在する最強の権限の SA をアタッチすることで実質的にその権限を持つことと同じになって SA を作り分けてロールを管理する意味がなくなりますね。昔デフォルトサービスアカウントにはこの穴? があって整備されたのは比較的最近で 2021 年とか。
https://gyazo.com/46e6b6587ae9568f2cd696e613fb55de
サービスアカウントトークン作成者 roles/iam.serviceAccountTokenCreator
トークンを作成する = サービスアカウントに成り代わる、権限を借りて操作するための権限
記事には関係ないけど、サービスアカウントの権限で何かをする、ときに主に使うのはこちらです
https://gyazo.com/26b36d3036ace17c452560a4e2c56ee5
このロールを持っている SA に対し gcloud --impersonate-service-account=SA_EMAIL でなりすまして gcloud コマンドを使えたりします。
用途としては、
権限管理を集約する(多くの人間に配るのではなく Gateway 的な SA を通させて管理やログを追えるようにする)
一時的な権限昇格を実現する(SA がより強い権限、本番環境へのアクセスや機密データを持っていて、それを貸し出す)
トークンの TTL を使って短時間の権限を付与する (GitHub Actions から Google Cloud を使う Workload Identity とかもこれ)
アタッチした SA の権限が足りないときのデバッグ
編集者 roles/editor というのは大体何でもできる強いロールですが、トークン作成者はデフォルトでは持っていません。
このロールの出番があるのは、何らかポリシーを持ってアクセス制御を行いたい時なので editor 全員に配ってるのは変、というのに共感できると納得できますね。ちなみにこれも個別の SA に対してではなく、プロジェクトレベルで付与するとプロジェクトの全部の SA のトークンを作成できる最強人間になります。
このあたりの話は全部ここに書いてる
まとめると
記事でやっていることは、
プロジェクト全体で Cloud Build を実行できるようにする
google_project_iam_member を使う
特定の SA を Cloud Run にアタッチできるようにする (= Cloud Run をデプロイできるようにする)
google_service_account_iam_member を使う
特定の Secret を 読み取れるようにする
google_secret_manager_secret_iam_member を使う
という3つのスコープで別々の権限を与えているという話で、適切だと思います。
Cloud Runの実行用のSAにバトンタッチする必要がある
これはアタッチと実行 SA は別というのが曖昧な状態で書いているのだと思うけど(実際にサービスアカウントユーザーを付与しているし)、Cloud Build 実行サービスアカウントを実行ごとに個別に指定しているからかな?
Cloud Build 実行サービスアカウントを1つ決めて、プロジェクトレベルのサービスアカウントユーザをつけると任意の SA をアタッチできるので簡単だと思う。セキュリティ的にはきめ細かな権限設定をするのが良い姿勢ではありますが、そういうUI 用意しとるの Google Cloud お前やろという気持ちで自分はサボってます。 ---.icon
以下おまけ
付与の仕方
ユースケースに応じて付与の仕方は _policy, _binding, _member の3種類用意されてます
これは Google Cloud の概念ではなく、Terraform 側 & ユースケースからくるもので、Authoritative と Non-Authoritative(Additive) の違いをわかっていないと、_binding と _member で同じロールを参照して取り合ってハマっているのを偶に見る
その他知っておくと良い概念
プリンシパル
ユーザやシステム上の操作者、"誰" を表す概念
ユーザの Google アカウント、サービスアカウントなど
Google Group や Google Workspace ドメイン、全員 を表す allUsers など集合の場合もあります
user:EMAIL や serviceAccount:EMAIL, group:EMAIL など prefix 付けて指定します
サービスエージェント
Google Cloud 側で自動的に作成される、特定のサービスに紐づいているサービスアカウントまたはその権限
例えば PubSub を使い始めると
Cloud Pub/Sub Service Agent service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com が生え
PubSub に関する internal な操作が一通りできる roles/pubsub.serviceAgentロールが付与されている
API を有効にしたタイミングや、最初の1つ目のリソースを作成した段階で生えてくる
うっかり消したりロールを外したりしてしまったときにしょんぼりして設定する
ロールはパーミッションを束ねて名前をつけたもの
パーミッション = 許可されている個々の操作
code:quote
例えば BigQuery データ閲覧者 (roles/bigquery.dataViewer) は、以下の permission を持つ。
- bigquery.datasets.get
- bigquery.datasets.getIamPolicy
- bigquery.models.export
- bigquery.models.getData
- bigquery.models.getMetadata
- bigquery.models.list
- ...
大抵は "事前定義ロール" で考えて付与していているけど、任意のパーミッションを束ねてカスタムロールを作ることもできる