中規模プロジェクトでの GCP権限管理(アクセス制御)ベストプラクティス

GCP(Google Cloud Platform)の開発・運用者へ付与する権限の管理について、現状のベストプラクティスを考えてみました。
※Googleが推奨する権限管理の形とは異なる部分があります。あくまで個人の考えたベストプラクティスですので、ご了承下さい。

# 目次
* [はじめに](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)
   * [なぜ権限管理が必要なのか](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%81%AA%E3%81%9C%E6%A8%A9%E9%99%90%E7%AE%A1%E7%90%86%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B)
   * [どうしたいのか](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%81%A9%E3%81%86%E3%81%97%E3%81%9F%E3%81%84%E3%81%AE%E3%81%8B)
* [GCPの権限管理](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#gcp%E3%81%AE%E6%A8%A9%E9%99%90%E7%AE%A1%E7%90%86)
   * [アクセスする主体と役割の管理方法](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%E4%B8%BB%E4%BD%93%E3%81%A8%E5%BD%B9%E5%89%B2%E3%81%AE%E7%AE%A1%E7%90%86%E6%96%B9%E6%B3%95)
   * [アクセス対象と権限の管理方法](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%AF%BE%E8%B1%A1%E3%81%A8%E6%A8%A9%E9%99%90%E3%81%AE%E7%AE%A1%E7%90%86%E6%96%B9%E6%B3%95)
   * [GCP権限周りの困りポイント・注意すべきポイント](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#gcp%E6%A8%A9%E9%99%90%E5%91%A8%E3%82%8A%E3%81%AE%E5%9B%B0%E3%82%8A%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E6%B3%A8%E6%84%8F%E3%81%99%E3%81%B9%E3%81%8D%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88)
* [こんな運用もあり](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%81%93%E3%82%93%E3%81%AA%E9%81%8B%E7%94%A8%E3%82%82%E3%81%82%E3%82%8A)
* [現状のベストプラクティス](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E7%8F%BE%E7%8A%B6%E3%81%AE%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9)　**←時間のない人はこちら**
  * [コード化して管理する](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%82%B3%E3%83%BC%E3%83%89%E5%8C%96%E3%81%97%E3%81%A6%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B)
  * [運用してみて良かったこと・課題と今後](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E9%81%8B%E7%94%A8%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6%E8%89%AF%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E8%AA%B2%E9%A1%8C%E3%81%A8%E4%BB%8A%E5%BE%8C)
* [おわりに](https://qiita.com/kusuwada/items/f2acb7288070e0c0e724#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB)

# はじめに
GCPの権限管理(IAM)周りについての基礎知識はこちら。

* [Cloud IAM 概念](https://cloud.google.com/iam/docs/concepts)  
* [Google Cloud Platform(GCP)のCloud IAM](https://qiita.com/NagaokaKenichi/items/02e723511d244c82bd82)
  * Qiita記事, GSuiteやCloudIdentityにも言及

ここらへんの知識はある程度あることを前提とした記事になっています。
Googleから発信されているベストプラクティス的な記事は以下を参照。(古い記事もあるので注意)

* [IAM の安全な使用](https://cloud.google.com/iam/docs/using-iam-securely)
* [IAM best practice guides available now (2016/3/29)](https://cloudplatform.googleblog.com/2016/03/IAM-best-practice-guides-available-now.html)
* [Snapchat shares security best practices for running on GCP (GCP Next 2016の発表内容)](https://cloudplatform.googleblog.com/2016/03/Snapchat-shares-security-best-practices-for-running-on-GCP-practices.html)
* [エンタープライズ企業のベスト プラクティス #プロジェクトとアクセス](https://cloud.google.com/docs/enterprise/best-practices-for-enterprise-organizations?hl=ja#projects-and-access)

※今回のスコープは人に紐づく権限管理のみとし、システムが動作するための権限(サービスアカウント)は対象外とします。
また、GCP上で開発・運用するプロダクト(サービス)の権限管理・アクセス管理も対象外とします。

## なぜ権限管理が必要なのか
やれっていう風潮だし、会社もそう言っているし・・・だけではなく、権限管理をしていない場合の実影響を考えてみます。

**一般的に**

* サービスを商用として運用している場合、システムに影響のあるオペレーションが誰でもできてしまうと、プロジェクトに参画したての初心者がサービスを止めてしまったり・顧客のデータを消してしまったり、ということが起こり得る
* 普段権限を持っている偉い人ほど、たまに何か確認したりオペレーションしようとすると、操作に慣れておらず「うっかりやらかした！」ということも起こりがち
* 顧客データを扱うサービスだと特に、誰がどの顧客のデータを閲覧できるかを細かく制御する必要がある
  * 例えば写真管理サービスでGCSに集めた、顧客のプライベートな写真や BQ上に保管されたコメントログなどが、開発者が居室から簡単にアクセスして見れる,DLできるというのは問題

**現在のGCPだと特に・・・**

* WebUI怖い
  * GCPのUIは大変危険で、ボケっとカーソルを動かしているだけのつもりでも誤って設定を変更してしまっていたりする。(WebConsole上で設定変更系のオペレーションをする際に、確認画面が出てこないことが多い)  
  なので、設定がどうなっているか確認したいだけなのに、最新の注意を払ってマウスが期待通りの動きしかしていないことを祈りつつ、WebConsoleを触ることになる。  
  これが、通常は設定が変更できないような権限しかついていないと、安心してポチポチ設定を確認できる。
* プロジェクト間でログインアカウントが共通
  * 基本的に自分のgoogleアカウント1つで、全てのプロジェクトに参加する。  
  権限管理のために各プロジェクトにIAMアカウントを作成するが、これらは原則一つの(自分の)googleアカウントに紐付ける。WebConsole上で各プロジェクトへログインするには、ブラウザ上でgoogleアカウントにログインすれば良い。  
  このため、ブラウザで開発環境のWebConsoleにログインした状態で商用環境のWebConsoleを開くと、既にログイン済みなのである。  
  この思想は、複数プロジェクトを日常的に使っているととても便利（いちいちプロジェクトを切り替える時に再ログインが必要にならない）が、  
  違うプロジェクトのタブを沢山開きっぱなしで作業しようものなら、どれがどの環境か常に意識するのは難しい。オペレーションミスの予感。
* 強制ログアウト時間が無い
  * 上の続きだが、セッションタイムアウトみたいなのがWebConsole全体としては無く(CloudShellにはある)、ブラウザのcookieが切れるまで自動でログインしっぱなし。気づいたら商用環境の画面を編集可能な状態で開きっぱなしで放置してたor別の作業をしていた、ああ怖い、なんてことになりがち。

他にも挙げれば沢山出てくるだろうけど、ぱっと思いつくだけでもこれだけありました。

## どうしたいのか
基本的に **必要な人が、必要なときにのみ、(ある程度)必要最小の権限を持つ** ようになっていれば良い。これは、セキュリティ系の用語だと **最小権限(特権)の原則**, **特権処理の局所化**, **職務分離・責務分離の原則** にあたります。  
まず、どういった種類のオペレーションがあり、どれくらいの種類の権限が必要かを把握します。細かい事を言い出すと、人ごとに立場やオペレーションが違うので人ごとに付けなければなりませんが、運用コストがかかること・管理しきれず結局ルールがワークしないほうが問題なので、ある程度グルーピングして考えます。  
例を下記に。

|役割の種類|権限|備考|
|:---:|:---:|:---:|
|owner|プロジェクトのオーナー|各プロジェクトに必ず一人は必要。すべての権限を持つ|
|pi|顧客の個人情報(PI)にアクセスできる|障害時のデータ復旧作業などができる|
|operator|システム管理者|システムの更新・障害の調査などができる|
|monitor|システム監視者|監視用の権限。システムリソースやログなどを閲覧できる|
|developer|開発者|develop環境を自由に使える|

こんな感じでグルーピングして、IAM機能などでそれぞれに必要最小限の権限を付与するとします。
これで、**必要な人が、(ある程度)必要最小の権限を持つ** までは実現できそうです。
ただし、**必要なときにのみ** というのがまだ抜けています。
なんらかの方法でこの役割を切り替えて行く必要がありそうです。`帽子を変える`とよく表現されるやつですね。

ちなみにAWSだと、個人のアカウントが`User`, 役割の種類が`Role`, それに与える権限(アクセス許可を定義したもの)が`Policy`で、UserはRoleを**スイッチ**することで切り替えることができます。スイッチできる権限も同様に管理できるので、このメンバーは`pi`までスイッチできるけどこのメンバーは`monitor`までしかできない、みたいな制御もできます。



# GCPの権限管理

基本概念や他の方のわかりやすい導入記事は「はじめに」をご参照下さい。
AWSとはかなり違うので、同じ`IAM`でも概念・できることは結構違います。
**誰が**,**何をする時に(どういう役割で)**,**何に**,**どういった内容の** 操作ができるか、という下記4つの視点でまとめてみます。
参考：[Cloud IAM 概要](https://cloud.google.com/iam/docs/overview)

* **誰が** : アクセスする主体(Subject)
  * xxxさんが、というレベルでのアクセス主体
  * Auditの観点から、ユーザー一人ひとりにまで分解できることが必要
* **何をする時に(どういう役割で)** : 役割(Role)
  * 日々の監視(運用者)・システム更新(システム管理者)など
  * 一人で複数の役割を担う・使い分けることも考慮する
* **何に** : アクセス対象(Resource)
  * Projectのリソース全部なのか、"BigQuery"というサービス全体なのか、更にその中の特定の"dataset"なのか
  * AWSと比べると"特定の"というのが指定できるサービスが少ない
* **どういった内容の** : アクセス権限(Permission/Operation)
  * Read/Write/Admin 的な「何ができるか」の設定
  * Role種別の拡充により、より細かい設定ができるようになってきている
  
アクセスする主体と役割の管理方法を`アクセスする主体と役割の管理方法`で、役割とアクセス対象・アクセス権限の管理についてを`アクセス対象と権限の管理方法`で書きます。

## アクセスする主体と役割の管理方法
アクセスする主体は、下記のタイプのものが登録できます。
詳細はこちらをご参照下さい。[Cloud IAM 概要 > ID に関する概念](https://cloud.google.com/iam/docs/overview)
GCPとしてはメンバーと表現するようです。

|メンバータイプ|概要|
|:---|:---|
|Google アカウント|GCPを利用するためには、まずGoogleアカウントの取得が必要。基本的に個人に紐づくアカウント。|
|サービス アカウント|個々のエンドユーザーではなく、利用するアプリケーションに属するアカウント。GCP project内で作成。|
|Google グループ|Googleアカウントをグルーピングする概念。GCP機能とは別管理になる。|
|G Suite ドメイン|1つの組織内のすべてのメンバーの仮想グループ。詳細は[こちら](https://gsuite.google.com/)。|
|CloudIdentity ドメイン|1つの組織内のすべてのメンバーの仮想グループ。G Suite機能のGCP特化バージョン。無料で使用できるがG Suiteの機能は使用できない。|

以下、どのようにアクセスする主体と役割を管理すべきか検討した内容です。
Auditの観点からも、アクセスする主体は各自のGoogleアカウントで管理し、役割の管理を下記の機能から選択することにします。

* サービスアカウント
* GoogleGroup
* G Suite
* CloudIdentity

役割の管理方法、各ユーザーの役割の変更方法について検討した内容をまとめておきます。

|役割の管理手段|方法|検討・検証結果|
|:---|:---|:---|
|サービスアカウント|役割ごとにサービスアカウントを作成し、必要なときのみユーザーはそのサービスアカウントを使って作業をする。|ログがユーザーではなくサービスアカウントとして残るため、実際に誰が作業したのか特定できない。Auditの観点から難点あり。|
|Googleグループ|役割ごとにGoogleGroupを作成し、必要なときのみ権限の強いGroupに所属する。|ログはユーザーとして残るので◎。GoogleGroupにはownerの権限は付与できないため、ownerのみ別のやり方で管理する必要がある。|
|GSuite|※お金の関係で試せず|今回は検証の対象外とする|
|CloudIdentity|※諸事情によりDomainを新たに取得する必要があったので試せず|今回は検証の対象外とする。ただし、今後検証してレポートしたい|

## アクセス対象と権限の管理方法
GCPでは下記の権限管理方法があります。

1. Project内の各サービス単位での権限を管理する`Project IAM`
2. GCS(CloudStorage)のbucketやobject単位で設定できるアクセス制御
3. BQ(BigQuery)のdataset単位で設定できるアクセス制御

基本的に、サービス単位(AppEngine/StackDriverなど)での権限管理と、GCSとBQのみ個々のbucketやdataset単位でアクセス権の管理ができます。
それぞれの特徴はこんな感じです。詳細は次の項で順次ふれます。

|権限管理方法|権限管理の単位|設定できる内容|
|:-----------------|:-----------|:----|
|Project IAM|Project     |owner/editor/viewer の3種類|
|GCS(CloudStorage) IAM|Bucket/Object|Primitive Role / PreDefined Roleをbucketやobject単位で設定|
|GCS(CloudStorage) ACL|Bucket/Object|Primitive Roleをbucketやobject単位で設定|
|BQ(BigQuery) ACL|Dataset|Primitive Roleをdataset単位で設定|

また、Project IAMについては下記のRole種別が用意されており、歴史的に上から順番にリリースされています。どんどん細かい設定ができるようになっていますが、まだ最後のCustom RoleはBeta提供だったりするので利用には注意が必要です。

|Role種別|権限管理の単位|設定できる内容|
|:-----------------|:-----------|:----|
|Primitive Role    |Project     |owner/editor/viewer の3種類|
|PreDefined Role   |Service     |サービス毎にいくつか(4~7種類程度)用意された権限|
|Custom Role (beta)|Service     |サービス毎にいくつか(10~20種類程度)用意された権限を自由に組み合わせてポリシーを作成|

<h3>Project IAM</h3>
project内の個々のサービス(AppEngine/StackDriverなど)について、どういう権限を与えるかを管理します。
つい一年前くらいまでは、全サービス共通の**Primitive Role**(Owner/Editor/Viewer)の設定しかできませんでしたが、
**Predefined Role** を使用することで、サービスごとにPrimitive Roleより細かい権限を設定することができるようになっています。
例えば運用者に対して、「AppEngineはdeployできる権限を付与したいが、中で動いているコードは見てほしくない」といった制御が可能です。
更に細かくRoleを定義したい場合は、まだBeta版ではありますが[**Custom Role**](https://cloud.google.com/iam/docs/understanding-custom-roles)の機能を使うことができます。

<h3>GCS(CloudStorage)のアクセス制御</h3>
上述の「このbucketにはアクセスできるけど、こっちの顧客データを含むbucketは中身を見られないようにしたい」と言ったニーズに応えられるのは、こちらのbucket/objectごとの権限管理です。
ACLによる管理とIAMによる管理ができるようです。これについて、わかりやすい記事を見つけたのでこちらをご参照下さい。
[Google Cloud Storage (gcs) IAM対応でACL設定がより簡単に](http://iga-ninja.hatenablog.com/entry/2017/10/23/195630)  
上記記事によると、多くの場合では今後GCSのBucket/Object単位で権限を設定したいときは、ACLではなくIAMでやったほうが良さそうです。
何よりWebUIでACLによる設定をいじるのが非対応になったというのは大きいですね。
ちなみに個人的には管理が煩雑になりそうなので、原則object単位ではなくbucket単位での権限設定が良いかと思います。

<h3>BQ(BigQuery)のアクセス制御</h3>
こちらもGCS同様、「このdatasetにはアクセスできるけど、こっちの顧客データを含むdatasetは中身を見られないようにしたい」的なニーズに答えられます。
BQのdataset単位でのアクセス制御については、[こちら](https://cloud.google.com/bigquery/docs/access-control)の「データセットに対する基本の役割」で語られています。
BQのdatasetのほうはIAM対応していないようで、ACLでのみの設定ができ、`READER`, `WRITER`,`OWNER`の中から権限を選択することになります。
ユーザーやサービスアカウント・グループに対して権限を付与できます。

## GCP権限周りの困りポイント・注意すべきポイント
<h3>Deny設定できない</h3>
AWSでは設定できる、**Deny** の機能がありません。
このためBigQueryを例にとると、「基本全てのdatasetは閲覧可能だけど、このdatasetだけは見れないようにしたい」というのを実現しようとすると、少々面倒です。
ここでは前述の`pi`以上には見せてよいが、`operator`以下には見せないようにしたいdatasetがあると仮定して`operator`に対するアクセス制御の実現方法を考えてみます。`operator`はそれ以外のdatasetは基本的に触れるようにしたいとします。
1. `operator`にProjectRoleレベルではBQ datasetへの参照権限(`PreDefined Role`の`bigquery.data*,bigquery.admin`)を付与、アクセスさせたくないdatasetから個別にoperatorの権限を削除する
2. `operator`以下にはProjectRoleレベルではBQ datasetへの参照権限を与えず、許可すべきdatasetにのみ個別に権限を付与する

どちらでもできそうに見えるのですが、1. の方法はとれません。**BQ(BigQuery)の権限管理** のところで触れたように、BigQueryのdataset別アクセス権限管理はACLしか対応していないので、IAMによって定義された`operator`への参照権限の定義は、dataset側のアクセス制御からは確認できないのです。(権限を削除もできない) datasetに対するアクセス権限が2つの方法で管理(ProjectIAMとACL)されていて、最終的に誰がアクセスできるかはIAMとACL, 両方を確認しないとわかりません。何をどっちで定義するか、project内でポリシーを決めておかないとカオスの予感です。

<h3>Project Viewerは結構強い</h3>
とりあえずprojectに参画したての人や、他部署の人には`Project Viewer`権限を付けておこう！というのはやりがちだと思うのですが、実はViewerとは言え結構できちゃいます。
GCS上のファイルのコピー・DLが行えるため、商用環境のデータをDL、他のprojectに横流し、など結構グレーと言うかアウトです。
Primitive Roleだけが提供されていた時期だと、これが一番弱い権限だったので「とりあえずViewer」というのはまだまだやられているのではないでしょうか。
今はPreDefined Roleに`Project Browser`という、本当に弱いroleができているので、defaultではこれをつけるようにするのがおすすめです。

<h3>Primitive RoleをGCSやBQから勝手に消さないほうが良い</h3>
GCPのサービスを使用すると、自動でサービス用のサービスアカウントが作成され、サービスはそのサービスアカウントの権限で動作します。そのアカウントに付与されるroleは後から変更できるますが、参照されるリソース側(例えばBQのdataset)の方で基本のroleを消してしまうと、サービスが権限エラーで動けなくなる事があります。
例：DataFlowを利用すると `service-{PROJECT_NUMBER}@dataflow-service-producer-prod.iam.gserviceaccount.com` というサービスアカウントが自動で作成され、DataFlowはこのサービスアカウントを使用して動作します。これが持つroleは `Cloud Dataflow サービスエージェント`となっているが、中でおそらく`Project Editor`などを持っており、DataflowがアクセスするBQのdatasetのpermissionから`Project Editor`を消してしまっているとDataflowがアクセスできず処理がErrorになる、ということがありました。



# こんな運用もあり
## 基本の役割 (Primitive Role) でやりきる
プロジェクト規模が小さかったり、商用環境がなかったり、お遊びプロジェクトだったりする場合はこれで十分かと思います。
またPreDefined Roleが出る前までは、この運用でやっているプロジェクトが多かったのではないでしょうか。
上記のような役割のグルーピングは不要で、`owner`,`editor`,`viewer`でまかないます。プロジェクト内のすべてのサービス・リソースに対してのアクセス権限レベルが設定されます。
この場合、基本`viewer`状態で、必要なときのみ`editor`または`owner`に昇格する(付け替える)運用で問題ありません。

ただし、editor, ownerになったら、人の権限も自由にいじれてしまうことや、viewerの状態では権限をさわれないので誰かに昇格させてもらう必要がある(=常に誰かがeditorかownerである必要がある、もしくはその権限だけ持ったユーザーを別途用意しておく)必要があります。
また、「注意すべきポイント」でも触れました、viewer結構権限あるよ！というのも注意が必要です。

何より「このbucketにはアクセスできるけど、こっちの顧客データを含むbucketは中身を見られないようにしたい」というような制御ができません。



# 現状のベストプラクティス
以上のことをまるっと踏まえて、自分が今ベストだと思う方法をご紹介します。
もちろん各自Googleアカウントには2段階認証の設定をしておいてくださいね。

## やりたいこと
**必要な人が、必要なときにのみ、(ある程度)必要最小の権限を持つ** ようにしたい

<h3>project前提</h3>
* projectメンバーを含め、10人以上がアクセスする
* メンバーの入れ替わりがそこそこある
* 商用環境あり
* 一人が複数のGCP projectにアクセスする(開発環境・接続試験環境などを含む)
* 開発運用チームだけでなく、サービスオーナー, 外部組織にもアクセス権限を付与する必要がある(顧客企業・パートナー企業など)
* 顧客のデータなど、気軽にアクセスするべきではないデータがCloudStorageやBigQueryに保管されている

<h3>要件</h3>
* **最小限の権限の原則**：必要な人が、必要なときにのみ、(ある程度)必要最小の権限を持つ
  * 普段の開発時には開発環境のみ強い権限を持ち、商用環境は監視に必要な権限のみ
  * 商用環境へのリリース時や障害調査のときのみ、商用環境用の強い権限を持つ
* **運用コスト**：権限の付替えには大きな手間を伴わないようにする
  * 「今からリリースするよ」というときに、必要最小な権限をぽちぽち付与するのは手間だしミスが起こりやすいので、予め用意してある「リリース用」権限をちゃちゃっと付与したい
* **運用コスト**：一人が複数個のアカウントを所有することは原則行わない
  * 管理が煩雑になるため
* **Audit**：なにか起こった時に「誰がなんの操作をしたか」が追えるようになっている
  * 共用アカウントは原則使わない、など

<h2>まずは絵を</h2>

<img src="https://qiita-image-store.s3.amazonaws.com/0/104518/b142f0c0-ff1e-134b-27a0-66e8f32c011b.png" width=80%>
※役割やリソース・権限は一部の例のみを記載しています。

全てのメンバーは、普段弱い権限のgroupのみに所属(ここではmonitorの帽子)しており、必要に応じて自分に与えられた帽子の中で役割を変えて作業を行います。
それぞれの役割がどういった権限を持つかは予め定義されており、帽子を変える=所属するGoogleGroupを変更/追加する だけですみます。(owner/iam managerは別のGoogleアカウントにログイン)
GCS・BQへのアクセス権限は、ProjectIAMではoperator以下のgroupに付与せず、それぞれ個別のbucket/datasetのiam/aclで管理します。
なぜこうなったか、それぞれの詳細などは次項より。

<h2>メンバーと役割の管理方法</h2>
* 基本的にGoogleGroupsを利用します。
* 下記Groupをプロジェクトごとに作成し、必要なときだけ特権Groupに参加します。
* これにより、メンバーが役割を"スイッチ"できること、メンバーごとに複雑な権限管理をしなくて良いこと、がメリットとしてあげられます。
※メンバーの入れ替えがあるときも楽です

|役割|管理方法|備考|権限の例|
|:---:|:---:|:---:|:---:|
|iam manager<br>(GoogleGroupのオーナー)|専用Googleアカウント※1|各メンバーに対して、役割を変更させる権限を持つアカウント。役割のアサインに責任を持つ人のみで共有し、役割の変更(Groupへの追加・削除)はこのアカウントで実施する。|(GCP IAMなし)|
|owner<br>(プロジェクトのオーナー)|専用Googleアカウント※2|プロジェクトリーダー,もしくはそれ相当の人でのみ共有するアカウント。普段は使用しない。|project owner|
|pi<br>(顧客の個人情報(PI)にアクセス)|GoogleGroup||project.browser,<br>storage.admin,<br>bigquery.admin|
|operator<br>(システム管理者)|GoogleGroup||project.browser,<br>appengine.appAdmin,<br>appengine.serviceAdmin,<br>custom.bigqueryList|
|monitor<br>(システム監視者)|GoogleGroup|普段はprojectメンバーはこのgroupにのみ属する。|project.browser,<br>appengine.appViewer,<br>custom.appengineMonitor|
|developer<br>(開発者)|GoogleGroup|開発用環境にのみ作成。比較的自由になんでもできる権限を付与する。|project.editor|
|その他、顧客企業やパートナー企業向けの役割|GoogleGroup|役割を分けるべき単位ごとにGroupを作成し、管理する。|適宜|

* ※1 GoogleGroupには常に誰か一人がownerとして所属している必要がある。これを個人アカウントにしてしまうと、例えばpiグループのオーナーであるメンバーは必然的に常にpiの権限を持ってしまう。これを防ぐため、個人のアカウントとは別のアカウント(この作業を行えるのが複数人の場合は共有アカウントになる)で管理する。
* ※2 ownerを個人のGoogleアカウントにしていない理由は、その人がオペミスや悪いことをしない可能性が0ではないためです。特にバリバリ開発・運用する人だった場合はシステムを良く触るので、その分ミスもしやすいです。("WebUI怖い" 参照)
こちらも、ownerとして作業できるのを複数人にしたい場合は共有アカウントになります。

<h3>具体的なシナリオに沿った手順</h3>
1. 各GoogleGroupの作成
  * iam manager 及び owner用のGoogleアカウントを作成します。
  * 各GoogleGroupは、iam managerのアカウントで作成しておきます。
    * この時、グループに参加できるのを`招待されたユーザーのみ`に設定します。また、トピックの表示や投稿権限がグループのメンバーに限定されていることを確認します。
  * 各GoogleGroupをプロジェクトIAMに登録し、適切な権限を設定します（次項参照）
  
2. チームメンバーのAさんが、商用環境にプロダクトをデプロイしたい場合
  * 普段Aさんはmonitor groupにいるので、このときoperatorになる必要があります
  * Aさんはiam managerであるチームメンバーのCさんに、作業内容とoperatorにしてほしい旨を申請します
  * Cさんは申請の内容が適切かを吟味した後、iam managerアカウントにログインし、Aさんをoperator groupに追加します
  * Aさんは作業を実施、完了後に自らoperator groupを脱退してCさんに報告、もしくはCさんが強制的にAさんをoperator groupから脱退させます

3. チームリーダーのBさんが、プロダクト用の鍵を発行したい場合
  * 普段Bさんもmonitor groupにいるので、この時ownerになる必要があります
  * Bさんはownerの共有アカウントでログインし、プロダクト用の鍵を発行します
  * 作業が終わったのでBさんはownerの共有アカウントからログアウトします

<h2>Project IAM</h2>
上記のように、権限管理をメンバーではなくGoogleGroupをベースに行いますので、ProjectのIAMに直接紐づくGoogleアカウントはownerのみとなります。
各役割のGoogleGroupに、PreDefined RoleないしCustom Roleを用いて必要最小な権限を付与していきます。
付与する権限の例は上の表をご参照下さい。

ポイントは、operator以下にはstorageやbigqueryのadmin権限を付与しないこと。
特にbigqueryはdataset毎に"deny(拒否)"の設定はできないため、基本project全体としてbigqueryには権限を付けず、許可するdatasetにのみ個別で権限を付与します。("BQ(BigQuery)のアクセス制御"や"Primitive RoleをGCSやBQから勝手に消さないほうが良い"参照)
次項でGCS,BQについての権限管理について考えます。

<h2>CloudStorage権限</h2>
※"GCS(CloudStorage)のアクセス制御"もご参照下さい。

上記の設定のProjectIAMでは、pi, owner など、なんでも見えて良い役割しか全bucket/objectへのアクセス権を持っていません。
そこで、他の役割がアクセスできるようにすべきbucket/objectについて、個別に権限を設定してやります。

CloudStorage側の権限設定では、bucketやobject毎にアクセス権限を制御できますが、objectごとの制御をしだすと管理が複雑になりすぎるため、ベストプラクティスとしてはbucket毎に管理をおすすめします。
また"GCS(CloudStorage)のアクセス制御"で触れたとおり、GCSのアクセス制御としてはACLとIAMが用意されていますが、原則としてIAMで統一して管理することをおすすめします。

|bucket|アクセス権(IAM)|メンバー|
|:---|:---|:---|
|user_contents|storage.admin|pi|
|deploy_resource|storage.admin|pi,operator|

※ primitive role (レガシーな権限)は省略しています

設計の段階で必要になるbucketについて、どんな情報が保管されて誰がアクセスするべきか、と言うのは明確になるはずなので、そこでついでに権限をどのgroupに付与するかを決めてしまうようにすれば、そこまで大きな手間ではないと思います。

<h2>BigQuery権限</h2>
※"BQ(BigQuery)のアクセス制御"もご参照下さい。

GCSと同じく、上記の設定のProjectIAMでは、pi, owner など、なんでも見えて良い役割しか全datasetへのアクセス権を持っていません。 そこで、他の役割がアクセスできるようにすべきdatasetについて、個別に権限を設定してやります。

|dataset|アクセス権(ACL)|メンバー|
|:---|:---|:---|
|user_contents|Can edit|pi|
|deploy_resource|Can edit|pi,operator|

ここの権限管理の仕組みやUIがCloudStorageとぜんぜん違うところも、GCPらしい。設計の段階で〜という下りはGCSと全く同じです。

## コード化して管理する
大きなプロジェクトになればなるほど、どの権限状態が正しいかの確認が難しくなってきます。特に"WebUI怖い"で触れた、マウスが勝手に設定変えちゃった！みたいなことが無意識のうちに起きると、何をどう戻せば良いかももはやわからないです。
また、設計情報という意味でも、権限は誰がどういうものを持っている、というのをコメント付きで見えるように管理したほうが良いです。エクセルなんかで管理するのも悪くはないと思いますが、コード化しておくと情報が陳腐化するのを防げたり、変更点のレビューがしやすいです。
幸い、GCPのIAMにもAPIが用意されており、[`gcloud projects set-iam-policy {project-id} {iam.yaml}`](https://cloud.google.com/sdk/gcloud/reference/projects/set-iam-policy)でProjectIAMを設定することができます。
また、GCS/BQのアクセス制御もそれぞれ[`gsutil iam set {bucket} {role}`](https://cloud.google.com/storage/docs/access-control/iam-gsutil) / [`bq update --source={iam.json} {dataset}`](https://cloud.google.com/bigquery/bq-command-line-tool)で設定することができ、なんとかコードで管理・ツールで変更を適用できそうです。
ただし`set-iam-policy`は、今回スコープ外とした、サービスアカウントの権限も全て対象となるため、例えば新しくサービスを使い始めたために自動でサービス用サービスアカウントが作成されている！なんて場合には、ツールで管理している設定と実環境の設定にずれが生じてしまい、自動で作成されたアカウントの設定をを常に取り込みながらコード管理をしていく必要があります。
GCPの「良きに計らって」くれる思想の良いところの裏返しです。

具体的なコード&ツールの話は別の機会に。

## 運用してみて良かったこと・課題と今後
<h3>良かったこと</h3>
* とりあえずViewer, とりあえずEditor, がなくなったので、監査のときなどに胸を張って「アクセスコントロールしています」と言えそう
* ずっとownerやeditorの状態でBQのdatasetを眺めたり、IAMの設定を確認したりすることがなくなった。(WebUIでうっかり設定変えちゃった！うっかり消しちゃった！のリスクが減った)
* 個人がオペレーションする時に毎回必要になった権限を積み上げ式で付与する方式だと、不要になった時に削除し忘れる&誰がどんな状態か管理しきれていなかったが、数個のGroupを行き来するだけだと管理が格段に楽になった
* プロジェクトが巨大化しており、運用者がメンバーを全て把握できていない状態(これは誰？状態)だったため、メンバーではなくGroupで管理することでどういう人が何ができるのかが明確になった
* 権限周りの設計書的なもの(コード)ができた

<h3>課題と今後</h3>
* GoogleGroupを使用しているが、誰がいつどのgroupに所属していたか、誰がいつ正体・脱退させたか、などの情報が取れない
* そもそも特権Groupに所属するメンバーは、常に監視されていなければいけない(特権Groupに所属しっぱなしのGroupがないかなど)が、GoogleGroupにそのような機能・公開APIは存在しない
* 特に顧客企業やパートナー企業向けの役割もGoogleGroupで管理するようにする場合、先方都合での人の追加・削除を先方で自由にやっていただけるというメリットは有るが、ログに出てくるのはユーザーのGoogleアカウントだけで、その時どのGroupに所属していたのかまではわからないため、トラッキングしにくくなる。
* CloudIdentity, GSuiteを使えば、もっと上記のGroupに関する課題は解決できそう、と中の人にもアドバイスいただいているので、次はこれを試してみてのベストプラクティスを検討したい



# おわりに
GCPは、色々細かいことを考えなくても良きに計らってくれるので、簡単にいろんなサービスが使えるのが良いところだと思います。反面、色々細かいところも自分たちで考えて設計・管理したい、となると、機能やツールが今ひとつ足りていないと感じます。
こういった面から、かっちりした企業や大規模なプロジェクトで利用するには、GCPの権限周りの機能は今ひとつ心もとないと感じてしまいます。
また、どうしてもAWSからの載せ替えプロジェクトだったり他でAWSを触っていたりすると、AWSと比較して痒いところに手が届かないと感じることが多いです。

GCPが今後、どういう方向にどれくらいのスピードで成長していくのかはGoogleが決めていくことですが、折角BigQueryやML系APIなど強力なサービスがあるので、権限管理・セキュリティ面も早く強化していって様々な企業・プロジェクトが心置きなく利用できるようになって欲しいです。  
ちょっと権限周りが気になるから、せっかく美味しいサービスがあるけどやめとこう、というのはもったいない。

GCPはプロダクトの更新・追加サイクルが早いので、この記事が陳腐化していると感じたらご連絡・コメントいただけますと幸いです。
また、この記事はGoogleが推奨する権限管理の形とは異なる部分があります。あくまで個人の考えたベストプラクティスですので、ご了承下さい。