Reputation: 123
We are using Terraform to store secrets inside AWS secrets manager. We would like to expand our Terraform to add resource access policy to each secret to only allow certain IAM roles or user access the secret and get it is value. We are defining each secret and it is metadata using YAML. Terraform will then decode the yaml and store all the contents in a map. We then have a for_each to iterate through each map and create the secrets. Below is the yaml definition for a secret
nonprod:
- name: my-super-secret
metadata:
description: my-super-secret
value: somesecret
policy: true #This is the feature we trying to add. It will tell TF to add resource access policy
iam_roles:
- "arn:aws:iam::account-id:role/sagemaker"
- "arn:aws:iam::account-id:user/jon.doe"
- "arn:aws:iam::account-id:role/test"
tags:
purpose: sagemaker
The YAML is decoded and then stored in a var.secrets
map. Using TF console this is what TF store in var.secrets after decoding YAML.
{
"metadata" = {
"description" = "my-super-secret"
}
"name" = "my-super-secret"
"policy" = true
"iam_roles" = [
"arn:aws:iam::account-id:role/sagemaker",
"arn:aws:iam::account-id:user/jane.doe",
"arn:aws:iam::account-id:role/test",
]
"tags" = {
"purpose" = "sagemkaer"
}
"value" = "somesecret"
}
on the main.tf
file, I added the following code for the IAM policy document:
data "aws_iam_policy_document" "example" {
for_each = { for item in var.secrets : item.name => item }
statement {
sid = "EnableAccessFor${each.value.name}"
principals {
type = "AWS"
identifiers = [lookup(each.value, "iam_roles")]
}
actions = [
"secretsmanager:GetSecretValue",
]
resources = [
"*",
]
}
}
then I am passing the policy document to aws_secretsmanager_secret_policy
resource to attach the policy to the secret that has policy
set as true
resource "aws_secretsmanager_secret_policy" "policy" {
depends_on = [aws_secretsmanager_secret.secret]
for_each = { for item in var.secrets : item.name => item }
secret_arn = each.key
policy = data.aws_iam_policy_document.example.json
}
no matter what way I use, I always get errors when I run a plan. I have used the following functions with no luck:
join
, concat
, toset
, splat
, jsonencode
and for expressions
I get the following errors:
identifiers = [for r in lookup(each.value, "iam_roles") : r]
produces this error: Invalid value for "inputMap" parameter: the given object has no attribute "iam_roles"
identifiers = "${each.value[*].iam_roles}"
produces this error: Inappropriate value for attribute "identifiers": element 0: string required.
toset
with lookup
identifiers = "${toset(lookup(each.value, "iam_roles", ""))}"
produces this error Invalid value for "v" parameter: cannot convert string to set of any single type.
join
with lookup
identifiers = ["${join(", ", lookup(each.value, "iam_roles", ""))}"]
produces this error Invalid value for "lists" parameter: list of string required.
jsonencode
identifiers = [jsonencode(each.value.iam_roles)]
produces this error This object does not have an attribute named "iam_roles".
each.value
without lookup
identifiers = [each.value.iam_roles]
produces this error Inappropriate value for attribute "identifiers": element 0: string required.
Any idea?
Update
I got rid of the iam_policy_document
and instead opt-in to use the aws_secretsmanager_secret_policy resource with a json-policy. See example below:
resource "aws_secretsmanager_secret_policy" "policy" {
depends_on = [aws_secretsmanager_secret.secret]
for_each = { for item in var.secrets : item.name => item if try(item.policy, false)}
secret_arn = aws_secretsmanager_secret.secret[each.key].arn
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnableAccessFor${each.value.name}",
"Effect": "Allow",
"Principal": {
"AWS": [
"${join(",", formatlist("\"%s\"", each.value.iam_roles))}"
]
},
"Action": "secretsmanager:GetSecretValue",
"Resource": "*"
}
]
}
POLICY
}
The part I am having issue is with the each.value.iam_roles
as that is a tuple vs. a string. I tried multiple ways to convert that into string but it is not working. Perhaps someone can help me with that.
Upvotes: 0
Views: 965
Reputation: 123
issue was resolved with encoding the entire policy to JSON using the `jsonencode function in Terraform.
Upvotes: 0