Github Actions で OIDC を使って Firebase Hosting に deploy したい
firebase 公式の github actions を使って、hosting を deploy する場合、Service Account を利用しなければならない。
OIDC token を利用して認証を行うことで、Service Account なしでよりセキュアに GCP とやりとりできるらしのでやってみる。
こちらを利用していく。
google-github-actions/auth の準備をする
Document に従って進めていく
Setting up Workload Identity Federation
まず、下準備として、GCP 側で Workload Identity Federation のセットアップを行う。
To exchange a GitHub Actions OIDC token for a Google Cloud access token, you must create and configure a Workload Identity Provider. These instructions use the gcloud command-line tool.
gcloud cli tool で Workload Identity Provider を作っていく。
対象の project を選択
$ export PROJECT_ID="my-project" # update with your value
Service Account を作成
$ gcloud iam service-accounts create "github-actions-cd"
ちゃんと作れてるか確認する
$ gcloud iam service-accounts list
作成した Service Account の email を後程使用するので控えておく。
IAM Credentials API を有効化する
$ gcloud services enable iamcredentials.googleapis.com
ちゃんと有効化されているか確認する
$ gcloud services list
iamcredentials.googleapis.com
があればOK
Workload Identity Pool を作成する
$ gcloud iam workload-identity-pools create "my-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="Demo pool"
エラー出たぞ
ERROR: (gcloud.iam.workload-identity-pools.create) PERMISSION_DENIED: Permission 'iam.workloadIdentityPools.create' denied
roles/iam.workloadIdentityPoolAdmin
role が必要みたい
roles/iam.workloadIdentityPoolAdmin
role を付与する
$ gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=user:me@example.com --role=roles/iam.workloadIdentityPoolAdmin
作成した Workload Identity Pool の ID を取得する
gcloud iam workload-identity-pools describe "my-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--format="value(name)"
projects/123456789/locations/global/workloadIdentityPools/my-pool
のような値
作成した Workload Identify Pool に Workload Identity Provider を作成する
gcloud iam workload-identity-pools providers create-oidc "my-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="my-pool" \
--display-name="Demo provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
ちゃんと作成されてるか確認する
gcloud iam workload-identity-pools providers list \
--location=global \
--workload-identity-pool="my-pool"
Workload Identity Pool に先ほど作成した Service Account を接続する
# TODO(developer): Update this value to your GitHub repository.
export REPO="username/name" # e.g. "google/chrome"
gcloud iam service-accounts add-iam-policy-binding "my-service-account@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}"
Workload Identity Provider Resource Name を取得
gcloud iam workload-identity-pools providers describe "my-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="my-pool" \
--format="value(name)"
projects/123456789012/locations/global/workloadIdentityPools/cd-pool/providers/my-provider
のような値
Firebase Hosting に必要な権限を Service Account に付与
roles/firebasehosting.admin
role を付与すれば良さそう
$ gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} --role=roles/firebasehosting.admin
functions や storage の deploy を行いたい場合は、それぞれに応じた role を別途付与。
これで準備完了!
Usage
jobs:
job_id:
# ...
# Add "id-token" with the intended permissions.
permissions:
contents: 'read'
id-token: 'write'
steps:
# actions/checkout MUST come before auth
- uses: 'actions/checkout@v3'
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v1'
with:
workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
service_account: 'my-service-account@my-project.iam.gserviceaccount.com'
# ... further steps are automatically authenticated
Outputs
- project_id: Provided or extracted value for the Google Cloud project ID.
- credentials_file_path: Path on the local filesystem where the generated credentials file resides. This is only available if "create_credentials_file" was set to true.
- access_token: The Google Cloud access token for calling other Google Cloud APIs. This is only available when "token_format" is "access_token".
- access_token_expiration: The RFC3339 UTC "Zulu" format timestamp for the access token. This is only available when "token_format" is "access_token".
- id_token: The Google Cloud ID token. This is only available when "token_format" is "id_token".
"google-github-actions/auth@v1" 以降の step で、以下の値が env
として利用できるようになる↓
CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE
GOOGLE_APPLICATION_CREDENTIALS
GOOGLE_GHA_CREDS_PATH
CLOUDSDK_CORE_PROJECT
CLOUDSDK_PROJECT
GCLOUD_PROJECT
GCP_PROJECT
GOOGLE_CLOUD_PROJECT
Firebase Tools の認証について
--token
は非推奨
User Token - DEPRECATED: this authentication method will be removed in a future major version of firebase-tools; use a service account to authenticate instead
firebase tools を利用した CI/CD に関しての記事でよく目にするが、--token
は非推奨。次期完全に廃止される。
firebase --token="<token>" projects:list
代わりに service account での認証を使う。
service account による認証
Service Account - set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to the path of a JSON service account key file. For more details, see Google Cloud's Getting started with authentication guide.
GOOGLE_APPLICATION_CREDENTIALS
env var に service account json file への path を指定する
workflow 作る
name: Deploy Firebase Hosting
on: workflow_dispatch
jobs:
deploy:
name: Deploy Firebase Hosting
runs-on: ubuntu-latest
# Add "id-token" with the intended permissions.
permissions:
contents: 'read'
id-token: 'write'
steps:
- uses: actions/checkout@v3.0.2
- uses: actions/setup-node@v3.1.1
with:
node-version: v16.14.2
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn install --immutable
- name: Install firebase tools
run: npm install -g firebase-tools
- id: auth
name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider
service_account: my-service-account@my-project.iam.gserviceaccount.com
- name: Build
run: yarn build
- name: Deploy
run: firebase deploy --only hosting
これで完了!