google-cloud-platformgoogle-compute-engineservice-accountsgoogle-cloud-iamgoogle-container-os

Programmatically get current Service Account on GCP


Is there a way to programmatically access the email of the currently used Service Account on a GCP instance when no GOOGLE_APPLICATION_CREDENTIALS is set? (ie. when using the default Service Account)

I've looked through the GCP documentation, but the only resource I found can't be used with the default Service Account when no GOOGLE_APPLICATION_CREDENTIALS is set. I know that it is possible to do so using gcloud (see this SO question or documentation), however these solutions aren't applicable when running on a ContainerOptimisedOS. I've spent a couple of weeks back and forth with the GCP support team, but they concluded with not being able to help me and redirected me to Stack Overflow for help.


Solution

  • The solution of John works great, on any language without any external library. However, it works only in Google Cloud environment, when a metadata server is deployed. You can't perform this test on your computer.

    I propose just bellow a piece of Python code (with Google OAuth library, but it works in other languages that have this library) to ask the library the current credential. If the credential is a service account (from GOOGLE_APPLICATION_CREDENTIALS on your computer, the ADC (Application Default Credential) or from the metadata server), you have the email printed, else you have a warning message because you use your user account credential:

    import google.auth
    
    credentials, project_id = google.auth.default()
    
    if hasattr(credentials, "service_account_email"):
        print(credentials.service_account_email)
    else:
        print("WARNING: no service account credential. User account credential?")
    

    Note that if the default service account is used this method will print default instead of the entire email address.

    The Go version:

    ctx := context.Background()
    credential,err := google.FindDefaultCredentials(ctx)
    content := map[string]interface{}{}
    
    json.Unmarshal(credential.JSON, &content)
    if content["client_email"] != nil {
        fmt.Println(content["client_email"])
    } else {
        fmt.Println("WARNING: no service account credential. User account credential?")
    }