3
votes

I'm trying to write an internal module using Terraform 0.13 that allows for the caller to choose one or more prewritten policy documents at call time. What I'd like to do is define each policy as a data.iam_policy_document, and conditionally include/merge them into the resulting policy as multiple statements. None of the examples I've found seem to quite do this, and most of the IAM related modules in the registry just rely on the parent module passing the complete policy statement, but my goal is for the user of the module to not need to understand how to write proper IAM policies.

My thought was the easiest way would to be to merge the .json versions of the policy documents and pass that to the iam_policy resource, but that didn't seem to work well with having the policy document controlled via a count ternary, and I realize this is maybe the wrong approach entirely.

The desired result of using the module is the creation of a single role, with an appropriate trust policy, that has access to the chosen group of services, and to not create any unused and uneeded resources (extra policies that remain unattached, etc)

1
How many policies are you dealing with? It would be a lot easier in Terraform to attach multiple policies to a single role than it would be to combine the policy documents somehow. Otherwise I think you may want to split out the statement portions into separate JSON strings, and then combine them into a single string based on what you need.Mark B

1 Answers

2
votes

The aws_iam_policy_document is primarily for defining entirely new policies, but for this sort of task of wrangling existing policies (which may or may not have been created with aws_iam_policy_document, I suppose) I think it would be easier to decode the policy JSON using jsondecode and then work with those resulting data structures before merging the result back together again.

That could get complicated if the policies can potentially be interdependent or conflict with one another, but if you can assume that all of the policies will be independent of each other then you could potentially just concatenate together the Statement arrays from each document.

For example:

variable "iam_policies_json" {
  type = list(string)
}

locals {
  iam_policies = [for src in var.iam_policies_json : jsondecode(src)]
  iam_policy_statements = flatten([
    for policy in local.iam_policies : policy.Statement
  ])
  merged_policy = jsonencode({
    Version   = "2012-10-17"
    Statement = local.iam_policy_statements
  })
}

The above just unconditionally merges all of them together, but once you have data structures like the local.iam_policy_statements here you can potentially use other Terraform expression constructs, such as for expressions with if clauses, to conditionally filter out any policies you don't want to include in the result.