Unable to assign iam.serviceAccounts.signBlob permission
Asked Answered
S

4

36

TLDR; I'm having trouble assigning an IAM permission to a service account.

I'm building a test that involves minting custom tokens with firebase Auth. When I hit:

  const token = await admin.auth().createCustomToken('test', {
    isAdmin: true,
  })

the following error is thrown

Permission iam.serviceAccounts.signBlob is required to perform
this operation on service account 
projects/-/serviceAccounts/[email protected].;
Please refer to 
https://firebase.google.com/docs/auth/admin/create-custom-tokens
for more details on how to use and troubleshoot this feature

In the referenced documentation it says to add the Service Account Token Creator role to the service account. I have added that role (as well as tried Service Account Admin to no avail.
Image verifying permissions

I can verify that my permissions seem to be correctly set, when I run gcloud projects get-iam-policy project I can see my service account attached to the desired role

- members:
  - serviceAccount:[email protected]
  role: roles/iam.serviceAccountTokenCreator

However if I look at that specific service account, it seems to show up empty which would fall in line with my error:

gcloud iam service-accounts get-iam-policy [email protected]
etag: ACAB
  • Why would those two commands & cloud console show differing information?

I assume that whatever is causing my service account permissions to show up blank is the culprit, but I'm not sure where to debug further. It seems to me the only difference is one command is called with a project in it, but I initialize my firebase app with the project id, and have verified it with (firebase-admin).apps[0].options so it seems like a dead end.

Sprawl answered 19/8, 2019 at 22:10 Comment(0)
C
30

The sign feature of a service account requires the iam.serviceAccounts.signBlob permission. This permission is included in the Service Account Token role roles/iam.serviceAccountTokenCreator

You can assign this role at the "project" level or at the "service account" level. This is why you see different results. Assigning roles at the project level affects permissions for all service accounts. Assigning roles at the service account only affects that service account.

The key to your problem is that the caller does not have this role on service account [email protected]. You have given the service account permission and NOT the caller. Look into your code for the service account that you used to setup the Firebase SDK.

Another option is to grant the role to {YOUR_PROJECT_NAME}@appspot.gserviceaccount.com (1st gen) or {RANDOM_NUMBER}[email protected] (2nd gen) but that grants permission to use any service account.

A service account is both an identity and a resource. You need permission for the resource. That permission can be granted via a service account's IAM policy or via the project's IAM policy.

Cella answered 20/8, 2019 at 0:25 Comment(7)
Thank you so much for your reply! I'm a little confused though, is the supplied service account to initializeApp not the service account used by the code? I am using the same service account, and see it listed when I look at the initialized apps options. admin.initializeApp({ projectId:project, serviceAccountId: [email protected]', });Sprawl
Edit your question with your code. Include enough to see everything from initialization to usage of the service accountCella
Where is your code running (Compute Engine, App Engine, your desktop)? Your initialization code will only work with a Google service as it relies upon ADC. Outside of Google, you will need to use a service account JSON key file to initialize Firebase.Cella
My code is running on my desktop. I've used gcloud auth application default with my user account so this initialization looks similar to how I initialize storage, pubsub, etc. Does firebase admin have different restrictions than those other SDKs?Sprawl
What is the user id (gcloud auth list). Verify that the user id has the permissions mentioned above.Cella
Ahh, that was it! My user account is an owner for the project and I assumed that would include all permissions but apparently not. Thank you for your help!Sprawl
how to assign that role on itself at service account level?Freddie
I
26

Firebase mentions about this error on its docs:

https://firebase.google.com/docs/auth/admin/create-custom-tokens#failed_to_determine_service_account

You must initialize your app correctly through a JSON config file.

A simple fix would be:

  1. Go to https://console.cloud.google.com/iam-admin/iam?project=PROJECT_NAME
  2. Edit your default service account.
  3. Add the role Service Account Token Creator

In a few minutes your project will be able to create signed tokens.

Internecine answered 11/6, 2020 at 15:14 Comment(1)
Is there a way to do this only for specific email addresses?Lasonde
P
10

If you still get iam.serviceAccounts.signBlob required error message even after following what others have said and you are using Firebase Cloud Functions, here are a few things you need to keep in mind.

  • If you are running "Firebase Local Emulator" or non-Google environment (i.e. not using Google Cloud), then your best option is to use service account JSON file. Note that in this case, the service account defined in the JSON file (that would be firebase-adminsdk-*****@PROJECT_NAME.iam.gserviceaccount.com in my case) doesn't need to have Service Account Token Creator role, because JSON file itself contains the private key. Not a terribly secure way to handle things, but there aren't many other options.

  • Firebase Cloud Functions come in 2 different flavors: 1st gen and 2nd gen. 1st gen's service account is typically [email protected], and 2nd gen is [email protected]. If you are using 2nd gen Cloud Function, you need to give Service Account Token Creator to the 2nd gen's service account. You can find it in "Google Cloud Console -> Your Project -> Serverless (in left pane) -> Cloud Functions -> Select function -> Details (2nd tab) -> Look for Service account".

Photopia answered 18/6, 2023 at 18:12 Comment(1)
I just upgraded to 2nd gen cloud functions and this was exactly my problem. To add the Service Account Token Creator role to my 2nd gen cloud function's service accounts I went to my project's IAM page and found the ${rand()}[email protected] service account, then clicked the Edit Principal pencil icon on the right, then ADD ANOTHER ROLE, then searched for Service Account Token Creator and hit Save. I had to wait a few minutes for it to work.Meng
B
1

If you need to accomplish this task within a Firebase Cloud function using .onCall(), please follow the steps outlined below:

from firebase_admin import storage
from google.auth import compute_engine
from google.auth.transport.requests import Request
from datetime import timedelta

def your_function(parameter):
    # Create an authentication request
    auth_request = Request()

    # Get your IDTokenCredentials
    signing_credentials = compute_engine.IDTokenCredentials(
        auth_request,
        "",
        service_account_email='<ADD YOUR SERVICE ACCOUNT MAIL(Principal)>'
    )

    # Get your storage bucket
    data_bucket = storage.bucket('<YOUR BUCKET>')
    
    # Generate a signed URL for your bucket
    blob = data_bucket.blob(parameter)
    url = blob.generate_signed_url(
        expiration=timedelta(days=7),
        credentials=signing_credentials, 
        version="v4"
    )
    
    return url

Remember to replace '<ADD YOUR SERVICE ACCOUNT MAIL(Principal)>' and '' with your actual service account email and bucket name, respectively.

Bucksaw answered 9/7, 2023 at 1:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.