How to generate and use temporary credentials on Google Cloud Platform

With the 2.4 version of the GCP Terraform provider, a new feature is shipped allowing to generate short lived credentials. These credentials are based on the Oauth2 token exchange mechanism to implement impersonation between accounts.
You can also use this feature with the —-impersonate-service-account flag in the CLI gcloud.

This feature is very similar of the AWS AssumeRole allowing users to obtain temporary new permissions onto specific resources.

Let’s take a look at this feature!

Why using such mechanism?

This is great news because authenticating Terraform against GCP in a complex environment can be painful, and even more so when you want to manage the lifecycle of keys and users.

The two main ways to authenticate with gcloud are using personal access with oauth2 login or using a service account with its own key. The first may not be ideal because you have to grant individual (or group) permissions to the resources, which can be hard to track along time. Furthermore, not all APIs are working with individual credentials. The second way is more suitable to be used in automation but the credentials are long lived, and you have to share them with the members of your team who need to use automation tools.

To mitigate this issue, some people use a central tool like Terraform Enterprise or Atlantis. These tools handle your service account key and create another level of authorization for your users.

With this new mechanism, we can imagine new security models:

  • We can limit write access to a service account and grant read only access to users
  • We can grant impersonate access from users and/or group to a central service account
  • We can create many service accounts in projects and decide to allow different impersonation on each

For example you can see below an example of integration with a central service account.


How does this work?

The feature implements the token exchange described in the GCP Documentation for short lived credentials.

As a prerequisite, we need to create the service account to be impersonated:

  • Create the service account
  • Give permissions to the service account on desired resources
  • Allow users (or other SA) to issue access tokens on behalf of this service account

Then, you can emit impersonated credentials by following these steps:

  • Authenticate yourself with your own account or with another service account
  • Request a token for the service account
  • Use this token to authenticate on GCP

This new token will be linked to the service account and can use all of its permissions.

Granting permissions to a service account

As described before, we need some prerequisites to enable impersonation, the first is standard: we need to create a service account and grant it some permissions.

You can do it either in the gcloud console, or via Terraform. This is a sample using Terraform code:

resource "google_service_account" "admin_sa" {
account_id = "admin-impersonated"
display_name = "admin impersonated"
}
resource "google_project_iam_member" "editor" {
role = "roles/editor"
member = "serviceAccount:${google_service_account.admin_sa.email}"
}

Then, the second step is to grant permissions to your members to create access token:

resource "google_service_account_iam_member" "admin-account-iam" {
service_account_id = "${google_service_account.admin_sa.name}"
role = "roles/iam.serviceAccountTokenCreator"
member = "user:${var.user_email}"
}

Now the user targeted can issue a token on behalf of the service account.

On the other hand, you may want to use gcloud commands to set up this base permissions. Here are the commands to do this task:

PROJECT=my-project-id
USER=my-user@email.com
gcloud iam service-accounts create admin-impersonated
gcloud projects add-iam-policy-binding ${PROJECT} --member serviceAccount:admin-impersonated@${PROJECT}.iam.gserviceaccount.com --role roles/editor
gcloud iam service-accounts add-iam-policy-binding admin-impersonated@${PROJECT}.iam.gserviceaccount.com --member user:${USER} --role roles/iam.serviceAccountTokenCreator

Impersonating the service account to create a temporary access token

From now on, we can issue a token and use it to interact with GCP. To do that, we just have to call the API endpoint to generate tokens https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken. This endpoint supports some args: we can limit the scopes, or restrict the lifetime of the token. After the call, the response will contain the access token that we are looking for.

Here is a sample of code using Terraform. You will notice that we use two providers, one using the default authentication, and the other using the newly impersonated access token.

provider "google" {
scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
]
}
data "google_service_account_access_token" "default" {
target_service_account = "${google_service_account.admin_sa.email}"
scopes = [
"userinfo-email",
"cloud-platform",
]
lifetime = "300s"
}

In the code above we are setting the default provider, and calling the API endpoint to request an access token.

provider "google" {
version = "~> 2.4"
alias = "impersonated"
access_token = "${data.google_service_account_access_token.default.access_token}"
scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
]
}
resource "google_compute_network" "vpc_network" {
provider = "google.impersonated"
name = "test-net"
}

That’s it, the mechanism is very simple, you can easily implement it in your workflows. Note that the Terraform datasource will generate a new access token at each run, even if the previous is not expired yet.

Then, in this second block, we are defining another provider using the access token, and a dummy resource (a VPC) created with this new provider.

You can also use the gcloud command to do the same thing. Since version 240.0.0 (2019–03–26), the global flag —-impersonate-service-account is added into gcloud.

gcloud --impersonate-service-account=admin-impersonated@my-project-id.iam.gserviceaccount.com compute networks create test-net

Be careful

Even if this method is much more secure than having the same key used by everyone, you have to know that these generated credentials are non revocable and last for 3600 seconds by default (unless you change their lifetime). It means that if someone steals your temporary token, you won’t be able to mitigate the leak without deleting the service account itself!

To finish

I hope you enjoy this new technique and you will use it in your GCP deployments!

If you are looking for other nice contents and you are not afraid of French, feel free to check out our French blog: https://blog.wescale.fr (Come on, google translate is your friend!)

Thanks to my friends from The WeTribu who have patiently reviewed this article.