GitHub Actionsでfirebaseのdeploy時の認証をトークンからGCPのサービスアカウントに切り替える

`firebase deploy --token="$FIREBASE_TOKEN"`でデプロイすると、

```shell
Authenticating with `--token` is deprecated and will be removed in a future major version of `firebase-tools`. Instead, use a service account key with `GOOGLE_APPLICATION_CREDENTIALS`: https://cloud.google.com/docs/authentication/getting-started
```

と指摘されてしまいます。

CircleCIの値上がりによって、CircleCIからfirebaseにデプロイしていたサイトのCI/CDをGitHub Actionsに乗り換えていたのですが、せっかくなのでこちらの警告にも対応したいと思います。

# 材料

- GitHab Actionsのworkflowの設定ファイル（yamlファイル）
- GCPのサービス アカウントの認証キー（JSONファイル）

workflowの設定ファイルはFIREBASE_TOKENですでにデプロイ可能になっていることを前提としています。

# レシピ

## 1. GCPのサービス アカウントを作成する
firebaseと紐付いているgoogleアカウントで[サービス アカウントの作成] ページを開きます。すでに、Firebaseでプロジェクト作成済みの方は、「Firebaseコンソール」から[プロジェクトの設定] > [サービス アカウント] > [新しい秘密鍵の生成]からでも次のキーを取得まで実施可能です。

https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts/create?supportedpurview=project&_ga=2.55102056.276356708.1660636014-1058177307.1658898508

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412418/e9da2799-2954-79e1-1639-d0b289eefd76.png)


アカウント名もサービスアカウント説明も全部適当でOKです。

アカウントの権限は「Firebase Develop 管理者」にしました。

## 2. 作成したアカウントからキーを取得

アカウント一覧から作成したアカウントの[キーの管理]を開きます。

https://console.cloud.google.com/iam-admin/serviceaccounts

![スクリーンショット-2022-08-16-16.53.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412418/7c8176f7-fe9b-aac2-3700-e2b87dc6d41f.png)

キーの管理を開いたら中断にある[鍵を追加]を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412418/130398b5-ac61-c521-1592-751ca447ed86.png)

新しい鍵を作成を選択して、作成形式をJSONにしてください。

作成したらダウンロードが始まるのでローカルの適当なところに保存。

## 3.  キー（JSON）をbase64でエンコード

JSONファイルの扱いですが、認証情報なのでGitHub repositoryのsecretsに登録したいのでbase64で文字列にエンコードします。

```shell
cat 〇〇〇〇.json | base64
```
結果はクリップボードにコピーしておきます。

## 4. GitHub repositoryのsecretsにエンコード後の認証情報とJSONファイルの生成先を登録
ここからややこしくなっていきます。

対象のレポジトリの[settings]→[secrets]→[actions]から、[New repository secret]を選択して新しいsecretを2つ登録します。

|secret|内容|
|---|---|
|GCLOUD_SERVICE_KEY|先程コピーしたエンコード後の認証情報の文字列|
|GOOGLE_APPLICATION_CREDENTIALS|エンコード後の認証情報をデコードして生成する認証用JSONファイルの保存先・任意で設定できますが今回は先人に習って`/tmp/credentials.json`と指定しました|

GCLOUD_SERVICE_KEYは任意の名前で利用可能です。GOOGLE_APPLICATION_CREDENTIALSはこの名前で認証時にローカル変数として読まれるため、この時点からこの名前を使うことをおすすめします。

## 5. workflowの設定ファイルで4で設定したsecretを環境変数として読み込み

環境変数を設定するためにYAMLファイルの上段で以下のコードを記述して下さい。

```yaml
        GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
        GCLOUD_SERVICE_KEY: ${{ secrets.GCLOUD_SERVICE_KEY }}
```

するとこんな感じなります。

```yaml
jobs:
  deploy:
    env:
      GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      GCLOUD_SERVICE_KEY: ${{ secrets.GCLOUD_SERVICE_KEY }}
    runs-on: ubuntu-latest
```


## 6. CI/CD実行時にエンコード後の認証情報をデコードしてJSONに変換

一番面倒なところです。ローカルでエンコードしたJSONファイルをデコードして復活します。

以下の記述をデプロイ直前に追加してください。

```yaml
        # 認証情報を保持するjsonファイルをGOOGLE_APPLICATION_CREDENTIALSで指定したpassに生成
      - name: make GOOGLE_APPLICATION_CREDENTIALS
        run: echo $GCLOUD_SERVICE_KEY | base64 -d > $GOOGLE_APPLICATION_CREDENTIALS
```

## 7. 普通にデプロイ

ここまでやれば認証情報は勝手に読み込まれてくれるみたいなので普通にデプロイしてみましょう

```yaml
      - name: change environments
        run: firebase use environment
      - name: deploy to hosting
        run: firebase deploy
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412418/15472cb9-8025-4a3a-6ced-2a0f727a8ccf.png)


最後に一応認証情報を環境から削除しておきます。

```yaml
      - name: delete GOOGLE_APPLICATION_CREDENTIALS
        run: rm $GOOGLE_APPLICATION_CREDENTIALS
        if: ${{ always() }}
```

お疲れさまでした。

まとめるとこんな感じになると思います。

```yaml
jobs:
  deploy:
    env:
      GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      GCLOUD_SERVICE_KEY: ${{ secrets.PROD_GCP_KEY }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
```
（省略）
```yaml
      - name: install firebase
        run: npm install --save-dev firebase-tools
        # 認証情報を保持するjsonファイルをGOOGLE_APPLICATION_CREDENTIALSで指定したpassに生成
      - name: make GOOGLE_APPLICATION_CREDENTIALS
        run: echo $GCLOUD_SERVICE_KEY | base64 -d > $GOOGLE_APPLICATION_CREDENTIALS
      - name: change environments
        run: |
          ./node_modules/.bin/firebase use aitcweb-prod
      - name: deploy to hosting
        run: |
          ./node_modules/.bin/firebase deploy
        # 認証用jsonファイルを削除
      - name: delete GOOGLE_APPLICATION_CREDENTIALS
        run: rm $GOOGLE_APPLICATION_CREDENTIALS
        if: ${{ always() }}
```

軽くまとめていますが、自分が設定した際はかなり手こずりました。CircleCIからの移行は対したことなかったのですが、思ってなかったところでコケましたね。



それでは。