3

I am trying to fetch gsuite alerts via API. I have created a service account as per their docs and I have assigned that service account to my google cloud function.

I do not want to use environment variables or upload credentials along with source code but I want leverage default service account used by function.

from googleapiclient.discovery import build

def get_credentials():

    # if one knows credentials file location(when one uploads the json credentials file or specify them in environment variable) one can easily get the credentials by specify the path.
    # In case of google cloud functions atleast I couldn't find it the path as the GOOGLE_APPLICATION_CREDENTIALS is empty in python runtime

    # the below code work find if one uncomments the below line
    #credentials = ServiceAccountCredentials.from_json_keyfile_name(key_file_location)

    credentials = < how to get default credentials object for default service account?>

    delegated_credentials = credentials.create_delegated('admin@alertcenter1.bigr.name').create_scoped(SCOPES)
    return delegated_credentials

def get_alerts(api_name, api_version, key_file_location=None):

    delegated_credentials = get_credentials()
    alertcli = build(api_name, api_version, credentials=delegated_credentials)
    resp = alertcli.alerts().list(pageToken=None).execute()
    print(resp)


Is there any way I can create a default credentials object. I have tried using from google.auth import credentials but this does not contain create_delegated function and I have also tried ServiceAccountCredentials() but this requires signer.

himanshu219
  • 654
  • 7
  • 22

2 Answers2

4

Here is an example to use the Gmail API with delegated credentials. The service account credentials will need "Enable G Suite Domain-wide Delegation" enabled.

from google.oauth2 import service_account
from googleapiclient.discovery import build

credentials = service_account.Credentials.from_service_account_file(
                        credentials_file,
                        scopes=['https://www.googleapis.com/auth/gmail.send'])

impersonate = 'username@example.com'

credentials = credentials.with_subject(impersonate)

service = build('gmail', 'v1', credentials=credentials)
John Hanley
  • 74,467
  • 6
  • 95
  • 159
  • 1
    as you can see from my sample code that from_json_keyfile_name works fine if I know the file path but this code needs to run in google cloud function and I do not want to upload the credentials file separately with source code since I have already assigned the required role to the service account used by google cloud function. I just want to set the scope and delegated email. – himanshu219 Mar 27 '19 at 03:51
  • I misunderstood your question. – John Hanley Mar 27 '19 at 04:58
  • The problem is that you want to delegate access to a GSuite API with the Application Default Credentials. The default credentials cannot be used to impersonate and are only authorized to use Google Cloud APIs, not the other Google APIs like Gmail – Luiz Ferraz Jun 04 '19 at 00:15
  • @LuizFerraz - I am not sure why you posted this comment to me. In your comment you mention Application Default Credentials (ADC). You can authenticate with a service account which means that you can use default credentials for Domain-Wide delegation. You are misunderstanding what ADC means. ADC is a method of finding credentials and is not a type of credential. – John Hanley Jun 04 '19 at 00:37
  • On the question he asked for `< how to get default credentials object for default service account?>`. By "you" I was referring to @himanshu219 – Luiz Ferraz Jun 04 '19 at 00:43
  • I agree ADC is a method of finding credentials. What I meant is that the credentials google exposes through this method on Google Cloud Function has the restrictions I said. – Luiz Ferraz Jun 04 '19 at 00:49
  • @LuizFerraz - You can use the `--service-account` command-line option to specify any service account you want including one with G Suite Domain-Wide delegation. Therefore, you cannot make your assumption. – John Hanley Jun 04 '19 at 01:12
  • The [credentials exposed on GCF ADC](https://cloud.google.com/functions/docs/securing/function-identity#fetching_identity_and_access_tokens) contains the identity token and access token. It does not contain any private key, that is why it cannot be used to sign a delegated JWT. Even if you pass `--service-account` to change which service account is being used, the ADC will still only return the access token and this is not enough to impersonate a user, be the delegation enabled or not. Admittedly, it might have access to GSuite APIs scopes, but as the service account, not the user. – Luiz Ferraz Jun 04 '19 at 01:19
  • @LuizFerraz - You are partially correct, however, the private key is not required. Use the IAM signBlob API to sign instead. – John Hanley Jun 08 '19 at 03:11
  • @JohnHanley indeed, you can use the IAM signBlob API, but then you would need to implement that manually, since `google-auth` does the signing locally. You could also send a pull request to them to add this possibility, would solve multiple similar questions here – Luiz Ferraz Jun 10 '19 at 23:01
  • Well this helped me, so thank you :) – Robin Winslow Oct 05 '21 at 10:05
2

You can use the google.auth.default function to get the default credentials and use them to make an IAM signer which can be used to create new service account credentials which has the delegated email adress as subject. I have a more detailed answer for a similar question.

There is also Google Cloud Platform Github repository with some documentation about this method.

vkopio
  • 914
  • 1
  • 11
  • 28