Carpe Diem

備忘録

GCPのIAMを使う上で理解しておくこと

背景

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

であれば、

  • フォルダA配下の全プロジェクトの全GCSバケットの参照権限を持つ
  • その上でプロジェクトBの全GCSバケットに対して管理者権限を持つ

となります。

例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を使う上で押さえておくべき点をまとめました。

ソース