In the documentation for aws_iam_user_policy
at the time of this answer the main usage example shows setting policy
like this:
# Terraform's "jsonencode" function converts a
# Terraform expression result to valid JSON syntax.
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ec2:Describe*",
]
Effect = "Allow"
Resource = "*"
},
]
})
Notice that it recommends using the jsonencode
function to produce the entire value, rather than trying to construct JSON from parts via template concatenation, since that ensures that the result will always be valid JSON syntax.
It also has the benefit that you can use any expressions you need to make dynamic decisions about the data structure. In your case you already have a dynamic reference to the user's email address from a variable, so let's start by translating what you have into a form more like the example in the documentation:
policy = jsonencode({
Version = 2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ses:SendEmail",
"ses:SendRawEmail",
]
Resource = "*"
Condition = {
StringEquals = {
"ses:FromAddress" = [
var.user_email_address,
]
}
}
}
]
})
Notice that the value is now written in Terraform's own expression syntax, rather than JSON syntax. Terraform will construct the valid JSON syntax itself as part of evaluating the jsonencode
function call.
Your new requirement is to omit Condition
entirely in certain cases. To describe that requirement as a Terraform expression requires merging the object which describes the parts that are always present (Effect
, Action
, and Resource
) with another expression which describes the optional parts.
For example:
policy = jsonencode({
Version = 2012-10-17"
Statement = [
merge(
{
Effect = "Allow"
Action = [
"ses:SendEmail",
"ses:SendRawEmail",
]
Resource = "*"
},
coalesce(var.condition ? {
Condition = {
StringEquals = {
"ses:FromAddress" = [
var.user_email_address,
]
}
}
} : null, {}),
)
]
})
What I've changed here is a bit subtle and perhaps hard to see with all of the other content that didn't change, so here's a cut down version with some of the previous elements replaced by comments just to make the new content more prominent:
policy = jsonencode({
Version = 2012-10-17"
Statement = [
merge(
{
# (common attributes here)
},
coalesce(var.condition ? {
# (conditional attributes here)
} : null, {}),
)
]
})
The merge
function takes multiple objects and returns a single object containing the elements from all of them taken together. In this case, the second argument to merge
is a more complex expression which produces either an object with a Condition
attribute or an empty object depending on the condition value. Merging an empty object into an object changes nothing about the result, and so in this case the condition controls whether that second argument will contribute any attributes at all.