Home > OS >  Dynamically refer to a Terraform data resource by variable containing its name
Dynamically refer to a Terraform data resource by variable containing its name

Time:10-17

I'm trying to concatenate a declared variable within the Terraform data assignation to build a dynamic call.

Having the following code:

# Policy 1
data "aws_iam_policy_document" "1_s3_access_policy" {
   statement {
     effect = "Allow"
     actions = [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
     ]
     resources = [
      "arn:aws:s3:::1_s3_access_policy/*",
      "arn:aws:s3:::1_s3_access_policy",
     ]
     principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::67435677645:user/d2c-user-us-west-1"]
     }
   }
 }
# policy 2
data "aws_iam_policy_document" "2_s3_access_policy" {
    statement {
     effect = "Allow"
     actions = [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
     ]
     resources = [
      "arn:aws:s3:::2_s3_access_policy/*",
      "arn:aws:s3:::2_s3_access_policy",
     ]
     principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::67435677645:user/d2c-user-us-west-1"]
     }
   }
 }
# Policy 3
...
variable "s3_bucket_names" {
      type    = list(any)
      default = ["1_s3_access_policy", "2_s3_access_policy", "3_s3_access_policy"]
}

module "platform-cloud" {
      source              = "./module"
      count               = length(var.s3_bucket_names) //count will be 3
      bucket_name         = var.s3_bucket_names[count.index]
      sse_algorithm       = "aws:kms"
      iam_policy_document =  data.aws_iam_policy_document.${var.s3_bucket_names[count.index]}.json
}

It's failing with error:

Error: Invalid character

on main.tf line 10, in module "platform-cloud":

iam_policy_document = data.aws_iam_policy_document.${var.s3_bucket_names[count.index]}.json

This character is not used within the language.

Is there a way to concatenate a variable within terraform data call?

CodePudding user response:

Normally you would do this as follows:

iam_policy_document =  data.aws_iam_policy_document[var.s3_bucket_names[count.index]].json

Exact details would depend on how data.aws_iam_policy_document is defined. But sadly such information is not given in your question.

CodePudding user response:

Terraform cannot dynamically look up a resource in the way you are attempting because that would mean that the resource dependency would not be decided until evaluation time, but Terraform needs to know the correct dependency order before evaluating any expressions.

However, you can meet your use-case of dynamically selecting a resource with the extra step of creating a mapping using the keys that you'll then use to select each one:

locals {
  bucket_policies = {
    s3_access_policy_1 = data.aws_iam_policy_document.s3_access_policy_1
    s3_access_policy_2 = data.aws_iam_policy_document.s3_access_policy_2
    s3_access_policy_3 = data.aws_iam_policy_document.s3_access_policy_3
  }
}

module "platform-cloud" {
  source = "./module"
  count  = length(var.s3_bucket_names) //count will be 3

  bucket_name         = var.s3_bucket_names[count.index]
  sse_algorithm       = "aws:kms"
  iam_policy_document = local.bucket_policies[var.s3_bucket_names[count.index]].json
}

I have changed the names of your data resources to be like s3_access_policy_1 instead of 1_s3_access_policy because Terraform does not allow resource names to start with digits. Terraform isn't reporting that error message yet because you have a syntax error, but resolving the syntax error would've then exposed the naming error.

Notice that now module.platform-cloud's iam_policy_document refers to the whole of local.bucket_policies, which in turn depends on all three of the data resources. Terraform therefore understands that it must evaluate all three of those data resources before evaluating that module argument, which produces a correct evaluation order.


Although not directly related to your question, I'd recommend reading When to use for_each instead of count to decide whether it might be better to use for_each in your module "platform-cloud" block, instead of count.

  • Related