iam_gcp_sa_terraform

1 June 2023

Learn how to manage IAM in Google Cloud Platform (GCP) using Service Account (SA) impersonation in Terraform. This article explores how to secure your infrastructure and in particular the IAM management in GCP by granting temporary access to specific resources through SA impersonation in Terraform.

IAM and service account impersonation

Reminder on Terraform

Terraform is an Infrastructure as Code (IaC) tool that enables you to define and manage your infrastructure resources using code. Terraform provides a simple and consistent way to create and manage resources across multiple cloud providers.

Using Terraform, you can define your infrastructure in code, version control it, and deploy it in a consistent and repeatable way. Terraform supports multiple cloud providers, including GCP, and it integrates well with other tools and services. Terraform allows you to automate your infrastructure deployment and management, thus reducing the risks of manual errors and inconsistency.

Reminder on Identity and Access Management

Identity and Access Management (IAM) enables you to manage users’ permissions and control who has access to which resources in your infrastructure. IAM is a crucial part of your environments’ security in GCP (Google Cloud Platform) as in any cloud provider. However, managing it can be challenging, especially when dealing with multiple users and services.

One way to simplify IAM management is to use Service Accounts (SA) and impersonation in Terraform. This approach allows you to grant temporary access to specific resources, thus reducing the risks of over-permissioning or under-permissioning.

What is Service Account impersonation?

A Service Account is a Google Cloud identity used by an application or service to authenticate with GCP APIs. Service Accounts provide a secure way to authenticate and authorize access to GCP resources without using a user account.

You can grant them permission to resources within a project or across multiple projects. Each of them is associated with a private key that can be used to authenticate API requests.

However, there may be situations where you need to grant temporarily restricted access to a resource without providing the user with the SA's private key. This is where SA impersonation comes in.

Service Account impersonation is a feature in GCP that allows you to grant access to a resource by delegating the permissions of a service account to a user or another service account, without disclosing the SA's private key.

When you impersonate a Service Account, you assume the identity of that account and can perform actions on behalf of that account. Therefore, you do not need access to the service account key material to authorize requests in Google Cloud.

Why is Service Account impersonation useful for Security?

With Service Account impersonation, you can reduce the risks of over-permissioning or under-permissioning, as you can grant access to specific resources for a limited time frame.

The user’s authorization will be controlled by the permissions assigned to the service account. If a user no longer requires access to the service account, all that is required is to remove the binding. The service account is not impacted and remains protected.

Service Account impersonation is essential for security because it reduces the attack surface and limits the potential impact of security breaches.

In addition, service account impersonation increases the traceability of some actions as only audit logs from the service account impersonated gather all events. This traceability improvement can be very useful for audit or forensic for example.

Strategy to manage IAM in a secure way with SA impersonation

Service account impersonation is a way to manage IAM in a secure way because it will enable one to not use some DevSecOps Engineer’s own credentials that are more prone to being compromised through phishing attacks or other means.

In contrast, SAs are specific to a project and have limited permissions, thus reducing the risk.

In the meantime, be aware that this method adds complexity and maintainability and should therefore not be used to manage all services in your infrastructure but only some very sensitive ones as IAM!

After these reminders about IAM and service account theory, we can go in-depth with the use of these concepts to manage IAM in a secure and streamlined way.

The strategy that will be explained below consists of the following steps:

  • Implement SA impersonation
    • Create a service account with the permissions to create the IAM resources you want to manage (IAM roles, permissions, bindings…)
    • Grant your user the right to impersonate your service account
  • Use SA impersonation to manage IAM
    • Add a specific provider for IAM
    • Create the terraform module with IAM resources that will be applied by SA impersonation
    • Apply your IAM terraform module

Implement SA impersonation through Terraform

Impersonation is supported in Terraform version 0.12 and later.

⚠️ The number of users having access to the IaC Terraform code that you will be creating with the following steps must be limited as any modification in code could lead to a privilege escalation.

A way to limit access could be, for example, by having it on a separate repository with only the security team authorized and protection on main branches.

Step 1: Create a Service Account and grant it the necessary permissions

To implement SA impersonation, you'll first need to create a service account that will be impersonated by your user. This one will need to have the necessary permissions to manage IAM roles and permissions in your project.

  • Use the google_service_account terraform resource to create a service account
  • Bind this service account to a role that contains the necessary permissions to manage IAM permissions and roles, such as roles/resourcemanager.projectIamAdmin or roles/iam.securityAdmin. Both of these roles are predefined roles from GCP, take the time to list what resources you want to manage through your service account to take the least privileged role you need. I recommend using the roles/resourcemanager.projectIamAdmin role whenever possible because he is less privileged and therefore safe. But this role may not be enough for your usage as, for example, it does not contain the rights to create custom roles. ⚠️ Granting excessive permissions to your service account can be a security risk.

The following Terraform code is created for the two resources described above:

resource "google_service_account" "iam_sa" {
  account_id   = "service-account-id"
  display_name = "IAM management Service Account"
}

resource "google_project_iam_binding" "iam_sa_binding" {
  project = var.project_id
  role    = "roles/resourcemanager.projectIamAdmin"

  members = [
    "serviceAccount:${google_service_account.iam_sa.email}"
  ]
}

Step 2: Impersonate the service account

Next, you'll need to grant your user the right to impersonate the service account created in Step 1.

To do this, you'll need to use the google_service_account_iam_binding resource in Terraform to grant your user the necessary permissions to impersonate the service account. Here's an example:

resource "google_service_account_iam_binding" "impersonate_sa" {
  service_account_id = "google_service_account.iam_sa.id"
  role               = "roles/iam.serviceAccountTokenCreator"

  members = [
    "user:<user-email>"
  ]
}

The iam.serviceAccountTokenCreator role can be granted at the project level and therefore gives you the right to impersonate any service account on the project but it would not follow the principle of least privilege.

That is to limit the risks that the code shown above grants the role only at the service account level.

The one GCP feature that allows this type of management relies on the roles/iam.serviceAccountTokenCreator and terraform google provider scopes (that will be explained in the next part).

Use SA impersonation to manage IAM

Now that you have set up a Service Account for impersonation in Terraform, you can use it to manage IAM roles and permissions in GCP.

By default, Terraform uses the default application credentials to authenticate with GCP APIs. The default application credentials are typically the credentials of the user running the Terraform command.

To use the authorizations of a Service Account instead of the user’s, you need to follow these steps:

Step 1: Add a specific provider

As said above, without further configuration, the default google provider will use the user credentials to run Terraform resources. To use impersonation, we need to define an extra provider block that will use the service account authorization.

This extra block contains two providers:

  • The first provider is still a google provider (with an impersonation alias to differentiate it). It will only be used to get google_service_account_access_token data. Google scopes used in the provider are needed to request to access specific Google API, all available scopes are described in GCP documentation.

We then use the google_service_account_access_token data source thanks to impersonation provider to fetch the service account token. In the example, the token lifetime is set to 600s (=10min). You can increase or decrease it’s lifetime depending on your terraform plan and apply elapsed time.

⚠️ If your lifetime is too short, the token could expire during your Terraform apply and make it fail! To prevent a fail, you can start with a very long lifetime and decrease it accordingly after you know how long took your terraform plan and apply.

  • Finally, we define a second google provider (with iam alias) that will authenticate thanks to the service account token we retrieved. This provider is the one that will be used to apply resources thanks to impersonation.

To sum up, the impersonation provider will enable you to get the service account authentication information. And the iam provider will enable you to create resources with Terraform thanks to the service account.

provider "google" {
  project = "<my-project>"
  region  = "<my-region>"
}

## Transitive provider to get Service Account Token
provider "google" {
  alias   = "impersonation"
  project      = "<my-project>"
  region       = "<my-region>>"
  scopes = [
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/userinfo.email",
  ]
}

data "google_service_account_access_token" "iam" {
  provider               = google.impersonation # References the impersonation provider to retrieve service account token
  target_service_account = "<my-serviceaccount-id>"
  scopes                 = ["userinfo-email", "cloud-platform"]
  lifetime               = "600s"
}

## Provider for IAM management
provider "google" {
  alias        = "iam"
  project      = "<my-project>"
  region       = "<my-region>"
  access_token = data.google_service_account_access_token.iam.access_token
}

This code example is from a provider.tf file and it will allow you to use the iam provider to create Terraform resources.

Step 2: Create a Terraform module for IAM management

The next step is to create the Terraform module that defines the resources you want to manage through the service account permissions. In this case, you want to manage IAM roles and permissions.

The following code snippet shows you a resource that allows binding between a role and a group of users that your user should not have the right to apply through its own credentials. We, therefore, add the IAM provider to manage this resource through the service account authorizations.

You can add to your module all resources concerning your IAM administration along with this resource.

resource "google_project_iam_member" "this" {
  provider = google.iam # References the iam provider to impersonate the Service Account
  project = "<my-project>"
  role    = "<my-role>"
  member  = "group:<my-group>"
}

Step 3: Manage IAM with SA impersonation

The final step is to deploy the Terraform module using the terraform apply command. Any Google Cloud resources your Terraform code creates with the google.iam provider will use the service account instead of your own credentials without the need for your user to have the IAM permissions. And any resources without a provider parameter defined will use the default google provider.

You could define the IAM provider as the default one by getting rid of the iam alias but be sure that you are placed on a layer where all your resources need to be applied through service account impersonation.

Conclusion

Terraform can be used to automate the deployment and management of IAM in GCP. However, to ensure security, it's essential to manage IAM roles and permissions correctly as it is an essential aspect of GCP security.

By using impersonation, the code becomes portable and is easily used to apply resources with Terraform. It also allows to easily grant or revoke access by removing the Token creator role to the user by an administrator.

Therefore, service account impersonation in Terraform provides a secure and simplified way to manage IAM in GCP. It allows you to grant temporary access to a resource by delegating the permissions of an SA to a user, without disclosing the SA's private key.

This is an important security feature that can help ensure the security of your GCP resources.

In this article, we worked with the roles/iam.serviceAccountTokenCreator and terraform google provider scopes to implement service account impersonation. We used these GCP features to manage IAM resources because of the high-security risk they represent, and the method can be replicated for any other needs.