Terraform on GoogleCloud - impersonating with short-lived AccessTokens & ServiceAccounts

syedrakib

Rakib Al Hasan

Posted on April 20, 2020

Terraform on GoogleCloud - impersonating with short-lived AccessTokens & ServiceAccounts

Your Current Setup

  1. you have a Google Cloud Platform (GCP) project
  2. you have a Terraform script
  3. you have the JSON Key of a ServiceAccount in your Terraform script
  4. your ServiceAccount has full (owner) access to your GCP - to be able to create & destroy anything & everything in GCP as & when needed.

The Problem Statement

Point number 4 above is the problem statement. You have a JSON key outside in the world that has FULL access to do anything with your GCP. If anyhow that JSON key is obtained by someone(despite all sorts of encryption / protection / etc etc), you run the risk of a lot of damage. That's a big risk in security perspective and we can do better than that.

Enter Impersonation

The idea is simple.

The executor ServiceAccount (for which you have a JSON key that is literally floating out there in the wild jungle called "the internet") will only have super-limited / super-controlled / super-tight access to your GCP. That's all it is allowed to do. Nothing more than that. Kinda secure that way.

That TF executor ServiceAccount will "impersonate" another super ServiceAccount - the mighty one who will have all the privileges and permissions to do anything & everything with your GCP as required by Terraform to create/modify/destroy resources.

However, this super-mighty ServiceAccount will not have any JSON key (so nothing about it is floating out there on the internet - kinda secure that way) and it will allow only very specific ServiceAccounts (for example, the executor ServiceAccount in this case) to "impersonate" it.

How does it work in practice?

Let's assign some names first:

  • let's call the ServiceAccount with limited permissions our tf-executor
  • let's call the super-mighty ServiceAccount our tf-owner

Let's write our Terraform providers

provider "google" {
  credentials = file(var.path_to_tf_executor_service_account_json_file)
  alias       = "tf_executor"
}

data "google_service_account_access_token" "impersonated" {
  provider                = google.tf_executor
  target_service_account  = var.tf_owner_service_account_email
  scopes                  = [ "cloud-platform" ]
  lifetime                = "1800s" # 30 minutes - max can be set up to 60 minutes
}

provider "google" {
  access_token = data.google_service_account_access_token.impersonated.access_token
  project      = var.gcp_project_id
  region       = var.region
}

provider "google-beta" {
  access_token = data.google_service_account_access_token.impersonated.access_token
  project      = var.gcp_project_id
  region       = var.region
}

# Terraform v0.12.24
# provider.google v3.13.0
# provider.google-beta v3.13.0
Enter fullscreen mode Exit fullscreen mode

Some things to note in the script above

  1. there are 2 google providers and 1 google-beta provider. Ignore the importance of google-beta provider for this discussion. It is here just to show that we can have multiple providers "impersonating" the same ServiceAccount

  2. there is a google provider with an alias
    there is a google provider without alias

  3. the aliased google provider uses the tf-executor ServiceAccount via its JSON key file

  4. the data block uses the aliased google provider to call google APIs to request for a new access token on behalf of tf-owner - this new access token will last for 30 minutes - max can be set up to 60 minutes

  5. this new access_token from the data block has cloud-platform scope. This means the access token has full access across all of GCP - as long as the IAM roles assigned to the tf-owner ServiceAccount allow it - more on this inside the "Roles for tf-owner" section below.

  6. this new access_token from the data block is then used by the non-aliased google provider and the non-aliased google-beta provider - thus "impersonating" the tf-owner ServiceAccount

  7. now, we can use these non-aliased providers in our Terraform resources and modules:

    • mentioning provider = google.tf_executor inside the resource will refer to the aliased google provider - which really has only very limited permissions by itself
    • mentioning provider = google (or by not even mentioning it because it is implied by default) inside the resource will refer to the non-aliased google provider - which now has all the necessary permissions to perform everything

This way, throughout the rest of our Terraform script, our "impersonated" google provider (aka our non-aliased google provider) will have all the necessary permissions (on behalf of tf-owner) to perform all terraform operations like create/modify/destroy as needed.

Roles & Permissions

Roles for tf-executor:

  • roles/storage.admin - to be able to query GCS bucket if that is what you are using to store our TFStates. This is required even before the tf-executor gets to "impersonate" the tf-owner. Hence, we need to provide this bit explicitly. You may further tighten this permission by adding a condition to this role so that it can access only the specific GCS bucket that is dealing with the TFStates

  • roles/iam.serviceAccountTokenCreator - to be able to perform the work of the data block - requesting access token on behalf of another ServiceAccount

  • that's all - nothing more than that

Roles for tf-owner:

  • roles/owner - to be able to create/modify/destroy anything & everything inside your GCP project.

  • or you may consider not giving the owner role at all but instead just the specific admin roles of specific GCloud resources if you want to further tighten the permissions.

Benefits

This actually helps tighten the access and makes sure that the JSON key file that is out there sitting in the internet cannot do anything much by itself - It also has to know additional things like the tf-owner ServiceAccount email address etc to be able to fully exploit its potentials

Watch Out

This certainly doesn't mean it's now OKAY to pay less attention to the security / encryption / storage of the tf-executor ServiceAccount JSON key.

You still gotta do all that. But the risks associated with it being compromised is measurably reduced now.


With inspirations from https://medium.com/wescale/how-to-generate-and-use-temporary-credentials-on-google-cloud-platform-b425ef95a00d
This article originally appeared in https://medium.com/@syedrakib/terraform-on-gcp-impersonating-with-limited-access-on-serviceaccount-9dae6e2be11c

💖 💪 🙅 🚩
syedrakib
Rakib Al Hasan

Posted on April 20, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related