Terraform Providers can sometimes be a bit clunky when you are working locally vs what your final pipeline configuration will be. For instance, often an AWS role will be limited to pipeline access and not allowed to be assumed by users for security reasons. Users will have to authenticate with their SSO roles for any actions they perform instead.
While Terraform supports this with the profile = <your-sso-profile>
configuration, this means setting specific values in your local development, remembering to change those before committing/pushing to your project, etc.
Now, there is way you can get the best of both worlds, with dynamic "assume_role"
and some clever logic!
Overview¶
This is a short post, but super useful if you are developing Terraform code you want to work in your pipeline without going back and forth and commenting things in/out for your providers.tf
config.
As an example for using a role with GitLab CI pipelines, you may want to have that role limited to specifically GitLab OIDC identity and not let your developers actually assume that role. This helps ensure security and no one abusing a potentially pervasive and highly permissive role, so that you can have flexible (and auditable) pipeline IAM access.
The challenge is, since you can't assume the role as a developer, how are you supposed to test locally in Terraform? You could comment out the assume_role
block and put in your profile = my-sso-profile
for your specific account.
What if we could instead make it dynamic and allow either and override for local development? You totally can!
Configuration¶
Here's an example of an AWS Provider configuration where we do exactly that.
# variables.tf
variable "region" {
description = "The AWS region where you are deploying resources."
type = string
default = "us-west-2"
}
variable "account_id" {
description = "The 12 digit AWS account ID where resources should be deployed."
type = string
default = ""
}
variable "sso_profile" {
description = "Optional parameter for running locally with AWS SSO profile."
type = string
default = null
}
# providers.tf
provider "aws" {
region = var.region
profile = var.sso_profile
dynamic "assume_role" {
for_each = var.sso_profile != null ? [] : [1]
content {
role_arn = provider::aws::arn_builder("aws", "iam", "", var.account_id, "role/your-terraform-role")
}
}
}
This allows you do export
your SSO profile when working locally, but still let the default pipeline role when running without that variable defined!
Then all you have to do is export TF_VAR_sso_profile=my-sso-profile
, run your terraform
commands, and when you commit / push / run your code in pipelines with your role, nothing has to change! Simple!