I'm trying to create a schedule Cloud Function exporting my Firestore database to create backups. The code is running fine when serving on my local machine (which uses my personal user account with owner role) but failes once deployed. I already found out that I need to add the 'Storage Admin' and 'Datastore Import Export Admin' to the service account used when running the cloud function, but I can't figure out which service account is used for the functions.
Does anyone know which service account is used?
Firebase Cloud Functions use the {project-id}#appspot.gserviceaccount.com service account (App Engine default service account). Roles and permissions added to this service account carry over to the Cloud Functions runtime.
Good to know: When using Google Cloud Functions, the service account being used while running the function can be defined when deploying the function.
You can specify a custom service account with the runWith() method if you prefer not to use the default one nowadays. It accepts a number of RuntimeOptions that can be defined.
Related
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.
In a Firebase Cloud Function I want to trigger other functions on command (these would be http functions, since I don't think there's another way to do this). I want to make these functions not callable by any user, but only from the admin sdk, from other cloud functions. How should I do that?
HTTP functions deployed by the Firebase CLI are made public by default. You can choose not to make them public by configuring them to not allow public access (requiring authentication). This requires some knowledge about how the underlying Cloud Functions infrastructure works in Google Cloud Platform (Firebase does not expose all these details). The documentation for securing functions starts here.
If you choose not to allow unauthenticated access, you will have to provide IAM account credentials in the request from the code that you do want to allow to invoke the function.
This page explains both:
Obtaining and providing service account credentials manually for developing local, deploying on-premises, or deploying to another public cloud.
Obtaining credentials on Compute Engine, Kubernetes Engine, App Engine flexible environment, and Cloud Functions
But there is no mention of obtaining credentials on Cloud Run. I'd appreciate it if you give instructions for obtaining credentials and setting firebase-admin initializeApp and firebase initializeApp for authentication on Cloud Run.
The documentation suggests that you can use the default service account just like other Google Cloud products as described here. The Firebase Admin SDK should use that account when initialized with no parameters.
There are also steps described if you want to use a non-default service account, which you can simply configure in the console or provide with gcloud.
If you must provide a file that's readable at runtime, you will have to deploy an image with that file added to the image. There is no short set of steps to add that file - you will have to make your docker build include it in a readable location, and your code will know where to look for it in order to load it.
I have a Cloud Function that should only be invoked by a GKE cluster I'm also hosting. I'd also like to use Firebase Hosting to make a nice url. If I set up the Cloud Function Invoker role on that function to only allow the service account set up on that GKE cluster, will Firebase Hosting proxy that service account and thus still limit access to the Function to only the Invoker role? Or would I need to use something like Cloud Endpoints to achieve that?
If it's not supported with Firebase Hosting, can I still use the Firebase CLI to at least deploy the function and maintain the Invoker role set up? That is, will Firebase reset the Invoker role to allow All Users each time I deploy the Function?
I could test all this to determine the behavior, but I thought I'd ask the question first in case there's a better approach.
Firebase Hosting URLs are always public and Cloud Functions are proxied via public HTTP. You won't be able to restrict access to a function without Hosting also being unable to access it.
You should be able to restrict access to an HTTP function deployed by Firebase by:
Deploy it (it will be public for a brief time)
Modify the IAM for the function from the Google Cloud console
Redeploying the function via Firebase CLI shouldn't change any existing invoker roles (I haven't tried this, but it should work).
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.