背景
IAMはアクセス制御をする上で非常に重要な仕組みですが、一方で複雑になりがちです。
間違った理解のままだと必要以上の権限を与えてしまい、事故の原因となるので押さえておくべき点をいくつかまとめてみます。
リソース階層
GCPのIAMにはリソース階層があり、それぞれの階層を意識した上でIAMポリシーを設定する必要があります。
ref: リソース階層を使用したアクセス制御 | IAM のドキュメント | Google Cloud
リソース階層は4つのレベルがあります。
- 組織レベル
- フォルダレベル
- プロジェクトレベル
- リソースレベル(一部のサービスのみ)
IAMポリシーは階層構造になっていて、最終的にリソースで有効なポリシーは、そのリソースに設定されたポリシーとその上位レベルから継承されたポリシーの和となります。
このような考え方はReBAC(Relationship-Based Access Control)と呼ばれています。
例1
付与するmember | レベル | 対象リソース | 権限 |
---|---|---|---|
ユーザA | プロジェクト | プロジェクトA | roles/storage.objectViewer |
であれば、プロジェクトA内での全てのGCSバケットを参照できます。
例2
付与するmember | レベル | 対象リソース | 権限 |
---|---|---|---|
ユーザA | フォルダ | フォルダA | roles/storage.objectViewer |
ユーザA | プロジェクト | プロジェクトB | roles/storage.objectAdmin |
であれば、
となります。
例3
付与するmember | レベル | 対象リソース | 権限 |
---|---|---|---|
ユーザA | リソース | バケットA | roles/storage.objectViewer |
であれば、
となります。
IAMポリシー(許可ポリシー)
IAMポリシーはbinding
のコレクションです。
binding
は以下の要素で構成されています。
要素 | 説明 |
---|---|
role | 1つ以上の権限をまとめたもの |
members | roleを付与する対象 |
condition | この期間だけ有効、このリソースだけ対象、といった条件。オプショナル |
具体的なデータ構造は以下です。
{ "bindings": [ { "role": "roles/storage.objectAdmin", "members": [ "user:mike@example.com", "group:admins@example.com", "domain:google.com", "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role": "roles/bigquery.admin", "members": [ "user:eve@example.com" ], "condition": { "title": "expirable access", "description": "Does not grant access after Sep 2020", "expression": "request.time < timestamp('2020-10-01T00:00:00.000Z')", } } ] }
モデリングすると以下のような形です。
members
membersは特定ユーザ、グループ、サービスアカウントなど柔軟な設定ができるようになっています。 ※最近はこれらの対象のことをプリンシパルと呼びます
設定できる値 | 意味 |
---|---|
allUsers | 全ユーザ |
allAuthenticatedUsers | すべてのサービス アカウント、および Google アカウントで認証されたユーザー全員 |
user:{emailid} | メールアドレスで指定したGoogle アカウント |
serviceAccount:{emailid} | メールアドレスで指定したサービスアカウント |
group:{emailid} | 指定したGoogle group(メーリングリスト等で使うやつ)に属している全ユーザ |
domain:{domain} | 指定したGoogle Workspace (旧G Suite)/Cloud Identity domainに属する全ユーザ |
ref: ID に関するコンセプト
例えば人の異動が多いチームなどは、毎回IAMポリシーを修正するのではなく、Google Workspace domainやGoogle groupを使うことでIAMポリシーはそのままで権限を付与・剥奪することができます。
リソース階層毎にIAMポリシーがある
繰り返しになりますが、このIAMポリシーはリソース階層毎に存在します。
組織レベルなら
$ gcloud organizations get-iam-policy 組織ID
フォルダレベルなら
$ gcloud alpha resource-manager folders get-iam-policy フォルダID
プロジェクトレベルなら
$ gcloud projects get-iam-policy プロジェクト名
リソースレベル(例えばGCS)なら
$ gsutil iam get gs://バケット名
という形で階層ごとにコマンドが用意されており、IAMポリシーも別々で表示されます。
なので
$ gcloud projects get-iam-policy プロジェクトID \ --flatten="bindings[].members" \ --format='table(bindings.role)' \ --filter="bindings.members:サービスアカウント"
としてプロジェクトレベルのIAMポリシーが無かったとしても、実はリソースレベルで別の権限がついていた、みたいなことも当然あります。
一覧方法
前述のように階層ごと分かれて表示されると確認が大変なので、一覧化するコマンドがあります。
$ gcloud asset search-all-iam-policies --scope=projects/プロジェクト名 --query="policy:メンバー名"
scopeは
- projects/{PROJECT_ID}
- projects/{PROJECT_NUMBER}
- folders/{FOLDER_NUMBER}
- organizations/{ORGANIZATION_NUMBER}
といった形で指定できます。organizationsにすればそれ以下の全階層を含めて検索してくれます。
ただしscopeの権限を持っていないとコケます(=プロジェクト権限しかない場合にorganizations指定するとコケる)。
例えばprojectAのあるサービスアカウントfoobarがどんな権限を持ってるか調べる場合、
$ gcloud asset search-all-iam-policies --scope=projects/projectA --query="policy:foobar"
実行すると
--- policy: bindings: - members: - projectViewer:projectA - serviceAccount:foobar@projectA.iam.gserviceaccount.com role: roles/storage.objectViewer project: projects/123456789 resource: //storage.googleapis.com/バケットA # リソースレベル --- policy: bindings: - members: - serviceAccount:foobar@projectA.iam.gserviceaccount.com role: roles/bigquery.admin project: projects/123456789 resource: //cloudresourcemanager.googleapis.com/projects/projectA # プロジェクトレベル
このようにscope以下の全階層のIAMポリシーが表示されるようになります。
ロールと権限
バインディングに紐づくロールについてもう少し深堀ります。
ロール
ロールは権限のコレクションです。
ref: アクセス管理に関するコンセプト|ロール
ロールは以下の3種類があります。
種類 | 説明 | 例 |
---|---|---|
基本ロール | IAMができる以前のロール。 オーナー、編集者、閲覧者の3つのロールがある |
roles/owner ,roles/editor ,roles/viewer |
事前定義ロール | 特定リソースを扱う際に必要な権限をまとめた、Google側のマネージドロール。roles/service.roleName の命名規則になっている |
roles/pubsub.publisher ,roles/storage.objectAdmin |
カスタムロール | 事前定義ロールでは満たせない場合に自前で作成するロール |
事前定義ロールは非常にたくさんあるので、使用するサービスに応じて確認した方が良いです。
基本的な方針として基本ロールは使わず、事前定義ロールやカスタムロールで最低限の権限のみ付与するのが大切です。
権限
権限は
- あるサービスの (service)
- あるリソースに対して (resource)
- どんな操作を許可するか (verb)
を決めるものです。
なので権限は service.resource.verb
の形式で書かれています。
例)pubsub.subscriptions.consume
権限はアクセス管理における最も細かい粒度です。
まとめ
IAMを使う上で押さえておくべき点をまとめました。