👻

一番わかりやすいGoogleCloud認証認可(IAM)入門

に公開

前置き

クラウドで一番難しいのはセキュリティ周りだと思います。
最近ようやくGoogleCloudの認証認可まわり(IAM)を理解してきたので、後から学ぶ皆さんのためにイラストを豊富に使って説明したいと思います。
これを読めば、なんとなくIAM理解できる状態になっていると嬉しいです。

なお、知識が間違っている可能性があります。その場合は指摘していただけるとありがたいです😄

プリンシパル(人っぽいなにか)がリソースを操作する

まず最初に大事なメンタルモデルが「プリンシパルがリソースを操作する」です。プリンシパルとは人っぽいなにかです。

プリンシパル(人っぽいなにか)がリソースを操作する

GoogleCloudではリソースを操作するのは、ユーザーだけではありません。そのためそれらを抽象化してプリンシパルと呼んでいます。

リソースを操作する主体の例

  • Googleアカウント
  • Googleグループ
  • サービスアカウント(サーバー系リソースに設定する仮想ユーザー的なもの)

なぜプリンシパルという概念が存在するかというと認可における「誰が(who)どのリソースに対して(what)何ができるか(do)」の「誰が」を定義するためです。また認証における「私は誰?」を定義することもできます。

学習を進めていると権限借用などの難しい概念が出てきたりしますが、「プリンシパルがリソースを操作する」というメンタルモデルを最初に意識していると比較的習得しやすいと思います。

まずは、プリンシパルという人っぽい何かがリソースを操作するというイメージが大事です。

プリンシパルの種類

プリンシパルは大きく2つに分類できます。

プリンシパルの種類

プリンシパルは大きく「人」と「ワークロード」の2つに分類できます。皆さんがイメージのつきやすいGoogleアカウントや、サーバー上でユーザーの代わりをするサービスアカウントなどです。他にも外部のIDプロバイダと連携するためのWorkforce Identityや外部のCI/CDと連携するためのWorkload Identity(forceとloadの違いに注意)などがありますが、これらは必要になったら調べてみてください。

  • Googleアカウント
  • Googleグループ
  • Workforce Identity

ワークロード

  • サービスアカウント
  • Workload Identity

ここでは最低限、Googleアカウントとサービスアカウントを抽象化してプリンシパルと呼んでいるんだなということを理解してください。

より詳しく知りたい方はGoogleCloudのドキュメントをご覧ください。

GoogleCloudにおける認可の仕組み

では、GoogleCloudではどのように「誰が(who)どのリソースに対して(what)何ができるか(do)」を定義しているのでしょうか?

GoogleCloudでは、「許可ポリシー」 をリソースに定義することでこれを実現しています。

認可の仕組み

とあるプリンシパル(例えば山田)がそのリソースを取得しようとしている場合、許可ポリシーでその操作が許可されていれば、山田はそのリソースを取得することができます。許可ポリシーに書かれていなければ却下されます(基本ホワイトリスト)。

ここで重要なのは、山田が直接権限を保持しているわけではなく、リソース側が許可リスト(許可ポリシー)を持っているというイメージです。

ところでリソースってなに?

今まで特にリソースについて言及せずに使ってきましたが、GoogleCloudにおいてリソースという言葉が指す対象は多岐にわたります。しかし、次のリソース階層構造を覚えていれば理解しやすいはずです。
リソースの階層構造

リソースは上から以下のような階層構造を持ちます。

  • Organization
  • Folders
  • Projects
  • Resources

OrganizationはGoogleCloudでアカウントを作ったときの主体です。会社単位で作成することが多いと思います。
Foldersではネストが許されます。ここでチーム構造や部署構造やプロダクトといった概念を表現できます。
ProjectsはGoogleCloudでサーバーやネットワークを直接置く名前空間単位です。主にテスト環境や本番環境など環境ごとに作ると良いでしょう。
ResourcesはCloudSQLやCloudStorageなどを指します。勘違いしてはいけないのは、リソースという言葉を使うときに最下層のResourceだけではなく上位のOrganization``Folders``Projectsも含まれることです。

なぜ、このような階層構造を採用しているかというと、階層構造を採用することで、アクセス制御を継承することができるためです。例えばあるプロジェクトで権限を設定すれば、プロジェクト配下のすべてのリソースに対して有効になります。

後述する許可ポリシーをリソースに設定するときは、今自分が設定しているリソースはどのリソースなのか意識しましょう。

許可ポリシーとは?

許可ポリシーとはリソースに設定された「誰が(who)このリソースに対して何ができるか(do)」を定義するものです。

許可ポリシーとは?

「プリンシパルとロール」をセットにしたもの(バインディングと呼ぶ)を配列として持っています。

jsonで表現するとこんな感じ。

許可ポリシー
[
  {
     principals: ['山田','近藤'],
     role: '閲覧'
  },
  {
    principals: ['佐藤'],
    role: '管理'
  }
]

ロールとはなんでしょうか?実はGoogleCloudはリソース名.getリソース名.listといった権限を直接プリンシパルに設定できず、必ずロールを介して設定しなければいけないという制約があります。

そのため、権限を設定するときはGoogleCloudが事前に用意したロールか、自分で作成したカスタムロールを利用することになります。

サーバー系リソースから他のリソースにアクセスしたい

ここから実践的な話に入ります。

最初にプリンシパルがリソースを操作するという話をしました。
再掲:プリンシパル(人っぽいなにか)がリソースを操作する

では、サーバー系リソース(例えばCloudRunやGAEなど)内のアプリケーションからリソースにアクセスするにはどうしたらよいのでしょうか?サーバー系リソースはプリンシパルではありませんので、リソースにアクセスできないはずです。

サーバー系リソース

ここで利用するのがサービスアカウントです。サーバー系リソースにサービスアカウントを設定することで、アプリケーションがプリンシパルとして振る舞います。

サーバー系リソースにサービスアカウントを関連付ける

ところで、サービスアカウントをリソースに設定することを、公式に「関連付ける」もしくは「接続する」と呼びます。今後はこの言葉を使って行きたいと思います。

サービスアカウントを関連付けることで、サーバー系リソースからリソースにアクセスすることが可能になりました。

さらにこのサーバー系リソースを実行するには?

では、このサーバー系リソースを実行するにはどうしたらよいでしょうか?頭がこんがらがってきましたでしょうか笑?。サーバー系リソースはリソースなので勝手に動いたりしません。大事な話なのでもう少し辛抱してください。

サーバー系リソースもリソースなので、それを操作する主体はもちろんプリンシパルです。

サーバー系リソースを操作するプリンシパル

GoogleアカウントでログインしたあなたがGUIから操作したり、gcloudコマンドを使って実行したりしますね。もしくはサービスアカウントが関連付けられた他のサーバー系リソースからアクセスすることもありうると思います。

どうでしょうか?だんだんイメージがついてきたのではないかと思います。

ところでサーバー系リソースを実行するために必要な許可ポリシーは?

サーバー系リソースを実行するのに必要な許可ポリシーは何でしょうか?しばらくGoogleCloudを扱った事がある人であれば、思い当たるかも?

サーバー系リソースを実行するために必要な許可ポリシーは?

答え

actAs権限をもったiam.serviceAccoutnUserロールが必要になります。

サーバー系リソースを実行するために必要な許可ポリシーは?答え

説明してませんでしたが、このロール、実はサービスアカウントの許可ポリシーで設定します。プリンシパルであるサービスアカウントに許可ポリシーを設定する、というのは意味がわからないかもしれません。実はサービスアカウントはプリンシパルであると同時にリソースでもあります。なので、許可ポリシーを持つことができるのです。

サービスアカウトに許可ポリシーを設定するユースケースはそこまで多くありません。上記の様にサーバー系リソースを実行するときや、後述するサービスアカウトを借用するときぐらいです。

外の世界からGoogleCloud上のリソースにアクセスするには?

ここまでの話はGoogleCloudに閉じた世界の話でした。しかし、現実にはそれだけでは済まないユースケースがあると思います。

  • ローカルの開発PCからGoogleCloud上のリソースにアクセスしたい
  • GitHub Actionsなど外部のCI/CDパイプラインからGoogleCloud上のリソースにアクセスしたい

外の世界からGoogleCloud上のリソースにアクセスするには?

どうすればよいでしょうか?外の世界なのでGoogleCloud上でそうしたようにサーバーにサービスアカウントを関連付けることはできません。

おおよそ予想はついているかもしれませんね。なんとかしてサーバー上にプリンシパルを憑依させればよいのです(憑依という言葉はわかりやすさのために使っているが正式な技術用語ではない)。

憑依させる

憑依させ方いろいろ

憑依させ方は複数あります。ユースケースに応じて選択しましょう!
ここでは深く踏み込むことはしませんが、主なユースケースとキーワードだけでも覚えてください。

  • ローカルのPCにシークレットキーをダウンロードせずにGoogleCloudリソースにアクセスしたい場合はADCがおすすめ。
  • GitHub ActionsなどCI/CD環境からGoogleCloudリソースにアクセスしたい場合はWorkload Identityがおすすめ
  • それ意外でどうしようもないときはローカルにシークレットキーを落として利用する

3番目以外の方法は、権限借用と呼ばれています。借用するサービスアカウントの許可ポリシーにroles/iam.serviceAccountTokenCreatorロールを設定する必要があります。

憑依させ方いろいろ

それぞれのメリデメ

それぞれのメリデメ

番外編: 具体的にどうやってアプリケーションのプログラムからリソースに対してクレデンシャル情報を渡しているの?

基本的に、Googleクライアントライブラリが裏側でいろいろやっています。Googleクライアントがリソースに対するリクエストに自動的にトークンをつけてくれることで、自分でトークンを取得しなくてもよいわけです。

クレデンシャルを渡す仕組み

Googleクライアントライブラリを使わない場合は、ここらへんを自分で1から実装する必要があります。

TRAPE(トラピ)

Discussion