Sabo Boz
Sabo Boz

Reputation: 2575

how to access all elements of a list variable in the policy argument of aws_iam_user_policy resource in terraform

I have an aws_iam_user_policy resource in terraform as follows:

resource "aws_iam_user_policy" "pol" {
  name = "policy"
  user = aws_iam_user.singleuser.name

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::toybucket-development/*",
        "arn:aws:s3:::toybucket-staging/*",
        "arn:aws:s3:::toybucket-production/*"
      ]
    }
  ]
}
EOF
}

The resources with development, staging and production are something I'm hoping to put in one line through using a list variable with the values development, staging and production and somehow looping through them, but I'm unsure of how to do this within the EOF. I know normally you can loop through such list variable but that's in normal terraform and not when you have this EOF with a string that represents a json. Would anyone know of a solution?

Upvotes: 1

Views: 1740

Answers (2)

Michael Aicher
Michael Aicher

Reputation: 901

I'm a big fan of using the data source aws_iam_policy_document for creating all kind of iam policy like resources. In combination with a locals using the formatlist function you can achieve your desired result.
This could look like this:

locals {
  resource_arns = formatlist("arn:aws:s3:::toybucket-%s/*", ["development", "staging", "production"])
}

data "aws_iam_policy_document" "policy" {
  statement {
    actions   = ["s3:List*"]
    effect    = "Allow"
    resources =  [local.resource_arns]
  }
}

resource "aws_iam_polcy" "pol" {
  name   = "policy"
  user   = aws_iam_user.singleuser.name
  policy = data.aws_iam_policy_document.policy.json
}

Upvotes: 1

Matthew Schuchard
Matthew Schuchard

Reputation: 28854

You can do this most easily with a Terraform template, and the templatefile function. The templatefile function invocation would appear like:

resource "aws_iam_user_policy" "pol" {
  name = "policy"
  user = aws_iam_user.singleuser.name

  policy = templatefile("${path.module}/policy.tmpl", { envs = ["development", "staging", "production"] }
}

The documentation for the function is probably helpful.

The template would appear like:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": [
        %{~ for env in envs ~}
        "arn:aws:s3:::toybucket-${env}/*"%{ if env != envs[length(envs) - 1] },%{ endif }
        %{~ endfor ~}
      ]
    }
  ]
}

That check at the end for adding a comma only if it is not the last element to ensure JSON format syntax is not super great. However, there is no easy check in Terraform DSL for whether a list/slice (latter being implicitly derived from Golang) is the last element, and using jsonencode would require placing the entire ARN in the variable list.

If envs = ["arn:aws:s3:::toybucket-development/*", "arn:aws:s3:::toybucket-staging/*", "arn:aws:s3:::toybucket-production/*"], then you could jsonencode(envs).

Upvotes: 2

Related Questions