Cloud Build で firebase functions と hosting を deploy したい
公式 Doc に従って進めていく
先に github repo 接続用の Cloud Build Repository を作成しておく。
service account 権限付与
service account 準備する
Add Cloud Build Service Account, Firebase Admin and API Keys Admin roles.
必要な role は以下三つ
- Cloud Build Service Account (roles/cloudbuild.builds.builder)
- Firebase Admin (roles/firebase.admin)
- API Keys Admin (roles/serviceusage.apiKeysAdmin)
cloud build default service account
cloud build はデフォで Compute Engine default service account を利用する。
PROJECT_NUMBER-compute@developer.gserviceaccount.com
実際に利用される service accoun は GCP console > Cloud Build >Settings > Service Account から確認できる
custom service account 作成
Note: We have introduced changes to the default service account used to run builds. As a best practice, we recommend that you specify your own service account to run your builds. For more information see Cloud Build default service account change.
デフォの compute engine の service account は Editor role なのでだいぶ権限が強い。そのため、Cloud Build 用の個別の service account を作成し、必要最低限の権限を付与するのがベターとのこと。
この方針に従い Cloud Buiild 用の service account を作成し、必要な role を付与していく。
service account 作成
gcloud cli で service account 作成する
SERVICE_ACCOUNT_NAME="cloud-build-firebase"
PROJECT_ID="$(gcloud config get-value project)"
gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
--project $PROJECT_ID \
--description="Cloud Build Service Account for Firebase Deploy" \
--display-name="Cloud Build Firebase"
確認
gcloud iam service-accounts list
service account email 控えとく
SERVICE_ACCOUNT_EMAIL="$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com"
role を付与
- Cloud Build Service Account (roles/cloudbuild.builds.builder)
- Firebase Admin (roles/firebase.admin)
- API Keys Admin (roles/serviceusage.apiKeysAdmin)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
--role="roles/cloudbuild.builds.builder"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
--role="roles/firebase.admin"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
--role="roles/serviceusage.apiKeysAdmin"
cloudbuild.yaml で指定
#...
serviceAccount: 'projects/$PROJECT_ID/serviceAccounts/cloud-build-firebase@$PROJECT_ID.iam.gserviceaccount.com'
options:
logging: CLOUD_LOGGING_ONLY
firebase comminuty builder
Cloud Build で firebase-tools 使えるように下準備をする。
github repo を clone して自身の project の Container Registry に build した image を push してあげる必要がある。
git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/firebase
gcloud builds submit --region=$REGION .
ERROR: (gcloud.builds.submit) FAILED_PRECONDITION: failed precondition: due to quota restrictions, cannot run builds in this region, see https://cloud.google.com/build/docs/locations#restricted_regions_for_some_projects
asia-northeast1 だとエラー出た。しょうがないので asia-east1 でやるか。
gcloud builds submit --region=asia-east1 .
firebase community builder の中身
FROM node:lts-alpine3.18 AS app-env
# Install Python and Java and pre-cache emulator dependencies.
RUN apk add --no-cache python3 py3-pip openjdk11-jre bash && \
npm install -g firebase-tools && \
firebase setup:emulators:database && \
firebase setup:emulators:firestore && \
firebase setup:emulators:pubsub && \
firebase setup:emulators:storage && \
firebase setup:emulators:ui && \
rm -rf /var/cache/apk/*
ADD firebase.bash /usr/bin
RUN chmod +x /usr/bin/firebase.bash
ENTRYPOINT [ "/usr/bin/firebase.bash" ]
#!/bin/bash
# run the original firebase
if [ $FIREBASE_TOKEN ]; then
firebase "$@" --token $FIREBASE_TOKEN
else
firebase "$@"
fi
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/firebase', '.']
images:
- 'gcr.io/$PROJECT_ID/firebase'
tags: ['cloud-builders-community']
push したら clone したコードは消してOK
cd ../..
rm -rf cloud-builders-community/
firebase command を Cloud Build で実行
これで準備完了。Cloud Build step で firebase command が利用できるようになった。
こんな感じで↓先ほど push した gcr.io/$PROJECT_ID/firebase
image を使う step を用意して firebase command を実行できる。
steps:
- name: gcr.io/project-id/firebase
args: ['deploy', '--project=firebase-project-id', '--only=hosting']
gcloud builds submit --region=$REGION --config config-file-path source-directory
Artifact Registry への移行
Container Registry is deprecated and scheduled for shutdown. Organizations that haven't used Container Registry prior to January 8, 2024 have new gcr.io repositories hosted on Artifact Registry by default. Effective May 15, 2024, Google Cloud projects without previous usage of Container Registry will only support hosting and managing images for the gcr.io domain in Artifact Registry.
Container Registry is scheduled for shutdown on March 18, 2025. For details on the deprecation, see Container Registry deprecation.
公式 Doc の warning にある通り、Container Registry は shut down されるので、Artifact Registry への移行が必要。(January 8, 2024 までに Container Registry 使っていなかったら "gcr.io" は Artifact Registry に host された状態になるので移行不要)
package.json script 経由で firebase command 使いたい場合
firebase comminuty builder は entrypoint に firebase を実行する bash が指定されているため、firebase command を実行する前提で args に引数を受け渡す指定の方法が基本となる。
steps:
- name: gcr.io/project-id/firebase
args: ['deploy', '--project=firebase-project-id', '--only=hosting']
ただこれだと package.json scripts で deploy 用の command を用意してその一部として firebase command を呼び出しているケースに対応できない↓
"scripts": {
"deploy:dev": "npm run build:dev && firebase deploy --only hosting --project dev",
//...
}
この場合の対応について考える。
entrypoint
Use the entrypoint in a build step to specify an entrypoint if you don't want to use the default entrypoint of the builder. If you don't set this field, Cloud Build will use the builder's entrypoint. The following snippet sets the entrypoints for the npm build step:
cluodbuild.yaml entrypoint
で builder の default entrypoint を置き換えることができる。
これを使って、firebase commnity builder の entrypoint を置き換えてあげれば良さそう。
firebase comminity builder の entrypoint 変更
firebase comminity builder は node image をベースに作られているので npm, yarn は利用できる。
firebase community builder Dockerfile
FROM node:lts-alpine3.18 AS app-env
# Install Python and Java and pre-cache emulator dependencies.
RUN apk add --no-cache python3 py3-pip openjdk11-jre bash && \
npm install -g firebase-tools && \
firebase setup:emulators:database && \
firebase setup:emulators:firestore && \
firebase setup:emulators:pubsub && \
firebase setup:emulators:storage && \
firebase setup:emulators:ui && \
rm -rf /var/cache/apk/*
ADD firebase.bash /usr/bin
RUN chmod +x /usr/bin/firebase.bash
ENTRYPOINT [ "/usr/bin/firebase.bash" ]
なので、npm を利用している場合なら、以下のように entrypoint に "npm" を設定してあげれば良い
steps:
#...
- name: gcr.io/project-id/firebase
entrypoint: 'npm'
args: ['run', 'deploy']
pnpm を使っている場合は...?
pnpm を利用している場合は、残念なが firebase comminity builder をそのまま利用する形での対応は難しそう...
対応案として考えられるのは、この辺↓
- firebase comminity builder の Dockerfile をベースに pnpm を組み込んだものを自作して image を push し、それを Cloud Build で利用する
- firebase cominity builder を Cloud Build で利用する際に pnpm を install する
- firebase-tools を project の devDependencies に入れちゃう
firebase community builder を利用する際に pnpm を install
firebase cominity builder を Cloud Build で利用する際に pnpm を install する
今回は手短に Cloud Build 内で完結できるこの方向で対応してみる。
Using the script field
cloudbuild.yaml の script
field を利用することで shell scripts を実行できる。こちらを利用して pnpm を install してから、package.json script command を実行する流れでいく。
cloudbuild.yaml
scrip field で pnpm を install した上で、pnpm install してからの deploy command を実行する例↓
steps:
- name: gcr.io/project-id/firebase
script: |
npm install -g pnpm
pnpm install
pnpm run deploy
権限エラー
Error: Missing permissions required for functions deploy. You must have permission iam.serviceAccounts.ActAs on service account xxxxxxxxx@xxxxxxxxxx
service account に対する Service Account User Role が足りないみたい。
hosting の deploy のみにしてみたところ、この権限エラーはでないので functions を deploy する際に必要な権限が足りてないっぽい。
Cloud Run service account 利用権限付与
"Cloud Build で利用する service account" に "Cloud Run runtime の service account" に対する Service Account User role (roles/iam.serviceAccountUser) 付与する
CLOUD_BUILD_SERVICE_ACCOUNT_EMAIL= Cloud Build で利用する service account
CLOUD_RUN_SERVICE_ACCOUNT_EMAIL= Cloud Run runtime の service account
gcloud iam service-accounts add-iam-policy-binding \
$CLOUD_RUN_SERVICE_ACCOUNT_EMAIL \
--member=serviceAccount:$CLOUD_BUILD_SERVICE_ACCOUNT_EMAIL \
--role=roles/iam.serviceAccountUser
確認
gcloud iam service-accounts get-iam-policy \
$CLOUD_RUN_SERVICE_ACCOUNT_EMAIL
App Engine service account 利用権限付与
どうやら App Engine の service account の権限も必要みたい。
"Cloud Build で利用する service account" に "App Engine の service account" ($PROJECT_ID@appspot.gserviceaccount.com
)に対する Service Account User role (roles/iam.serviceAccountUser) 付与する。
CLOUD_BUILD_SERVICE_ACCOUNT_EMAIL= Cloud Build で利用する service account
APP_ENGINE_SERVICE_ACCOUNT_EMAIL= App Engine Default Service Account (PROJECT_ID@appspot.gserviceaccount.com)
gcloud iam service-accounts add-iam-policy-binding \
$APP_ENGINE_SERVICE_ACCOUNT_EMAIL \
--member=serviceAccount:$CLOUD_BUILD_SERVICE_ACCOUNT_EMAIL \
--role=roles/iam.serviceAccountUser
確認
gcloud iam service-accounts get-iam-policy \
$APP_ENGINE_SERVICE_ACCOUNT_EMAIL
これで問題なく Cloud Build から firebase hosting, funcions に deploy できた
Custom Role 作ってみる
公式 Doc に従って以下3つの role を付与することで hosting, functions へ deploy できることは確認できた。
- Cloud Build Service Account (roles/cloudbuild.builds.builder)
- Firebase Admin (roles/firebase.admin)
- API Keys Admin (roles/serviceusage.apiKeysAdmin)
しかし、権限与えすぎな気がするので最低限の権限に絞りたい。特に Firebase Admin の権限が強すぎる。
roles/cloudbuild.builds.builder
description: Can perform builds
etag: AA==
includedPermissions:
- artifactregistry.aptartifacts.create
- artifactregistry.attachments.create
- artifactregistry.attachments.get
- artifactregistry.attachments.list
- artifactregistry.dockerimages.get
- artifactregistry.dockerimages.list
- artifactregistry.files.download
- artifactregistry.files.get
- artifactregistry.files.list
- artifactregistry.files.update
- artifactregistry.files.upload
- artifactregistry.kfpartifacts.create
- artifactregistry.locations.get
- artifactregistry.locations.list
- artifactregistry.mavenartifacts.get
- artifactregistry.mavenartifacts.list
- artifactregistry.npmpackages.get
- artifactregistry.npmpackages.list
- artifactregistry.packages.get
- artifactregistry.packages.list
- artifactregistry.packages.update
- artifactregistry.projectsettings.get
- artifactregistry.pythonpackages.get
- artifactregistry.pythonpackages.list
- artifactregistry.repositories.createOnPush
- artifactregistry.repositories.deleteArtifacts
- artifactregistry.repositories.downloadArtifacts
- artifactregistry.repositories.get
- artifactregistry.repositories.list
- artifactregistry.repositories.listEffectiveTags
- artifactregistry.repositories.listTagBindings
- artifactregistry.repositories.readViaVirtualRepository
- artifactregistry.repositories.uploadArtifacts
- artifactregistry.rules.get
- artifactregistry.rules.list
- artifactregistry.tags.create
- artifactregistry.tags.get
- artifactregistry.tags.list
- artifactregistry.tags.update
- artifactregistry.versions.get
- artifactregistry.versions.list
- artifactregistry.yumartifacts.create
- cloudbuild.builds.create
- cloudbuild.builds.get
- cloudbuild.builds.list
- cloudbuild.builds.update
- cloudbuild.operations.get
- cloudbuild.operations.list
- cloudbuild.workerpools.use
- containeranalysis.occurrences.create
- containeranalysis.occurrences.delete
- containeranalysis.occurrences.get
- containeranalysis.occurrences.list
- containeranalysis.occurrences.update
- logging.logEntries.create
- logging.logEntries.list
- logging.views.access
- pubsub.topics.create
- pubsub.topics.publish
- remotebuildexecution.blobs.get
- resourcemanager.projects.get
- resourcemanager.projects.list
- source.repos.get
- source.repos.list
- storage.buckets.create
- storage.buckets.get
- storage.buckets.list
- storage.objects.create
- storage.objects.delete
- storage.objects.get
- storage.objects.list
- storage.objects.update
name: roles/cloudbuild.builds.builder
stage: GA
title: Cloud Build Service Account
roles/firebase.admin
description: Full access to Firebase products.
etag: AA==
includedPermissions:
- apikeys.keys.get
- apikeys.keys.getKeyString
- apikeys.keys.list
- apikeys.keys.lookup
- appengine.applications.get
- automl.annotationSpecs.create
- automl.annotationSpecs.delete
- automl.annotationSpecs.get
- automl.annotationSpecs.list
- automl.annotationSpecs.update
- automl.annotations.approve
- automl.annotations.create
- automl.annotations.list
- automl.annotations.manipulate
- automl.annotations.reject
- automl.columnSpecs.get
- automl.columnSpecs.list
- automl.columnSpecs.update
- automl.datasets.create
- automl.datasets.delete
- automl.datasets.export
- automl.datasets.get
- automl.datasets.getIamPolicy
- automl.datasets.import
- automl.datasets.list
- automl.datasets.setIamPolicy
- automl.datasets.update
- automl.examples.delete
- automl.examples.get
- automl.examples.list
- automl.examples.update
- automl.files.delete
- automl.files.list
- automl.humanAnnotationTasks.create
- automl.humanAnnotationTasks.delete
- automl.humanAnnotationTasks.get
- automl.humanAnnotationTasks.list
- automl.locations.get
- automl.locations.getIamPolicy
- automl.locations.list
- automl.locations.setIamPolicy
- automl.modelEvaluations.create
- automl.modelEvaluations.get
- automl.modelEvaluations.list
- automl.models.create
- automl.models.delete
- automl.models.deploy
- automl.models.export
- automl.models.get
- automl.models.getIamPolicy
- automl.models.list
- automl.models.predict
- automl.models.setIamPolicy
- automl.models.undeploy
- automl.operations.cancel
- automl.operations.delete
- automl.operations.get
- automl.operations.list
- automl.tableSpecs.get
- automl.tableSpecs.list
- automl.tableSpecs.update
- clientauthconfig.brands.get
- clientauthconfig.brands.list
- clientauthconfig.brands.update
- clientauthconfig.clients.create
- clientauthconfig.clients.delete
- clientauthconfig.clients.get
- clientauthconfig.clients.list
- clientauthconfig.clients.update
- cloudbuild.builds.get
- cloudbuild.builds.list
- cloudbuild.operations.get
- cloudbuild.operations.list
- cloudconfig.configs.get
- cloudconfig.configs.update
- cloudfunctions.functions.call
- cloudfunctions.functions.create
- cloudfunctions.functions.delete
- cloudfunctions.functions.get
- cloudfunctions.functions.getIamPolicy
- cloudfunctions.functions.invoke
- cloudfunctions.functions.list
- cloudfunctions.functions.setIamPolicy
- cloudfunctions.functions.sourceCodeGet
- cloudfunctions.functions.sourceCodeSet
- cloudfunctions.functions.update
- cloudfunctions.locations.list
- cloudfunctions.operations.get
- cloudfunctions.operations.list
- cloudmessaging.messages.create
- cloudnotifications.activities.list
- cloudtestservice.environmentcatalog.get
- cloudtestservice.matrices.create
- cloudtestservice.matrices.get
- cloudtestservice.matrices.update
- cloudtoolresults.executions.create
- cloudtoolresults.executions.get
- cloudtoolresults.executions.list
- cloudtoolresults.executions.update
- cloudtoolresults.histories.create
- cloudtoolresults.histories.get
- cloudtoolresults.histories.list
- cloudtoolresults.settings.create
- cloudtoolresults.settings.get
- cloudtoolresults.settings.update
- cloudtoolresults.steps.create
- cloudtoolresults.steps.get
- cloudtoolresults.steps.list
- cloudtoolresults.steps.update
- datastore.backupSchedules.create
- datastore.backupSchedules.delete
- datastore.backupSchedules.get
- datastore.backupSchedules.list
- datastore.backupSchedules.update
- datastore.backups.delete
- datastore.backups.get
- datastore.backups.list
- datastore.backups.restoreDatabase
- datastore.databases.bulkDelete
- datastore.databases.create
- datastore.databases.createTagBinding
- datastore.databases.delete
- datastore.databases.deleteTagBinding
- datastore.databases.export
- datastore.databases.get
- datastore.databases.getMetadata
- datastore.databases.import
- datastore.databases.list
- datastore.databases.listEffectiveTags
- datastore.databases.listTagBindings
- datastore.databases.update
- datastore.entities.allocateIds
- datastore.entities.create
- datastore.entities.delete
- datastore.entities.get
- datastore.entities.list
- datastore.entities.update
- datastore.indexes.create
- datastore.indexes.delete
- datastore.indexes.get
- datastore.indexes.list
- datastore.indexes.update
- datastore.keyVisualizerScans.get
- datastore.keyVisualizerScans.list
- datastore.locations.get
- datastore.locations.list
- datastore.namespaces.get
- datastore.namespaces.list
- datastore.operations.cancel
- datastore.operations.delete
- datastore.operations.get
- datastore.operations.list
- datastore.statistics.get
- datastore.statistics.list
- errorreporting.groups.list
- eventarc.channelConnections.create
- eventarc.channelConnections.delete
- eventarc.channelConnections.get
- eventarc.channelConnections.getIamPolicy
- eventarc.channelConnections.list
- eventarc.channelConnections.publish
- eventarc.channelConnections.setIamPolicy
- eventarc.channels.attach
- eventarc.channels.create
- eventarc.channels.delete
- eventarc.channels.get
- eventarc.channels.getIamPolicy
- eventarc.channels.list
- eventarc.channels.publish
- eventarc.channels.setIamPolicy
- eventarc.channels.undelete
- eventarc.channels.update
- eventarc.enrollments.create
- eventarc.enrollments.delete
- eventarc.enrollments.get
- eventarc.enrollments.getIamPolicy
- eventarc.enrollments.list
- eventarc.enrollments.setIamPolicy
- eventarc.enrollments.update
- eventarc.events.receiveAuditLogWritten
- eventarc.events.receiveEvent
- eventarc.googleApiSources.create
- eventarc.googleApiSources.delete
- eventarc.googleApiSources.get
- eventarc.googleApiSources.getIamPolicy
- eventarc.googleApiSources.list
- eventarc.googleApiSources.setIamPolicy
- eventarc.googleApiSources.update
- eventarc.googleChannelConfigs.get
- eventarc.googleChannelConfigs.update
- eventarc.locations.get
- eventarc.locations.list
- eventarc.messageBuses.create
- eventarc.messageBuses.delete
- eventarc.messageBuses.get
- eventarc.messageBuses.getIamPolicy
- eventarc.messageBuses.list
- eventarc.messageBuses.publish
- eventarc.messageBuses.setIamPolicy
- eventarc.messageBuses.update
- eventarc.messageBuses.use
- eventarc.operations.cancel
- eventarc.operations.delete
- eventarc.operations.get
- eventarc.operations.list
- eventarc.pipelines.create
- eventarc.pipelines.delete
- eventarc.pipelines.get
- eventarc.pipelines.getIamPolicy
- eventarc.pipelines.list
- eventarc.pipelines.setIamPolicy
- eventarc.pipelines.update
- eventarc.providers.get
- eventarc.providers.list
- eventarc.triggers.create
- eventarc.triggers.delete
- eventarc.triggers.get
- eventarc.triggers.getIamPolicy
- eventarc.triggers.list
- eventarc.triggers.setIamPolicy
- eventarc.triggers.undelete
- eventarc.triggers.update
- fcmdata.deliverydata.list
- firebase.billingPlans.get
- firebase.billingPlans.update
- firebase.clients.create
- firebase.clients.delete
- firebase.clients.get
- firebase.clients.list
- firebase.clients.undelete
- firebase.clients.update
- firebase.links.create
- firebase.links.delete
- firebase.links.list
- firebase.links.update
- firebase.playLinks.get
- firebase.playLinks.list
- firebase.playLinks.update
- firebase.projects.delete
- firebase.projects.get
- firebase.projects.update
- firebaseabt.experimentresults.get
- firebaseabt.experiments.create
- firebaseabt.experiments.delete
- firebaseabt.experiments.get
- firebaseabt.experiments.list
- firebaseabt.experiments.update
- firebaseabt.projectmetadata.get
- firebaseanalytics.resources.googleAnalyticsEdit
- firebaseanalytics.resources.googleAnalyticsReadAndAnalyze
- firebaseappcheck.appAttestConfig.get
- firebaseappcheck.appAttestConfig.update
- firebaseappcheck.appCheckTokens.verify
- firebaseappcheck.debugTokens.get
- firebaseappcheck.debugTokens.update
- firebaseappcheck.deviceCheckConfig.get
- firebaseappcheck.deviceCheckConfig.update
- firebaseappcheck.playIntegrityConfig.get
- firebaseappcheck.playIntegrityConfig.update
- firebaseappcheck.recaptchaEnterpriseConfig.get
- firebaseappcheck.recaptchaEnterpriseConfig.update
- firebaseappcheck.recaptchaV3Config.get
- firebaseappcheck.recaptchaV3Config.update
- firebaseappcheck.resourcePolicies.get
- firebaseappcheck.resourcePolicies.update
- firebaseappcheck.safetyNetConfig.get
- firebaseappcheck.safetyNetConfig.update
- firebaseappcheck.services.get
- firebaseappcheck.services.update
- firebaseappdistro.groups.list
- firebaseappdistro.groups.update
- firebaseappdistro.releases.list
- firebaseappdistro.releases.update
- firebaseappdistro.testers.list
- firebaseappdistro.testers.update
- firebaseauth.configs.create
- firebaseauth.configs.get
- firebaseauth.configs.getHashConfig
- firebaseauth.configs.getSecret
- firebaseauth.configs.update
- firebaseauth.users.create
- firebaseauth.users.createSession
- firebaseauth.users.delete
- firebaseauth.users.get
- firebaseauth.users.sendEmail
- firebaseauth.users.update
- firebasecrash.issues.update
- firebasecrash.reports.get
- firebasecrashlytics.config.get
- firebasecrashlytics.config.update
- firebasecrashlytics.data.get
- firebasecrashlytics.issues.get
- firebasecrashlytics.issues.list
- firebasecrashlytics.issues.update
- firebasecrashlytics.sessions.get
- firebasedatabase.instances.create
- firebasedatabase.instances.delete
- firebasedatabase.instances.disable
- firebasedatabase.instances.get
- firebasedatabase.instances.list
- firebasedatabase.instances.reenable
- firebasedatabase.instances.undelete
- firebasedatabase.instances.update
- firebasedataconnect.connectorRevisions.delete
- firebasedataconnect.connectorRevisions.get
- firebasedataconnect.connectorRevisions.list
- firebasedataconnect.connectors.create
- firebasedataconnect.connectors.delete
- firebasedataconnect.connectors.get
- firebasedataconnect.connectors.list
- firebasedataconnect.connectors.update
- firebasedataconnect.locations.get
- firebasedataconnect.locations.list
- firebasedataconnect.operations.cancel
- firebasedataconnect.operations.delete
- firebasedataconnect.operations.get
- firebasedataconnect.operations.list
- firebasedataconnect.schemaRevisions.delete
- firebasedataconnect.schemaRevisions.get
- firebasedataconnect.schemaRevisions.list
- firebasedataconnect.schemas.create
- firebasedataconnect.schemas.delete
- firebasedataconnect.schemas.get
- firebasedataconnect.schemas.list
- firebasedataconnect.schemas.update
- firebasedataconnect.services.create
- firebasedataconnect.services.delete
- firebasedataconnect.services.executeGraphql
- firebasedataconnect.services.executeGraphqlRead
- firebasedataconnect.services.get
- firebasedataconnect.services.list
- firebasedataconnect.services.update
- firebasedynamiclinks.destinations.list
- firebasedynamiclinks.destinations.update
- firebasedynamiclinks.domains.create
- firebasedynamiclinks.domains.delete
- firebasedynamiclinks.domains.get
- firebasedynamiclinks.domains.list
- firebasedynamiclinks.domains.update
- firebasedynamiclinks.links.create
- firebasedynamiclinks.links.get
- firebasedynamiclinks.links.list
- firebasedynamiclinks.links.update
- firebasedynamiclinks.stats.get
- firebaseextensions.configs.create
- firebaseextensions.configs.delete
- firebaseextensions.configs.list
- firebaseextensions.configs.update
- firebaseextensionspublisher.extensions.create
- firebaseextensionspublisher.extensions.delete
- firebaseextensionspublisher.extensions.get
- firebaseextensionspublisher.extensions.list
- firebasehosting.sites.create
- firebasehosting.sites.delete
- firebasehosting.sites.get
- firebasehosting.sites.list
- firebasehosting.sites.update
- firebaseinappmessaging.campaigns.create
- firebaseinappmessaging.campaigns.delete
- firebaseinappmessaging.campaigns.get
- firebaseinappmessaging.campaigns.list
- firebaseinappmessaging.campaigns.update
- firebasemessagingcampaigns.campaigns.create
- firebasemessagingcampaigns.campaigns.delete
- firebasemessagingcampaigns.campaigns.get
- firebasemessagingcampaigns.campaigns.list
- firebasemessagingcampaigns.campaigns.start
- firebasemessagingcampaigns.campaigns.stop
- firebasemessagingcampaigns.campaigns.update
- firebaseml.models.create
- firebaseml.models.delete
- firebaseml.models.get
- firebaseml.models.list
- firebaseml.models.update
- firebaseml.modelversions.create
- firebaseml.modelversions.get
- firebaseml.modelversions.list
- firebaseml.modelversions.update
- firebasenotifications.messages.create
- firebasenotifications.messages.delete
- firebasenotifications.messages.get
- firebasenotifications.messages.list
- firebasenotifications.messages.update
- firebaseperformance.config.update
- firebaseperformance.data.get
- firebaserules.releases.create
- firebaserules.releases.delete
- firebaserules.releases.get
- firebaserules.releases.getExecutable
- firebaserules.releases.list
- firebaserules.releases.update
- firebaserules.rulesets.create
- firebaserules.rulesets.delete
- firebaserules.rulesets.get
- firebaserules.rulesets.list
- firebaserules.rulesets.test
- firebasestorage.buckets.addFirebase
- firebasestorage.buckets.get
- firebasestorage.buckets.list
- firebasestorage.buckets.removeFirebase
- firebasestorage.defaultBucket.create
- firebasestorage.defaultBucket.delete
- firebasestorage.defaultBucket.get
- logging.logEntries.list
- monitoring.timeSeries.list
- oauthconfig.verification.get
- orgpolicy.policy.get
- recommender.cloudFunctionsPerformanceInsights.get
- recommender.cloudFunctionsPerformanceInsights.list
- recommender.cloudFunctionsPerformanceInsights.update
- recommender.cloudFunctionsPerformanceRecommendations.get
- recommender.cloudFunctionsPerformanceRecommendations.list
- recommender.cloudFunctionsPerformanceRecommendations.update
- recommender.iamPolicyInsights.get
- recommender.iamPolicyInsights.list
- recommender.iamPolicyInsights.update
- recommender.iamPolicyRecommendations.get
- recommender.iamPolicyRecommendations.list
- recommender.iamPolicyRecommendations.update
- recommender.locations.get
- recommender.locations.list
- recommender.runServiceCostInsights.get
- recommender.runServiceCostInsights.list
- recommender.runServiceCostInsights.update
- recommender.runServiceCostRecommendations.get
- recommender.runServiceCostRecommendations.list
- recommender.runServiceCostRecommendations.update
- recommender.runServiceIdentityInsights.get
- recommender.runServiceIdentityInsights.list
- recommender.runServiceIdentityInsights.update
- recommender.runServiceIdentityRecommendations.get
- recommender.runServiceIdentityRecommendations.list
- recommender.runServiceIdentityRecommendations.update
- recommender.runServicePerformanceInsights.get
- recommender.runServicePerformanceInsights.list
- recommender.runServicePerformanceInsights.update
- recommender.runServicePerformanceRecommendations.get
- recommender.runServicePerformanceRecommendations.list
- recommender.runServicePerformanceRecommendations.update
- recommender.runServiceSecurityInsights.get
- recommender.runServiceSecurityInsights.list
- recommender.runServiceSecurityInsights.update
- recommender.runServiceSecurityRecommendations.get
- recommender.runServiceSecurityRecommendations.list
- recommender.runServiceSecurityRecommendations.update
- recommender.storageBucketSoftDeleteInsights.get
- recommender.storageBucketSoftDeleteInsights.list
- recommender.storageBucketSoftDeleteInsights.update
- recommender.storageBucketSoftDeleteRecommendations.get
- recommender.storageBucketSoftDeleteRecommendations.list
- recommender.storageBucketSoftDeleteRecommendations.update
- remotebuildexecution.blobs.get
- resourcemanager.hierarchyNodes.listEffectiveTags
- resourcemanager.projects.get
- resourcemanager.projects.getIamPolicy
- resourcemanager.projects.list
- run.configurations.get
- run.configurations.list
- run.executions.cancel
- run.executions.delete
- run.executions.get
- run.executions.list
- run.jobs.create
- run.jobs.createTagBinding
- run.jobs.delete
- run.jobs.deleteTagBinding
- run.jobs.get
- run.jobs.getIamPolicy
- run.jobs.list
- run.jobs.listEffectiveTags
- run.jobs.listTagBindings
- run.jobs.run
- run.jobs.runWithOverrides
- run.jobs.setIamPolicy
- run.jobs.update
- run.locations.list
- run.operations.delete
- run.operations.get
- run.operations.list
- run.revisions.delete
- run.revisions.get
- run.revisions.list
- run.routes.get
- run.routes.invoke
- run.routes.list
- run.services.create
- run.services.createTagBinding
- run.services.delete
- run.services.deleteTagBinding
- run.services.get
- run.services.getIamPolicy
- run.services.list
- run.services.listEffectiveTags
- run.services.listTagBindings
- run.services.setIamPolicy
- run.services.update
- run.tasks.get
- run.tasks.list
- runtimeconfig.configs.create
- runtimeconfig.configs.delete
- runtimeconfig.configs.get
- runtimeconfig.configs.list
- runtimeconfig.configs.update
- runtimeconfig.operations.get
- runtimeconfig.operations.list
- runtimeconfig.variables.create
- runtimeconfig.variables.delete
- runtimeconfig.variables.get
- runtimeconfig.variables.list
- runtimeconfig.variables.update
- runtimeconfig.variables.watch
- runtimeconfig.waiters.create
- runtimeconfig.waiters.delete
- runtimeconfig.waiters.get
- runtimeconfig.waiters.list
- runtimeconfig.waiters.update
- serviceusage.quotas.get
- serviceusage.services.get
- serviceusage.services.list
- storage.anywhereCaches.create
- storage.anywhereCaches.disable
- storage.anywhereCaches.get
- storage.anywhereCaches.list
- storage.anywhereCaches.pause
- storage.anywhereCaches.resume
- storage.anywhereCaches.update
- storage.bucketOperations.cancel
- storage.bucketOperations.get
- storage.bucketOperations.list
- storage.buckets.create
- storage.buckets.createTagBinding
- storage.buckets.delete
- storage.buckets.deleteTagBinding
- storage.buckets.enableObjectRetention
- storage.buckets.get
- storage.buckets.getIamPolicy
- storage.buckets.getObjectInsights
- storage.buckets.list
- storage.buckets.listEffectiveTags
- storage.buckets.listTagBindings
- storage.buckets.restore
- storage.buckets.setIamPolicy
- storage.buckets.update
- storage.folders.create
- storage.folders.delete
- storage.folders.get
- storage.folders.list
- storage.folders.rename
- storage.managedFolders.create
- storage.managedFolders.delete
- storage.managedFolders.get
- storage.managedFolders.getIamPolicy
- storage.managedFolders.list
- storage.managedFolders.setIamPolicy
- storage.managementHubs.get
- storage.managementHubs.update
- storage.multipartUploads.abort
- storage.multipartUploads.create
- storage.multipartUploads.list
- storage.multipartUploads.listParts
- storage.objects.create
- storage.objects.delete
- storage.objects.get
- storage.objects.getIamPolicy
- storage.objects.list
- storage.objects.overrideUnlockedRetention
- storage.objects.restore
- storage.objects.setIamPolicy
- storage.objects.setRetention
- storage.objects.update
name: roles/firebase.admin
stage: GA
title: Firebase Admin
roles/serviceusage.apiKeysAdmin
description: Ability to create, delete, update, get and list API keys for a project.
etag: AA==
includedPermissions:
- apikeys.keys.create
- apikeys.keys.delete
- apikeys.keys.get
- apikeys.keys.getKeyString
- apikeys.keys.list
- apikeys.keys.lookup
- apikeys.keys.undelete
- apikeys.keys.update
- orgpolicy.policy.get
- serviceusage.apiKeys.regenerate
- serviceusage.apiKeys.revert
name: roles/serviceusage.apiKeysAdmin
stage: GA
title: API Keys Admin
最低限必要そうなところから trial and error でしらみ潰しに必要な権限付け足していく
ようやく deploy できるところまでいけた...
こちらが hosting, functions を deploy するために必要だった権限↓
#...
includedPermissions:
# Cloud Build Operations
- storage.objects.get
- cloudbuild.builds.create
- cloudbuild.builds.get
- cloudbuild.builds.update
- cloudbuild.builds.list
- artifactregistry.repositories.downloadArtifacts
# Firebase tools
- firebase.projects.get
# Firebase Hosting Deployment
- firebasehosting.sites.update
# Cloud Functions Deployment
- cloudfunctions.functions.create
- cloudfunctions.functions.update
- cloudfunctions.functions.delete
- cloudfunctions.functions.list
- runtimeconfig.configs.get
- serviceusage.services.get
- firebaseextensions.instances.list
- resourcemanager.projects.get
- cloudfunctions.functions.generateUploadUrl
- cloudfunctions.operations.get
この他に、以下 resource 対して iam policy binding は別途行っている↓
- Logging 用 Storage bucket への storage admin 権限
- Cloud Run service account user
- App Engine service account user
ただ、現状 functions は https trigger しかないからこの程度で収まっている感もある。
おとなしく Firebase Functions Admin role を付与した方がいいかもしれない...
scheduler を追加してみる
scheduler functions を追加して不要な role が存在しないか確かめる
import { onSchedule } from 'firebase-functions/v2/scheduler';
//...
export const scheduler = onSchedule('every day 00:00', async (context) => {
console.log('This will run every day 00:00!');
// Add your scheduled task logic here
});
権限エラー出た
Permissions denied enabling cloudscheduler.googleapis.com.
serviceusage.services.enable
が足りなかったみたい
scheduler の deploy 時に permission エラー↓
HTTP Error: 403, Permission 'run.services.setIamPolicy' denied on resource
run.services.setIamPolicy
追加する
deploy 完了!
Permission 一覧
# ...
includedPermissions:
# Cloud Build Operations
- storage.objects.get
- cloudbuild.builds.create
- cloudbuild.builds.get
- cloudbuild.builds.update
- cloudbuild.builds.list
- artifactregistry.repositories.downloadArtifacts
# Firebase tools
- firebase.projects.get
# Firebase Hosting Deployment
- firebasehosting.sites.update
# Cloud Functions Deployment
- cloudfunctions.functions.create
- cloudfunctions.functions.update
- cloudfunctions.functions.delete
- cloudfunctions.functions.list
- runtimeconfig.configs.get
- serviceusage.services.get
+ - serviceusage.services.enable
- firebaseextensions.instances.list
- resourcemanager.projects.get
- cloudfunctions.functions.generateUploadUrl
- cloudfunctions.operations.get
+ - run.services.setIamPolicy
https trigger を public にするとエラー
export const example = onRequest(
{
+ invoker: 'public',
},
//...
);
Permission 'run.services.getIamPolicy' denied on resource ...
run.services.getIamPolicy
が必要
修正後の permissions↓
includedPermissions:
# Cloud Build Operations
- storage.objects.get
- cloudbuild.builds.create
- cloudbuild.builds.get
- cloudbuild.builds.update
- cloudbuild.builds.list
- artifactregistry.repositories.downloadArtifacts
# Firebase tools
- firebase.projects.get
# Firebase Hosting Deployment
- firebasehosting.sites.update
# Cloud Functions Deployment
- cloudfunctions.functions.create
- cloudfunctions.functions.update
- cloudfunctions.functions.delete
- cloudfunctions.functions.list
- runtimeconfig.configs.get
- serviceusage.services.get
- serviceusage.services.enable
- firebaseextensions.instances.list
- resourcemanager.projects.get
- cloudfunctions.functions.generateUploadUrl
- cloudfunctions.operations.get
- run.services.setIamPolicy
+ - run.services.getIamPolicy
hosting で firebase functions への rewrite するとエラー
run.services.get
が必要