Terraform on GoogleCloud - impersonating with short-lived AccessTokens & ServiceAccounts
Rakib Al Hasan
Posted on April 20, 2020
Your Current Setup
- you have a Google Cloud Platform (GCP) project
- you have a Terraform script
- you have the JSON Key of a ServiceAccount in your Terraform script
- 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
Some things to note in the script above
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
there is a google provider with an alias
there is a google provider without aliasthe aliased google provider uses the
tf-executor
ServiceAccount via its JSON key filethe 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 minutesthis 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.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-
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
- mentioning
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 thetf-executor
gets to "impersonate" thetf-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 TFStatesroles/iam.serviceAccountTokenCreator
- to be able to perform the work of the data block - requesting access token on behalf of another ServiceAccountthat'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
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
April 20, 2020