Stop Downloading Google Cloud Service Account Keys!

Service Accounts, OAuth2 and You

For some background, almost every change you want to make in Google Cloud from creating a GKE cluster to reading from a GCS bucket is handled using an API. This API is authenticated using the OAuth2 protocol, which basically means there’s a short lived (1 hour default) access token attached to every authenticated request. If you’re familiar with the whole “Sign in with Google” popup, that’s OAuth2 hard at work authenticating you with your Google credentials. Once you’re authenticated, an access token is attached to all your API requests whether you’re using gcloud, terraform, SDKs, or the console. In Google Cloud, we use a lot of automation and web services which similarly need those tokens, but robots aren’t very good at opening browsers and typing in passwords so they need some sort of verifiable identity. Enter Service Accounts.

Short lived tokens FTW!

Remember how I said that if you have the Service Account’s private key, you can sign a JWT token and be granted an API access token? Well there is a way to do that without ever needing to download the key.

gcloud container clusters get-credentials my-cluster
WARNING: This command is using service account impersonation. All API calls will be executed as []
gcloud config set auth/impersonate_service_account \
gcloud container clusters get-credentials my-cluster
# Other gcloud commands :)
#!/bin/bashIMPERSONATE='gcloud config set auth/impersonate_service_account'impersonate() {
echo "Impersonating $sa"
case $1 in
gcloud config unset auth/impersonate_service_account
echo "Usage: Updates impersonated service account"
echo " gsa [gke|admin|clear]"
$ gsa gke
Updated property [auth/impersonate_service_account].

$ gsa clear
Unset property [auth/impersonate_service_account].

What about Terraform?

We’ve spent all this time talking about a better way to consume service accounts through gcloud but what about the very common use case of Terraform? For development purposes, we need to test our infrastructure as code somehow. Thankfully, the google terraform provider supports directly passing an OAuth2 token as an environment variable. All you have to do to get this token and tell Terraform about it is this:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform apply
Example Makefile supporting impersonation with Terraform

Attribution and Logging

The SecOps folks may be thinking, how do I attribute and audit actions taken by a user impersonating a service account? In Cloud Logging, every API call executed by a service account that has been impersonated has the following structure within it:

"principalEmail": "",
"serviceAccountDelegationInfo": [
"firstPartyPrincipal": {
"principalEmail": ""
authenticationInfo: {
principalEmail: ""
serviceAccountKeyName: "//"


There are some use cases where downloading a service account key to your workstation is necessary, but they are not the norm. Keeping secrets like this short-lived locally should be the goal, the same way we should enable MFA and not use hunter2 as our password. For the obvious cases where service account keys must be downloaded to use GCP resources from your datacenter or another cloud, I’d recommend taking a look at HashiCorp Vault which has a plugin to checkout short-lived service account keys.

Next Steps



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store