Skip to main content

Use Terraform Provider Block with compatibility for Role ARNs and Profiles

Date: 19 Oct 2021

Needs Update!

The content in this ADR may be out-of-date and needing an update. For questions, please reach out to Cloud Posse

Status

ACCEPTED

Context

Cloud Posse has used 2 conventions for assuming roles within the terraform provider { ... } block.

The role_arn Method

This was our original method of assuming roles within terraform.

provider "aws" {
# The AWS provider to use to make changes in the DNS primary account
alias = "primary"
region = var.region

assume_role {
role_arn = coalesce(var.import_role_arn, module.iam_roles.dns_terraform_role_arn)
}
}

We used this for years together with AWS Federated IAM with SAML and had no issues. Then we started supporting AWS SSO and ran into some issues because with AWS SSO the role names are non-deterministic. As a result, we switched to the profile method below.

The profile Method

With the profile method we offload the burden of determining the role_arn to some external script that would generate the ~/.aws/config with profiles and role mappings. This allowed us to support simultaneously the AWS Federated IAM alongside the AWS SSO method of authentication. The downside was we had to use the generator pattern to create the ~/.aws/config, which we generally like to avoid. We painfully upgraded all of our components to use this method since we didn’t see a path forward with the role_arn method at the time.

provider "aws" {
region = var.region

# `terraform import` will not use data from a data source, so on import we have to explicitly specify the profile
profile = coalesce(var.import_profile_name, module.iam_roles.terraform_profile_name)
}

The Hybrid Method

Now we support the hybrid method after having come full circle and once again wanting to move to use the role_arn everywhere so we do not need to generate the AWS config. However, we also need to support customers that use the profile method. Fortunately, @Jeremy Grodberg found a convenient way to support both methods.

provider "aws" {
region = var.region

profile = module.iam_roles.profiles_enabled ? coalesce(var.import_profile_name, module.iam_roles.terraform_profile_name) : null
dynamic "assume_role" {
for_each = module.iam_roles.profiles_enabled ? [] : ["role"]
content {
role_arn = coalesce(var.import_role_arn, module.iam_roles.terraform_role_arn)
}
}
}

Decision

DECIDED: Use the Hybrid Method to support both profile or role_arn for backward compatibility Note: Until Proposed: Use AWS Federated IAM over AWS SSO is decided otherwise, our recommendation for new projects is to use role_arn, but we continue to use the hybrid provider in public components, and therefore in client components.

Consequences

  • Update all components to use the Hybrid Method.

References