💫

見て見ぬふりをしない、権限とWorkload Identity(Google Cloud)

2024/04/28に公開

はじめに

Google Cloudを使う際、最も頻繁に遭遇するエラーは「権限が足りない」というものでした。特に新しいプロジェクトを立ち上げ、CI/CDの構築に取り組む際、このエラーに何度も直面し、時間を浪費してしまいました。
この経験から、Google Cloudの権限管理を深く知ることが重要であることを痛感しました。そこで、体系的にGoogle Cloudの権限管理を学び、その成果をこの記事でわかりやすく共有したいと思います。

この記事を読んでほしい人

  • Google Cloudにおける権限、ロール、プリンシパル、ポリシーの意味と関係性を説明できない人
  • Workload Identityをなんとなくで使っている人

この記事で言いたいこと

  • Google Cloudにおいて、権限を複数まとめ、使いやすい集合にしたものがロール
  • リソースにアクセスするユーザーのことをプリンシパルといい、ロールとプリンシパルの関係をポリシーで表現している
  • この一連の管理方法がIAM
  • Workload Identityはセキュリティリスクのあるサービスアカウントキーを発行しないで済む
  • Workload Identityを支える認証方法がOIDC

この記事で説明しないこと

  • OIDCの具体的な認証プロセス

IAMを理解する

IAM(Identity and Access Management)は次の3つの要素を管理するシステムです。

  • アクセスするユーザー(ID)
  • アクセスされるリソース
  • そのとき可能な操作(権限)

これらをきめ細かく、かつ最小限の権限で管理するためにGoogle Cloudはさまざまな機能を導入しています。一つずつ順番に見ていきましょう。

プリンシパル

まず、Google CloudリソースにアクセスするIDのことをプリンシパルといいます。このIDは以下のどれかです。

  • Google アカウント
  • サービス アカウント
  • Googleグループ
  • Google Workspaceアカウント
  • Cloud Identityドメイン
  • 認証済みのすべてのユーザー
  • すべてのユーザー

Google Cloudではプリンシパルに対して権限を付与します。

権限

まず、一般的な用語として使われる「権限」とは意味が異なっています。Google Cloudにおける権限とは、特定のリソースに対して行うことのできる一つの操作です。
具体的には「Cloud Storageに対してWriteできる」というのが権限であり、「Cloud StorageについてWrite、Readなどすべての操作が行える」というものは権限とは言いません(後述するロールになります)。

すべての権限は互いに排他であり、一つの権限がアクセスできるリソースは一つのみに絞られます。

この細かな権限は、最小権限の原則を構成しやすくはなっているものの、多数のプリンシパルに対して膨大な数の権限を付与する必要があり、メンテナンスが十分にできないという問題点があります。

そこでロールという概念を導入します。

ロール

ロールは、複数の権限をまとめたセットです。Google Cloudでは権限を直接プリンシパルに付与することはできず、このロールをプリンシパルに付与することで権限を与えています。

例えばCloud Run Developerロールは画像のような権限のセットです。これらの権限を人の手でうまく管理できるかと言われると、ほとんどの場合は無理でしょう。ロールを使用することによって最小権限とマネジメントの容易さを実現しています。


https://cloud.google.com/iam/docs/understanding-roles#run.developer

ロールの種類

ロールには基本ロール、事前定義ロール、カスタムロールの三種類が存在します。

基本ロールはOwner, Editor, Viewerの3つがあります。逆に言うと3つしかありません。リソースごとに細かな権限の設定が全くできていない基本ロールは、現在非推奨となっています。

事前定義ロールは先程例にあげたCloud Run Developerロールのように、リソースごとに適切な権限を割り当てたロールです。プリンシパルには基本的にこの事前定義ロールを割り当てます。

カスタムロールは自分で権限を割り当てたロールです。事前定義ロールでは最小権限を実現できない場合に使用します。

ロールの決め方

まず必要となる権限を探します。実際に操作を行ってみて、エラー文から足りない権限を特定しても良いと思います。
必要な権限を以下のページで検索し、該当のロールから適切そうなものを探すことができます

https://cloud.google.com/iam/docs/permissions-reference

ポリシー

プリンシパルとロールを結びつけるのがポリシーです。
ポリシーは以下のような構造になっています。

{
  "bindings": [
    {
      "role": "roles/storage.objectAdmin",
      "members": [
        "user:ali@example.com",
        "serviceAccount:my-other-app@appspot.gserviceaccount.com",
        "group:admins@example.com",
        "domain:google.com"
      ]
    },
    {
      "role": "roles/storage.objectViewer",
      "members": [
        "user:maria@example.com"
      ]
    }
  ]
}

複数存在するロールに対して複数のプリンシパルを割り当てる、いわば中間テーブルのような構造をしています。
ポリシーをプリンシパルとロールから分離することでより権限を管理しやすくなっていると思います。

チェック

以下の質問に対して自分なりに答えることで理解を深めましょう !

  • IAMとは何ですか ?
  • ロールという概念が導入されたのはなぜですか ?
  • プリンシパルに付与するロールはどのように決定しますか ?

Workload Identityを理解する

Workload Identityは、外部からGoogle Cloud リソースにアクセスする際のセキュリティリスクを低減する目的で提供されています。しかしその必要性を理解するためにははWorkload Identityがない場合と比較する必要があります。

Workload Identityの必要性

GitHub ActionsからGoogle Cloudを操作する状況を考えます。

外部からリソースを操作する場合、プリンシパルとしてサービスアカウントを使用します。このサービスアカウントには適切な権限が付与されているものとします。
GtHub Actionsがサービスアカウントを利用してリソースにアクセスをするには、サービスアカウントキーを発行する必要があります。
GitHub Actionsはサービスアカウント、サービスアカウントキーを使って無事にリソースにアクセスできました。
しかしこの発行したサービスアカウントキーには、常に漏洩リスクがついて回ります。
サービスアカウントとサービスアカウントキーが漏洩してしまった場合、外部から悪意のある攻撃を受ける覚悟をしなければいけません。漏洩が発覚するのは往々にして攻撃があってからではないでしょうか。

このようなリスクを回避するために使われるのがWorkload Identityです。

Workload Identityの概要

Workload Identityは、OIDC(OpenID Connect)を用いて期限付きのトークンを発行することで、セキュアに認証と認可の両方を行い、外部IDに対して任意のサービスアカウントになりすますことができるロールを付与する仕組みです。

Workload Identity プール

Workload Identityは外部IDを管理しているエンティティです。
dev, stg, prodなど環境が分かれている場合は、外部IDに対してより細かな権限制御を行うために複数のプールを作成することが推奨されています。

https://cloud.google.com/iam/docs/workload-identity-federation?hl=ja#pools

Workload Identity プール プロバイダ

IAMにおけるポリシーのように、外部IDとGoogle Cloudの関係を持っています。プロバイダの責務は、GitHub Actionsからのリクエストに対して情報を含んだトークンを発行することです。このトークンには様々な属性を指定でき、その属性をもとに「特定のリポジトリ以外からのアクセスは拒否する」といった設定も可能です。

サービスアカウントの権限借用

先述したトークンをGoogle Cloudが検証し、正しいことが確認されれば外部IDに対してGitHub Actionsが指定したサービスアカウントになりすませるロールが付与されます。

この権限借用によって、サービスアカウントキーを発行することなくサービスアカウントのロールを活用してリソースにアクセスすることができます。

GitHub Actionsの例

以下のGitHub Actionsのサンプルをもとに解説します。
https://github.com/google-github-actions/example-workflows/blob/main/workflows/deploy-cloudrun/cloudrun-docker.yml

トークンの取得

Authアクションを使用することで、OIDCトークンを取得できます。このときid-tokenのpermissionを許可することで今後のアクションにおいてトークンを参照できます。

https://github.com/google-github-actions/example-workflows/blob/f601e097144431f49ab9abb1f8a46e7f4e6a5e5c/workflows/deploy-cloudrun/cloudrun-docker.yml#L65-L67

AuthアクションではWorkload Identityプロバイダと、権限を借用したいサービスアカウントの情報が入っています。

https://github.com/google-github-actions/example-workflows/blob/f601e097144431f49ab9abb1f8a46e7f4e6a5e5c/workflows/deploy-cloudrun/cloudrun-docker.yml#L74-L80

Docker認証、push

アクセストークンを使って、Artifact Registryにimageをpushしています。トークンによってサービスアカウントが指定されているので、サービスアカウントはArtifact Registryに対するWrite権限を持っている必要があります。

https://github.com/google-github-actions/example-workflows/blob/f601e097144431f49ab9abb1f8a46e7f4e6a5e5c/workflows/deploy-cloudrun/cloudrun-docker.yml#L93-L99

https://github.com/google-github-actions/example-workflows/blob/f601e097144431f49ab9abb1f8a46e7f4e6a5e5c/workflows/deploy-cloudrun/cloudrun-docker.yml#L110-L113

Cloud Runにデプロイ

GoogleのActinosではcore.getIDToken()というメソッドによって、Authアクションによって書き込まれたトークンを取得しています。
サービスアカウントはCloud Runに対する十分な権限と、Artifact Registryに対するRead権限を持っている必要があります。

https://github.com/google-github-actions/example-workflows/blob/f601e097144431f49ab9abb1f8a46e7f4e6a5e5c/workflows/deploy-cloudrun/cloudrun-docker.yml#L117-L124

最後に

この記事を書いたことによってGoogle Cloud周りの権限に対する理解が十分に深まったと思います。いつかこの記事を自分で見返しても参考になるように書いたつもりです。お読みいただきありがとうございました。

参考

https://cloud.google.com/iam/docs/overview?hl=ja
https://cloud.google.com/iam/docs/workload-identity-federation?hl=ja
https://cloud.google.com/blog/ja/products/devops-sre/deploy-to-cloud-run-with-github-actions
https://christina04.hatenablog.com/entry/workload-identity-federation
https://zenn.dev/cloud_ace/articles/7fe428ac4f25c8
https://zenn.dev/cybozu_ept/articles/c241f28b4f32ec

Discussion