firebase-admin-node icon indicating copy to clipboard operation
firebase-admin-node copied to clipboard

[FR] Is it possible to use impersonated service account?

Open blue-hope opened this issue 2 years ago • 1 comments

Is your feature request related to a problem? Please describe. maybe related to #1703 I think It is not natural for the client to always have the service account json file, and I want to access the firebase admin through impersonate service account generated by gcloud auth application-default login --impersonate-service-account= which the service account has permission for generating custom token. However, when I use the service account which now stored in ADC, firebase admin throws an error message: 'Refresh token must contain a "client_id" property.'. In fact, the impersonate service account does not have a client_id itself, but it is contained in source_credentials like:

{
  "delegates": [],
  "service_account_impersonation_url": "",
  "source_credentials": {
    "client_id": "",
    "client_secret": "",
    "refresh_token": "",
    "type": "authorized_user"
  },
  "type": "impersonated_service_account"
}

Describe the solution you'd like When checking ADC's service account, if type is impersonated_service_account, then check source_credentials.

Describe alternatives you've considered I can manually get my service account from ADC and use 'source_credentials'. But is it really the only solution for checking impersonated service account?

Additional context No additional context

blue-hope avatar Aug 10 '22 14:08 blue-hope

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Aug 10 '22 14:08 google-oss-bot

Hey @blue-hope Thank you for your feature request and the PR! I am looking into this now. Thank you for your patience!

lahirumaramba avatar Oct 18 '22 15:10 lahirumaramba

@lahirumaramba Are there any updates?

blue-hope avatar Nov 01 '22 14:11 blue-hope

Hello, any chance to get that reviewed ? It will helps a lot to reduce the risk of generating a json key. Thanks !

Klaitos avatar Jan 12 '23 13:01 Klaitos

This is fixed in #1862 and now included in the v11.5.0 release.

Thanks folks for your patience on this! Try out the new feature if you get a chance and let us know what you think. If you encounter any issues, please open a new issue on Github. Thank you!

lahirumaramba avatar Jan 19 '23 17:01 lahirumaramba

Hi @blue-hope ! Thanks for working on this! Could you let me know what your initializeApp function looks like?

I'm initializing firebase like this:

initializeApp({
        credential: applicationDefault()
    })

But I get the following error:

Error: //cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters. Raw server response: "{"error":{"code":403,"message":"Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.","errors":[{"message":"Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.","domain":"usageLimits","reason":"accessNotConfigured","extendedHelp":"https://console.developers.google.com"}],"status":"PERMISSION_DENIED","details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"SERVICE_DISABLED","domain":"googleapis.com","metadata":{"consumer":"projects/764086051850","service":"identitytoolkit.googleapis.com"}}]}}"

frederikvanhevel avatar Jan 24 '23 14:01 frederikvanhevel

Hi @blue-hope ! Thanks for working on this! Could you let me know what your initializeApp function looks like?

I'm initializing firebase like this:

initializeApp({
        credential: applicationDefault()
    })

But I get the following error:

Error: //cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters. Raw server response: "{"error":{"code":403,"message":"Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.","errors":[{"message":"Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.","domain":"usageLimits","reason":"accessNotConfigured","extendedHelp":"https://console.developers.google.com"}],"status":"PERMISSION_DENIED","details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"SERVICE_DISABLED","domain":"googleapis.com","metadata":{"consumer":"projects/764086051850","service":"identitytoolkit.googleapis.com"}}]}}"

+1

rafael-fecha avatar Jan 24 '23 15:01 rafael-fecha

Hello, you need to authenticate as a service account, not an end-user. gcloud auth application-default login --impersonate-service-account [email protected]

Of course your end-user will need specific permission like Service Account User on the impersonated service account

Klaitos avatar Jan 24 '23 15:01 Klaitos

Hey @Klaitos , that's what i have been doing but without luck. I'm impersonating the firebase service account that has the following permissions: Screenshot 2023-01-25 at 13 03 45 And as for the end user, my account has Owner permissions so i should be good. Is there anything else I could be doing wrong?

frederikvanhevel avatar Jan 25 '23 12:01 frederikvanhevel

Hum yes you're right, it does not simply work on my local computer either. I figured it out how to make it works but it requires a lot of changes in the class ImpersonatedServiceAccountCredential, i can try to make a pull request but i don't know many things on oauth2 scopes.

Klaitos avatar Jan 25 '23 13:01 Klaitos

@blue-hope i think we might need your help on this one. I tried some code on my laptop, it works when we tweak the function getAccessToken of class ImpersonatedServiceAccountCredential with something like


  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/cloud-platform',
  });
  const client = await auth.getClient();
  const json = await client.getAccessToken()

  if (!json.token || !json.res?.data.expireTime) {
    throw new FirebaseAppError(
      AppErrorCodes.INVALID_CREDENTIAL,
      `Unexpected response while fetching impersonated access token: ${JSON.stringify(json)}`,
    );
  }

  return {
    access_token: json.token,
    expires_in: new Date(json.res.data.expireTime).valueOf() - new Date().valueOf()
  }

but i'm not aware of unexpected consequences

Klaitos avatar Jan 25 '23 17:01 Klaitos

It looks like we are not handling the token creation for impersonated accounts correctly here: https://github.com/firebase/firebase-admin-node/blob/49251a82b8fd1e30e09a82ca3797623d8691f4d0/src/app/credential-internal.ts#L399

Looking at the implementation in google-auth-library-nodejs this needs a bit more work. We need to send the token request to iamcredentials.googleapis.com instead of using the REFRESH_TOKEN_HOST. We also need to include the required scopes for admin sdk and add support for delegates in impersonated credentials. See: https://github.com/googleapis/google-auth-library-nodejs/blob/bdc6339014ae13945bbf82576f7ff71534851ab1/src/auth/impersonated.ts#L132

The proper fix for this is to migrate Admin SDK credentials handling logic to use google-auth-library-nodejs. This migration prevents us from having to maintain a separate codebase to perform the same actions that google-auth-library-nodejs handles better.

This is part of the reason for @Klaitos's workaround above to work, as it creates a new GoogleAuth client using ADC (and the client is smart enough to detect impersonated service account credentials from your environment).

We are currently doing the initial planning for credentials migration to google-auth-library-nodejs and part of that work is also related to #1377

lahirumaramba avatar Jan 25 '23 17:01 lahirumaramba

Sorry for my naive approach for getting access token. Don't we have to hot-fix REFRESH_TOKEN_HOST to iamcredentials.googleapis.com before implementing google-auth-library-nodejs? @lahirumaramba And if I can get a chance, I would like to participate the migration task.

blue-hope avatar Jan 26 '23 07:01 blue-hope

It's not that simple because you need to call the route iamcredentials.googleapis.com with an access token from the source user in order to get the access token for the service account and we do not have a simple way to get the first one i think

Klaitos avatar Jan 26 '23 07:01 Klaitos

Folks, is there an open issue tracking this? It seems like a huge problem that firebase doesn't work out of the box with Google's Recommended Security Practices for Service Accounts.

lox avatar Aug 29 '23 00:08 lox

Can we re-open this please?

lox avatar Nov 09 '23 22:11 lox

I implemented a workaround to do service account impersonation in https://gist.github.com/lox/8bff5607c3e713c92a03a631796ab3f3.

lox avatar Nov 09 '23 23:11 lox

Any updates on this? Is @lox workaround still the only way? gcloud's documentation goes into incredible depth of why service accounts are risky but there's no official implementation for service account impersonation in firebase admin.

velocd avatar Mar 07 '24 19:03 velocd

Hey @velocd we have made some changes internally to migrate credentials handling to use google-auth-library. Check out https://github.com/firebase/firebase-admin-node/issues/1377#issuecomment-1971607584 for a custom build if you have some time to test it out and share any early feedback. Thanks!

lahirumaramba avatar Mar 07 '24 19:03 lahirumaramba