Unable to sign JWT when using serviceAccountId - firebase

We've switched from service account keys to serviceAccountIds (or tried to) so we can clean up all the rouge keys we have. After rolling out the change we're seeing:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/xxxx#xxx.iam.gserviceaccount.com.; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature....}}
The thing is, we've definitely got the correct role applied (see attachment). We've even tried a few more for good measure.
Thanks!

There are two service accounts being used in this case:
The service account used to authorize RPC calls (in case of Cloud Functions, this is the App Engine default service account).
The service account you have specified as the serviceAccountId.
It seems IAM only works when BOTH service accounts have the signBlob permission. I have inquired the GCP/IAM team about this. In the meantime, here are couple of fixes you can try immediately:
Grant the token creator role to the App Engine default service
account of your project.
Once you do that, you don't have to
specify a serviceAccountId at all. The SDK will auto-discover that same
service account ID when running in Functions.

Related

Assign GCP functions service account roles to engage with Firebase using Terraform

I want to use the Firebase Admin SDK in my GCP cloud function, specifically for creating custom auth tokens.
I was getting auth/insufficient-permission errors after deployment and got to this thread. Note that it talks about Firebase functions, while I use pure GCP Cloud Functions.
To my understanding, GCP Cloud Functions uses the default App Engine service account, which is missing the Firebase Admin SDK admin service agent role.
I manually added it through the GCP console and it seems to solve the issue, but now I want to automate it via terraform where I manage my infrastructure.
How do I access the default App Engine service account? I think it's auto created when the GCP project is created.
How do I add the relevant role to it without changing other service accounts using that roles?
Is this it right approach, or is there a better way I'm missing?
The relevant documentation I was looking at is here. Note that I'm using initializeApp() without arguments, i.e. letting the library to discover the service account implicitly.
How to get the default App Engine service account through Terraform: google_app_engine_default_service_account
How to work with 'additional' IAM roles assigned to a service account:
IAM policy for service account
For general recommendations - I would prefer to use a specifically created service account and completely delete (or disable) the default App Engine service account.
Edit ==> Additional details as requested
Here is a description of Cloud Function service account in runtime:
The App Engine service account has the Editor role, which allows it broad access to many Google Cloud services. While this is the fastest way to develop functions, Google recommends using this default service account for testing and development only. For production, you should grant the service account only the minimum set of permissions required to achieve its goal.
Thus, it may be useful to delete/disable App Engine service account, create a specific service account for the given cloud function, assign it all relevant minimum of IAM roles, and use it.
As a side note I also would suggest to delete/disable the default Compute Engine service account, delete the default network with all firewall rules and subnetworks... But this is a separate story.

Why can firebase-admin not be run in the browser?

Several questions have asked to run the firebase-admin package in the browser, such as
Can I break the rules and use firebase-admin on the client side? Or will trying to workaround errors be for nothing?
How to properly use Firebase Admin SDK using Node.js for a web-app?
Error importing firebase-admin
https://groups.google.com/g/firebase-talk/c/Jfq054TLEFQ?pli=1
However, both the questions and the answers given do not properly distinguish between the "browser vs. server/backend" distinction and the "end-user vs. privileged" distinction. A common theme seems to be warning against opening up firebase-admin for end-users, which is obviously a security risk, but they do not explain why a privileged user cannot access privileged Firebase functionality from code running in the browser, only from a backend / server.
So, assuming that a user has sufficient privileges (say, firebase project owner) and is willing to perform whatever authentication needed to transfer these privileges to code running in the browser -- what reasons are there for not doing this? Will it not work? Are there security risks? Is it simply discouraged because a significant fraction of developers will make mistakes WRT the exact requirements for making this work securely?
I think you have a misunderstanding about what a "privileged user" is, as you say.
firebase-admin is initialized with a service account. This is not the same as an Firebase Auth user account. Service accounts are entities belonging to a cloud project that are granted privileged access to some resources in that project. This is how fireabse-admin operates - you init with a service account and gain that privileged access. firebase-admin does not init with a user account.
You never want to expose a service account credentials to a web browser. That's a huge security risk. Since firebase-admin requires a service account, you will never want to use firebase-admin in the browser where it will be seen as public information.
The whole point of the documentation on the matter is to get you to write code to send Firebase Auth user tokens to your backend, where you can safely validate them and decide if that end user should be able to perform privileged operations using firebase-admin. There is really no safe workaround to this scheme - this is the pattern you should follow.

Generate firebase token with scope for github actions

Is it possible to create a Firebase token using the CLI that only works for a specific project inside the account? The current way using firebase login:ci looks like it can work for all projects inside an account. I am going to use this token for specifically Github action CI work and might pass around other team members.
I have seen questions like this which was asked in 2019.
I'm planning to use the token with this action so any workaround is appreciated.
It's not possible.
When you get a login token, that token represents the user, unrelated to any projects that user might have access to.
If you want to control the per-user access to various projects, you will have to configure that in the console using IAM for each product that you are trying to control. If you give the user permission to make changes in the console, then they implicitly have permission to make the same changes from the CLI.
So you want to authenticate against Firebase to deploy a service within a CI pipeline.
And you want to scope that access to a specific project only to reduce the impact radius, if the token leaks.
firebase login:ci has (I) a too broad scope (all projects you as a user have access to) and (II) is tied to a specific person, which does not scale well if you get ever offboarded from that project...
The solution is to create a Service Account and assign it the necessary role(s).
You will need to make the Service Account key JSON file available on your CI server and set the GOOGLE_APPLICATION_CREDENTIALS respectively
The Github Action you linked provides actually the ability to authenticate via a Service Account. This means you are good to go

Firebase admin.auth().createCustomToken "Letting the Admin SDK discover a service account" approach does not work [duplicate]

We've switched from service account keys to serviceAccountIds (or tried to) so we can clean up all the rouge keys we have. After rolling out the change we're seeing:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/xxxx#xxx.iam.gserviceaccount.com.; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature....}}
The thing is, we've definitely got the correct role applied (see attachment). We've even tried a few more for good measure.
Thanks!
There are two service accounts being used in this case:
The service account used to authorize RPC calls (in case of Cloud Functions, this is the App Engine default service account).
The service account you have specified as the serviceAccountId.
It seems IAM only works when BOTH service accounts have the signBlob permission. I have inquired the GCP/IAM team about this. In the meantime, here are couple of fixes you can try immediately:
Grant the token creator role to the App Engine default service
account of your project.
Once you do that, you don't have to
specify a serviceAccountId at all. The SDK will auto-discover that same
service account ID when running in Functions.

Alternative to Firebase Secret in Firebase 3.x

I need to allow my app to fetch general information available in the Database but without making the information accessible elsewhere. In other words, allowing only my app to access some data.
As far as I know, Anonymous login is not an option for me because at a later stage I am login using email and password.
Basically, I am looking for an alternative to Firebase Secret, in order to allow my app to access the data, but not make that data publicly available by making it .read": "true".
In Firebase 2.x the way to do this was using Firebase Secret, but do not know how to achieve the same access without officially login in.
There is a similar question here, but it asks whether or not it is possible rather than alternatives.
Although the Secrets are deprecated now, you can find it under Project settings -> Service accounts -> Database Secrets.
Instead of the Secret, you should use the Firebase Admin in your project.

Resources