Service Accountの権限でgcloudコマンドを実行する

#はじめに
Service Accountの権限でgcloudコマンドを実行してみます。
用途としては、普段の運用は参照権限が付与されたGoogle Accountを使用し、必要なときにSu -するようなイメージで、変更権限のあるService Accountの権限を使用して作業することのより、オペミスをすくなるすると言ったことが考えられます。

#前提知識
GCPの認可設定は、Google AccountやService AccountにIAM Roleを付与することで行われます。
この場合、Google AccountやService Accountは認証されるIdentityとなり、操作対象のリソースは、Project/Folder/OrganizationレベルのResourceを指定します。
Projectレベルを対象としてroles/storage.adminが付与された場合、IAM Conditionsでリソース名を指定した条件指定をしない場合、Projectに属するGCSリソースのすべての操作が可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/aa8db2a6-0296-f9e9-83de-b23558e17b45.png)

それぞれのリソースレベルでIAM Roleを付与するgcloudコマンドが準備されており、MEMBERとしてGoogle AccountやService Accountを指定可能です。

##Projectレベルを対象とした権限付与
https://cloud.google.com/sdk/gcloud/reference/projects/add-iam-policy-binding

```
gcloud projects add-iam-policy-binding PROJECT --member=MEMBER --role=ROLE
```

##Folderレベルを対象とした権限付与
https://cloud.google.com/sdk/gcloud/reference/alpha/resource-manager/folders/add-iam-policy-binding

```
gcloud resource-manager folders add-iam-policy-binding FOLDER --member=MEMBER --role=ROLE
```

##Organizationレベルを対象とした権限付与
https://cloud.google.com/sdk/gcloud/reference/organizations/add-iam-policy-binding

```
gcloud organizations add-iam-policy-binding ORGANIZATION --member=MEMBER --role=ROLE
```

これまでは、Service AccountをIdentityとして説明してきましたが、Service AccountはRosourceになることも出来ます。Service AccountをRosourceとして使うことが今回の「Service Accountの権限でgcloudコマンドを実行する」ということになります。

図にすると以下の様なイメージです。Service Accountは、Google Accountから見るとResourceとなり、ProjectレベルのResourceから見るとIdentityとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/06b2135d-a277-36a7-46fe-21ab858ecf73.png)

Google AccountをIdentity、Service AccountをResourceとした場合の権限付与するgcloudコマンドは以下になります。

```
gcloud iam service-accounts add-iam-policy-binding SERVICE_ACCOUNT --member=<Google Account> --role=ROLE
```

Google Accountは、Service Accountに対して、「Service Account User」ロールと「Service Account Token Creator」ロールを付与します。「Service Account Token Creator」は、テンポラリのアクセストークンを発行するための権限です。
また、「Service Usage Consumer」ロールをProjectに対して付与します。「roles/viewer」でもOKです。
正確には、「Service Usage Consumer」ロールに含まれれる「serviceusage.services.use」パーミッションが必要です。

#試してみる

Service Accountを作成します。

```
$ gcloud iam service-accounts create impersonate-sa
Created service account [impersonate-sa]
```

Projectレベルのリソースに対して、作成したService AccountにStorage Adminのロールを付与します。イメージ図の赤枠の認可設定です。

```
$ gcloud projects add-iam-policy-binding PROJECTID --member="serviceAccount:impersonate-sa@PROJECTID.iam.gserviceaccount.com" --role="roles/compute.admin"
```

Service Accountリソースに対して、Google Accountに「Service Account User」ロールと「Service Account Token Creator」ロールを付与します。イメージ図の青枠の認可設定です。

```
$ gcloud iam service-accounts add-iam-policy-binding impersonate-sa@PROJECTID.iam.gserviceaccount.com --member="user:USERNAME" --role="roles/iam.serviceAccountTokenCreator"
$ gcloud iam service-accounts add-iam-policy-binding impersonate-sa@PROJECTID.iam.gserviceaccount.com --member="user:USERNAME" --role="roles/iam.serviceAccountUser"
```

Projectレベルのリソースに対して、Google Accountに「Service Usage Consumer」ロールを付与します。イメージ図の緑枠の認可設定です

```
$ gcloud projects add-iam-policy-binding PROJECTID --member="user:USERNAME" --role="roles/serviceusage.serviceUsageConsumer"
```

以上で準備完了です。

Google Accountの権限でコマンド実行します。権限をもっていないのでエラーになります。

```
$ gcloud compute instances list
ERROR: (gcloud.compute.instances.list) Some requests did not succeed:
 - Required 'compute.zones.list' permission for 'projects/PROJECTID'
```

Service Accountの権限でコマンド実行します。インスタンスがリスト表示できました。

```
$ gcloud compute instances list --impersonate-service-account=impersonate-sa@PROJECTID.iam.gserviceaccount.com
WARNING: This command is using service account impersonation. All API calls will be executed as [impersonate-sa@PROJECTID.iam.gserviceaccount.com].
NAME        ZONE               MACHINE_TYPE               PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP  STATUS
instance    asia-northeast1-b  n1-standard-1                           192.168.0.4               TERMINATED
instance-2  asia-northeast1-b  n1-standard-1                           192.168.0.2               TERMINATED
instance-3  asia-northeast1-b  f1-micro                                192.168.0.5               TERMINATED
instance-4  asia-northeast1-b  n1-standard-1                           192.168.0.6               TERMINATED
vm-5        asia-northeast1-b  custom (1 vCPU, 3.75 GiB)               192.168.0.7               TERMINATED
```

#その他
gloudコマンドでエラーになるときは、「--log-http」をつけると理由がわかるかも。