0

I'm using gcloud configurations to handle my CLI access. (switching between them with gcloud config configurations activate <env_name>). I'm NOT using GOOGLE_APPLICATION_CREDENTIALS env var at all as I want to be able to switch between configurations/projects/accounts.

It works well with resources like google.cloud.firestore.Client() which takes the current configuration .

I'm trying to have authenticated calls between my (python) cloud functions. When I try to get the token using -

auth_req = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience)

I'm getting google.auth.exceptions.DefaultCredentialsError: Neither metadata server or valid service account credentials are found. I'll note that in a real cloud function fetch_id_token works.

I am able to get the token using cli command gcloud auth print-identity-token, but I want to get it using the python google auth library so it will work on both my local machine (using functions-framework) and in a real cloud function.

Is it possible? am I approaching all of this in a wrong way?

btw I'm using a Linux machine.

David Avikasis
  • 516
  • 1
  • 5
  • 16

3 Answers3

1

I have been struggling with the same issue. For some reason, there is almost no documentation on how to do this, but i managed to find a working way based on the following question How to get a GCP Bearer token programmatically with python that asks for access token. I found that id tokens can be fetched in the same way.

Using the following snippet:

import google.auth
from google.auth.transport.requests import Request as GoogleAuthRequest
auth_req = GoogleAuthRequest()

creds, _ = google.auth.default()
creds.refresh(auth_req)

id_token = creds.id_token

You will be able to fetch the id_token from local default credentials, following the order established in the documentation https://google-auth.readthedocs.io/en/master/reference/google.auth.html

This also works with the metadata server if running on a cloud environment

diegobatt
  • 113
  • 4
0

As long as you have the proper settings in place and the google.auth library can locate the credentials, you can get an ID token for the current gcloud configuration in Python. To get the ID token, utilize the audience parameter of the google.oauth2.id_token.fetch_id_token() method and set the URL of the Cloud Function you want to use for authentication as the audience parameter.

References:

Chanpols
  • 1,184
  • 1
  • 3
  • 13
  • Hi, thanks for your reply. As I've mentioned, this works on a cloud function, but not locally. I do have gcloud configuration set up locally, and it works for all cli and even python libs (like `google.cloud.firestore.Client()`) but does not work with `google.oauth2.id_token.fetch_id_token` - I get "Neither metadata server or valid service account credentials are found" – David Avikasis May 07 '23 at 08:05
0

Ok, I WAS getting it wrong*, according to the docs here -

The recommended way to use Google APIs is to use a client library and Application Default Credentials (ADC).

This works in a local development environment as well.

ADC searches for credentials in the following locations (in this order)

  1. GOOGLE_APPLICATION_CREDENTIALS environment variable
  2. User credentials set up by using the Google Cloud CLI
  3. The attached service account, returned by the metadata server

When logging in with gcloud auth application-default login, this command puts your credentials into a well-known location for use by ADC in a local development environment (e.g. ~/.config/gcloud/application_default_credentials.json). These are your local ADC credentials. The GOOGLE_APPLICATION_CREDENTIALS is NOT set automatically and is not needed, in most cases.

The credentials you provide to ADC by using the gcloud CLI (with gcloud auth application-default login as mentioned above) are distinct from your gcloud credentials — the credentials the gcloud CLI uses to authenticate to Google Cloud (i.e. with gcloud auth login, and using named/topic configurations using gcloud config configurations activate <env>). These are used to authenticate to and authorize access to Google Cloud services.

Your local ADC credentials are not used by the gcloud CLI, and your gcloud credentials are not used by ADC. They are two distinct sets of credentials.

Fetching ID token for authenticated requests

Ok, So we had local ADC credentials, and we had gcloud credentials. But neither of them will work with google.oauth2.id_token.fetch_id_token locally. For this, you'll need to use credentials of a service-account. you can get them using the web console or CLI, in short it's a json file, similar to the one that is created upon logging in with gcloud auth application-default login, but of a service-account. In order to make it work, you'll need to direct ADC to use this file - e.g. setting GOOGLE_APPLICATION_CREDENTIALS to this json file's path.


* In my defense I can confirm that google.cloud.firestore.Client() library works very well with gcloud credentials, including with different named configurations, which was the thing that really confused me. I'm still not sure why it works, as opposed to others like google.cloud.storage.Client(), which only works with ADC credentials locally.

David Avikasis
  • 516
  • 1
  • 5
  • 16