Blog

Integrating Bitbucket Cloud Pipelines with Google Firebase using OpenID Connect

Written by Michael Jank | 07. Juni 2022

This blog post covers all the necessary steps to set up a continuous deployment pipeline from Bitbucket Cloud to Google Firebase.

Approaches

There are several approaches to integrating Bitbucket Cloud Pipelines with Google Firebase. We describe the three methods that we encountered during our research. Although we recommend using workload identity federation, another approach might fit your use case better. Choose whatever suits you best.

Generate a refresh token using the Firebase CLI

This approach is quite easy and may be sufficient for many setups but has some downsides. You can follow the instructions in the official Firebase documentation here. Essentially, you have to call firebase login:ci and then provide that token to the firebase CLI.

The major downside that we found was that you cannot use this approach with a service account. Only real users can generate such a token which has some unwanted consequences. The user used in the CI pipeline may have more permissions than necessary as it may not only be used in that context. Additionally, the token can be used from anywhere, not just from within the CI environment. Similarly, the deployment history would not tell you whether a deployment was triggered via the CI or locally.

Create and use a service account key

Another approach that we found when researching this task was to create and use a service account key. We won't document this approach here as it has several downsides as well. The service account key is available as JSON file, which contains all the necessary information to authenticate the account. Therefore, you would not want to just add the file to your repository without any further protection. Getting access to the file enables everyone that has it to deploy to your Firebase instance. You could work around this limitation by saving the file content in the pipeline's environment variables and only retrieving it during the pipeline's execution, but that is cumbersome and still doesn't protect you from all angles. Remember, once the file is leaked, anyone can use it from anywhere until you manually revoke the key. Check out the official documentation if you're still interested.

Workload Identity Federation (OpenID Connect)

Using Workload Identity Federation can avoid all the downsides mentioned above. By configuring Bitbucket Cloud as an identity provider in GCP, only the configured service account can deploy the application. We still use service accounts here, but what sets this approach apart from using service account keys is that we ensure that the service account can only be used from within the pipeline.

As described in the Google Cloud documentation, "workload identity federation follows the OAuth 2.0 token exchange specification. You provide a credential from an external identity provider to the Security Token Service, which verifies the identity on the credential, and then returns a federated token in exchange." In our case, the external identity provider is part of the Bitbucket Cloud, while the Security Token Service is in GCP. The following figure outlines the Authentication Flow.

 

OpenID Connect Authentication Flow

 

When the pipeline is started, the Bitbucket Identity Provider provides an external token. Within the pipeline, that token is sent to Google Cloud's Security Token Service. After verifying the external token against the Workload Identity Pool, it responds with a short-lived access token. Using that token the Firebase app can be deployed as the Service Account user.

How to configure

In Bitbucket Cloud, go to "Repository Settings" / "OpenID Connect". You will need this information to create a workload identity pool in GCP.

 

Information provided by Bitbucket to set up OIDC

 

Create a workload identity pool and connect an identity provider

Open your Firebase project with the Google Cloud Platform (GCP) console and go to "IAM and admin" / "Workload Identity Federation".

You need to create a workload identity pool and add a provider to it. If you haven't created a pool yet, you can do both things in one step. When adding the provider, select "OpenID Connect (OIDC)". Now you need the previously mentioned information from Bitbucket. Copy the issuer URL and the audience to the respective fields.

Creating an identity pool and adding a provider in GCP

 

Configure provider mapping

Next, you can configure a mapping between attributes from Bitbucket Cloud to GCP. You can use these attributes to restrict access to only a subset of identities within the pool. You can read more about that here. At the very least, you have to map google.subject to a unique and immutable ID, which in Bitbucket's case is the attribute assertion.sub.

 

Create a service account

If you haven't done so yet, you need to create the service account that shall be used for the deployment. You need to assign at least the role "Service Account User" for the service account to work. Depending on the Firebase features you use within your application, you also have to assign other roles. If you are unsure what roles you need, you can initially assign the "Firebase Admin" role and later use the Google Cloud Policy Adviser to reduce the excess permissions. If you have scheduled functions, "Firebase Admin" is not enough, and you will need to assign the "Cloud Scheduler Admin" role as well.

Grant access to the service account

After you've created the service account, go to the previously created identity pool and grant it access to the created service account. After that, a dialog will pop up that lets you download the configuration for use with Google Cloud client libraries, which the Firebase CLI uses internally. Select the created provider, set the OIDC ID token path to bitbucket-step-oidc-token and select the text format.

 

Download the OIDC client configuration from GCP

 

Create a deployment step in your Bitbucket pipeline

Unfortunately, the Bitbucket Cloud provides the OIDC token only as an environment variable, while the Firebase CLI requires that the token is read from a file. For this reason, we will write the token in the temporary file bitbucket-step-oidc-token. This file is referenced from the configuration previously created and downloaded from GCP, clientLibraryConfig-bitbucket-cloud.json. By setting the environment variable GOOGLE_APPLICATION_CREDENTIALS to the path pointing to the file, the Firebase CLI will know how to authenticate against GCP.

- step:
oidc: true
deployment: production
name: Deploy to firebase
image: andreysenov/firebase-tools:10.5.0
script:
- echo $BITBUCKET_STEP_OIDC_TOKEN > bitbucket-step-oidc-token
- GOOGLE_APPLICATION_CREDENTIALS=./clientLibraryConfig-bitbucket-cloud.json firebase deploy

 

🎉 Congratulations! You’ve set up deployment from a bitbucket pipeline to a Firebase instance.

If you have any questions regarding this approach, I'm happy to help you! Just send me an email.