GCP で Service Account 作って CI サービスに登録する

# はじめに

[前回](https://qiita.com/82p/items/f472b499488a1c273b27) GCS を使って静的サイトをホスティングしようと試行錯誤した際に、GCP のサービスアカウントを作った。
GCS を使うより firebase のほうがいいじゃんとなったため、前回記事の続きは書く気にもなれないが、サービスアカウントについてはメモを残しておきたかった。

## おしながき

* サービスアカウントの作成
* 権限の付与（プロジェクト内のGCSへのフルアクセス権限）
* 接続情報(秘密鍵)の生成
* 接続情報を使って CLI でアクセス
* Circle CI に登録

## レッツトライ！
CIを回すにあたって、当然ルートアカウントで行うわけにはいかない。
なので、適切な権限を持った アカウントを を設定する。

### サービスアカウントの作成

GCP のアカウントについては[GCP公式Docs](https://cloud.google.com/iam/docs/overview?hl=ja)を参考に、今回は、「サービスアカウント」 というものを作成する。

* アカウント名は、 `web-static-upload` とする。
* プロジェクト名は前回に引き続き `web-yourdomain` とする。

```ps1
# Service Account の作成
# project は前回作成した web-yourdomain が デフォルトになっているものとする
PS> gcloud iam service-accounts create web-static-upload --display-name "Account for static web upload"
Created service account [web-static-upload].

# 作成できたか確認
PS> gcloud iam service-accounts list
NAME                                    EMAIL
Account for static web upload           web-static-upload@web-yourdomain.iam.gserviceaccount.com
```

確認した メールアドレス `web-static-upload@web-yourdomain.iam.gserviceaccount.com` は後々使うのでメモっておく

### 権限の付与

今回は Web公開用のプロジェクトを作ったので、プロジェクトのポリシーに設定する。

```ps1
# project のポリシーを確認
PS> gcloud projects get-iam-policy web-yourdomain --format json > iam.json
PS> cat .\iam.json
{
  "bindings": [
    {
      "members": [
        "serviceAccount:123456789012@cloudservices.gserviceaccount.com",
        "serviceAccount:123456789012-compute@developer.gserviceaccount.com"
      ],
      "role": "roles/editor"
    },
    {
      "members": [
        "user:hogehoge@gmail.com"
      ],
      "role": "roles/owner"
    }
  ],
  "etag": "XXXXXXX",
  "version": 1
}
```

メンバーの並びに、今回作成した Service Account を追加する。

```json
    {
      "members": [
        "serviceAccount:web-static-upload@web-yourdomain.iam.gserviceaccount.com"
      ],
      "role": "roles/storage.objectAdmin"
    }
```

これで、 `web-static-upload` アカウントに、 `web-yourdomain` プロジェクト内の GCS へのフルアクセス権が付与された。

既存の role については GCP公式Docs [役割について](https://cloud.google.com/iam/docs/understanding-roles?hl=ja#predefined_roles) を参照



### 接続情報の作成

このままでは、新しく作ったアカウントにアクセスすることはできないので、接続するための Key Pair を作成する。

```
# Key pair の生成
PS> gcloud iam service-accounts keys create .\key.json `
    --iam-account web-static-upload@web-yourdomain.iam.gserviceaccount.com
PS> cat .\key.json
{
  "type": "service_account",
  "project_id": "web-yourdomain",
  "private_key_id": "aabbccdd123456789012345678901234567890dd",
  "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqZsGugJ3PMzEq0uG9u44LsagEpQlfEc8Y9rrVlGsbwlDUYS7\nGOarCY90PsH1EV0XSWa3zls7GRJfzZuSliJEpg/SaeluFIDsbZJCfUy7hx33k7by\nolTl719lIxAZ2v7PZwJwt3MCMhIzCi40gwAi3kjNsVYrVHwuAp8Yi0YtQRhAi4c0\nzw0XW3qxvNl5gWeaCG2/aw4HHGGrRfTYdW6Q5jQxQeN0fkkX4pHv8oQdypZydCCi\nj3uEF8yVP1OVDAY0SE9rFUPLiEJSglOW/asOzgUaJZFpwfOotBQq+YrADR0Tg+mS\nx90Y8hqykcqweC/hKvcANkXQQlKOaN4XC7lxEQIDAQABAoIBADTcdoo+/n7aq2lg\nDt6jfKtHiNiBh/VmFnJg5vxuVDn/PxYHMnEeY6yFI4vz07fntbxQ4XTVhmPYEDf7\nBwL4B0FiqQgNkxuc2xODhGmdIs2ID4Pgf1sM7uVebB0zhXt185p9bjgfBk4o0fOY\nVxGFV1jEhCeDXdnlIkn64CF4a95feMpLO8lInTsgd9I/L3GJ5bM5aBxB+jBy5xHJ\nHEh1QDZAG3PsYyGlZ9L5NbsmcCnf6dmFRvw6gvII3H8M0EWXgNybytYL5vS6pZlc\n4mylMkogykqP2IqmyapC8Pi6M9/jIofb6edMC/SswqX80jW0KfRmcaDVazIKj2IK\nAfWucAECgYEA0ZTmmcuhDPuyK5AYD8PQBRavfd4zJsGJkqX1cuIAd0Ap+sow1Qx0\nSdK1Zy3jcXW7r8l3eh0rr9RVwvEaJbjYf502o14nXnb00KxJ1w6eeLqUTaxl7rYz\n03ps3EqcJe1nH4FvSXcxI8RipH3tzx1X4EOX2vGHNL3/qb+l5E9KoYECgYEAzyuE\nOs2gC9TLq6oscvsc0VCBE/v4zLkHYHsZHR1//S4E+kiTU76ghhFAkG8MxEptExxf\nGz4uQD3NN7ldkEggkL9KuAA4NjcOqZDTFVCWCXawVgTi81teHw6IQpSffGT0qc00\n6AsjlR3EmLVyC89r5dNJ6gvhrLGld9dy8//hd5ECgYBgd99lLzukVD6AmsTYjNM1\nZGnGz/5PeooufEFsbea0/U3VaDft+NuWF2z0X0Tvtrd7hIqAJOk099G592yHrHvK\n0bySmgYZDzxEyOj8GniLLaaR0ibhJ/DXCOUOyTDyrEHpWJS3BiwSQJT/Dg/mY6VN\nTw+Y8c/AUSxbICHl4zGBAQKBgQCRQ0EffkkHorkA8HzkTqFhP2KSoa5N1juO8iGk\n4ad53kfNOxBauyKRfw1XeRZpmIosyUsCrjH+B5eayBYL8hcrh4YbyMOheC+GxC7O\nFkht8FQqrJh57QntGuJ+VPoTXjKT0XiUcCMODuZn8Wo7T8CnUOTWAGjID3QnuOE4\np6XvkQKBgQDQ+1mZrSXWGk0ysyuEJrl58/a2Y1DHjmg7I/gFDBddS0IUrHZYEUbV\nYSrpGuuPjGNJKN7zpYnIrmhaDDURN1W3+esDZeMnUPsMTGVT0DP/W4hOpnpbDymA\n6fUgev/8GUS1t/bVPMXja7xl31lda9GDe3QjrC59aIDHFlAl4W6isA==\n-----END RSA PRIVATE KEY-----\n",
  "client_email": "web-static-upload@web-yourdomain.iam.gserviceaccount.com",
  "client_id": "12345678901234567890",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/web-static-upload%40web-yurdomain.iam.gserviceaccount.com"
}
```

このような形で秘密鍵などの情報を json 形式で取得できる。
*(秘密鍵などは当然ダミーデータです、念のため）*


### 接続情報を使って CLI でアクセス

Google Cloud SDK で auth サブコマンドの activate-service-account を利用して、
 `key.json` から認証情報を登録する。

```ps1
# keyファイルから認証情報を登録
PS> gcloud auth activate-service-account --key-file .\key.json

# 確認する
PS> gcloud auth list
                     Credentialed Accounts
ACTIVE  ACCOUNT
        hogehoge@gmail.com
*       web-static-upload@web-yourdomain.iam.gserviceaccount.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
```

`gcloud config set account hogehoge@gmail` のようにすればルートアカウントに切り替えられるようだ。
GCS にアクセスできるか、試しにアップロードしてみる。

```ps1
PS> echo "Hello GCP Service Account" > index.html
PS> gsutil cp -a public-read .\index.html gs://www.yourdomain.com
Copying file://.\index.html [Content-Type=text/html]...
- [1 files][   40.0 B/   40.0 B]
Operation completed over 1 objects/40.0 B.
```
うまくアップロードできた。あとは、この `key.json` を CI サービスに登録してやればうまくいきそうだ。

### Circle CI にを登録

CIサービスには [Circle CI のドキュメント](https://circleci.com/docs/1.0/google-auth/)を参考に。

先ほどの json を BASW64 エンコードして、環境変数として登録する。利用するときはデコードして秘密鍵を取り出す。

ということで登録するために key.json を BASE64 エンコードしてやる。

*※Powershell のパイプの方法がよくわからないので、いちいち変数に代入している。*

```ps1
PS> $key=Get-Content .\key.json
PS> $bytes=([System.Text.Encoding]::UTF8).GetBytes($key)
PS> [Convert]::ToBase64String($bytes)
```

出力された ey から始まる文字列を Circle-CI の環境変数に入れてやる。
*(プロジェクトをCIツールへ登録する方法などは割愛)*

![2018-01-05_18h50_44.png](https://qiita-image-store.s3.amazonaws.com/0/83984/7a8b3419-dda0-c5a2-304b-f8f8d8da709b.png)

あとはやっぱり、[ここ](https://circleci.com/docs/1.0/google-auth/)を参考に適当な ci スクリプト書いて

```yaml
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers`
      - image: google/cloud-sdk:latest
      
      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/repo

    steps:
      - checkout

      - run:
          name: create gcp credential
          command: |
            echo $GCLOUD_SERVICE_KEY | base64 --decode --ignore-garbage > ${HOME}/gcloud-service-key.json
      
      - run:
          name: deploy to gcs
          command: |
            gcloud auth activate-service-account --key-file ${HOME}/gcloud-service-key.json
            gsutil cp -a public-read ./index.html gs://$BUCKET_NAME/
```

ビルドを走らせれば…


![2018-01-15_18h38_58.png](https://qiita-image-store.s3.amazonaws.com/0/83984/8b2c9bd4-ab76-d781-be30-8d8e189a2aa3.png)

GCS にアップロードされる。

## 参考・その他

* 個人でするならこの程度でいいと思うが、企業で使うなら…

  * [Google Cloud のサービス アカウント キーを安全に管理する](https://cloudplatform-jp.googleblog.com/2017/08/help-keep-your-Google-Cloud-service-account-keys-safe.html)

* アカウントの種類について（ちょっと古いけど）
    * [GCPのCloud IAMを試してみた｜サイバーエージェント 公式エンジニアブログ](https://ameblo.jp/principia-ca/entry-12144854519.html)
* GCP コンソールから作成する方法（読んだだけで試してない）
    * [Google Cloud Platform のサービスアカウントキーを作成する | MAGELLAN BLOCKS](https://www.magellanic-clouds.com/blocks/guide/create-gcp-service-account-key/)