Reputation: 536
I'm currently working on an AWS terraform project where I have an array of ROLE IDs (as variables) for different accounts.
variable "slave_account_id" {
default = ["5686435678", "9889865446"]
}
Each of these roles allow a my current AWS account (linked with terraform) to deploy a module on those accounts (assuming for each account the role id)
Thus, I would like to create different providers for each role based on the variable array "slave_account_id".
I tried to do it this way:
provider "aws" {
counter = "${length(var.slave_account_id)}"
alias = "aws-assume-${counter.index}"
region = "eu-west-1"
assume_role {
role_arn = "arn:aws:iam::${var.slave_account_id[counter.index]}:role/slave_role_for_master"
session_name = "${var.slave_session_name[counter.index]}"
external_id = "EXTERNAL_ID"
}
}
This way I would have planned to use this code inside my module:
module "my_super_module" {
counter = "${length(var.slave_account_id)}"
providers = {
aws = "aws.aws-assume-${counter.index}"
}
[...]
}
But this doesn't work (from what I understood I cannot 'concatenate" variable inside the alias of a provider because provider has to be defined before we can interpolate). Here is the execution result (error du to alias section of the provider):
Error: Invalid provider configuration alias
An alias must be a valid name. A name must start with a letter and may contain
only letters, digits, underscores, and dashes.
Error: Duplicate provider configuration
on main.tf line 5:
5: provider "aws" {
A default (non-aliased) provider configuration for "aws" was already given at
main.tf:1,1-15. If multiple configurations are required, set the "alias"
argument for alternative configurations.
Error: Unsuitable value type
on main.tf line 8, in provider "aws":
8: alias = "aws-assume-${counter.index}"
Unsuitable value: value must be known
Error: Variables not allowed
on main.tf line 8, in provider "aws":
8: alias = "aws-assume-${counter.index}"
Variables may not be used here.
Error: Invalid provider configuration reference
on main.tf line 33, in module "my-lambda":
33: aws = "aws.aws-assume-${counter.index}"
A provider configuration reference must not be given in quotes.
Hence I am a bit lost...
How to deploy a module with a list of role ids (one module for each account) ?
Upvotes: 2
Views: 4530
Reputation: 74694
Provider configurations in Terraform are not dynamically-constructable (that is, to decide which to create based on a value) because Terraform needs to associate providers with resources very early in the lifecycle, during graph construction and before expression evaluation is possible.
Instead, we can refactor the problem so that each module takes a fixed number of AWS providers (most often one, but in some cases two if the module's purpose is e.g. to set up peering between two regions or two accounts) and then instantiate the module multiple times in the root:
provider "aws" {
alias = "eu-west-1_5686435678"
region = "eu-west-1"
assume_role {
role_arn = "arn:aws:iam::acct5686435678:role/admin"
session_name = "whatever_session_name"
external_id = "EXTERNAL_ID"
}
}
provider "aws" {
alias = "eu-west-1_9889865446"
region = "eu-west-1"
assume_role {
role_arn = "arn:aws:iam::acct9889865446:role/admin"
session_name = "whatever_session_name"
external_id = "EXTERNAL_ID"
}
}
module "acct5686435678" {
source = "./modules/aws-account"
providers = {
aws = aws.eu-west-1_5686435678
}
}
module "acct9889865446" {
source = "./modules/aws-account"
providers = {
aws = aws.eu-west-1_9889865446
}
}
module "peering_5686435678_9889865446" {
source = "./modules/aws-account-peering"
providers = {
aws.from = aws.eu-west-1_5686435678
aws.to = aws.eu-west-1_9889865446
}
}
Instantiating the same module multiple times is a common technique for situations where the same infrastructure must be created over multiple AWS accounts or over multiple AWS regions.
With that said, if the multiple AWS accounts are representing separate environments rather than separate components within an environment, it's often preferable to use a separate root configuration per environment while still sharing modules, so that updates to each environment are entirely separated, each environment has its own state, etc.
Upvotes: 5