gcp

Using stickfigures to show how Google Credentials work

2022-03-13

Google cloud authentication schemes are relatively confusing and I still have to take a step back and think about which credentials i’ve had and what is “in context” at the moment.

I’ve been meaning to draw the credentials you normally carry when using the gcloud cli and when you use Application Default Credentials.


..and all this confusion prompted me to writeup a helper script here:


Anyway, here are the pictures:

ADC

ADC, in excruciating details

  • first check if GOOGLE_APPLICATION_CREDENTIALS env-var is set.
  • If set, use the service account key file it points to or the Workload Identity federation
  • if not set, check the cred config that gcloud cli set with its own ADC setup (eg, who you logged in with gcloud auth application-default login)
  • read from metadata server if on GCE| Cloud Run | GCF| GKE, etc

gcloud

gcloud cli credentials are used for admin tasks for GCP resources. THese are the creds you use when running gcloud compute instances list

If the gcloud cli is bootstrapped as a user, its using three legged oauth (3LO) as described here Using Oauth2 for Native app

If you bootstrap gcloud cli for admin tasks using a service account, it will ultimately use two legged oauth (2LO): Using OAuth 2.0 for Server to Server Applications

So as a user, the login flow is pretty standard

gcloud initialization

for remote bootstrapping for a user (eg, to initialize gcloud in a system where there is no browser), its more complicated and involves some copy+paste

gcloud usage no-browser

and using it is same as an installed app:

gcloud usage

Finally, if you run gcloud cli in a GCE environment, the token is derived directly from the metadata server which has access to the key (ultimately)

gcloud with metadata server

Incase you want to run your own metadata server for testing locally, see GCE Metadata Server Emulator


Appendix: TokenInfo, ADC and gcloud

Lets “see” the credential types by hand and using the oauth2 tokeninfo endpoint to interrogate what we have:

https://oauth2.googleapis.com/tokeninfo?id_token=$ACCESS_TOKEN

The following uses a users credential and a service account credential (JSON) file just show which credentials we’ve just bootstrapped

Assume we have the following service account file and which carries the following client_id.

export SVC_ACCOUNT_FILE=/path/to/svcaccount.json
$ cat $SVC_ACCOUNT_FILE | jq -r '.client_id'
107846671635241723821

So lets login as a user and see some data about our token for ADC

# login as user
$ gcloud auth application-default login

curl -s https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN | jq '.'

$ export TOKEN=`gcloud auth application-default print-access-token`
$ curl -s https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN | jq '.'
{
  "azp": "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com",
  "aud": "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com",
  "sub": "1081579130932111111",
  "scope": "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth",
  "exp": "1647190187",
  "expires_in": "3592",
  "email": "user@domain.com",
  "email_verified": "true"
}

Note the email claim…that right, its me

Now set the environment variable for ADC pointing to the service account and repeat:

$ export GOOGLE_APPLICATION_CREDENTIALS=$SVC_ACCOUNT_FILE

$ export TOKEN=`gcloud auth application-default print-access-token`

$ curl -s https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN | jq '.'
 {
   "azp": "107846671635241723821",
   "aud": "107846671635241723821",
   "scope": "https://www.googleapis.com/auth/cloud-platform",
   "exp": "1647190437",
   "expires_in": "3596",
   "access_type": "online"
 }

# revoke just to clar
$ gcloud auth application-default revoke

So this is different but the thing to note is the azp, aud fields…it matches the client_id for our service account. Meaning ADC is now using a service account

Now compare this against gcloud CLI based usage

#  [login as user]
$ gcloud auth login
$ export TOKEN=`gcloud auth  print-access-token`

$ curl -s https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN | jq '.'
  {
    "azp": "32555940559.apps.googleusercontent.com",
    "aud": "32555940559.apps.googleusercontent.com",
    "sub": "1081579130932111111",
    "scope": "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/accounts.reauth",
    "exp": "1647190756",
    "expires_in": "3591",
    "email": "user@domain.com",
    "email_verified": "true"
  }

again, note the email and sub fields…thats me again

Lets move on to service account in gcloud cli:

## this will NOT set ADC...this only impacts gcloud cli operations (eg gcloud compute instances list)
$ gcloud auth activate-service-account --key-file=$SVC_ACCOUNT_FILE

$ export TOKEN=`gcloud auth  print-access-token`

$ curl -s https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$TOKEN | jq '.'
  {
    "azp": "107846671635241723821",
    "aud": "107846671635241723821",
    "sub": "107846671635241723821",
    "scope": "https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/userinfo.email openid",
    "exp": "1647190263",
    "expires_in": "3597",
    "email": "svcaccount1@mineral-minutia-820.iam.gserviceaccount.com",
    "email_verified": "true",
    "access_type": "online"
  }

Note the credentials for gcloud now uses a service account since we asked for gcloud cli’s token gcloud auth print-access-token

This site supports webmentions. Send me a mention via this form.