Several of our terraform root modules need add to an existing policy that provides read-only permissions for S3 buckets -- each module has its own bucket. I cannot figure out how to add to the existing policy, and merge new values (the new bucket) into it.
At first, we had just attached a new policy (three actually, one for development, staging, production) to the role. But we can only attach a maximum of 20 policies. So instead, I used the AWS CLI and just listed all the production buckets in one policy, staging, and dev likewise. Cool so far.
Now I want to accomplish the same thing with terraform.
I have created a submodule that the root modules can all call, passing their bucket in.
I can define the new policy as
data "aws_iam_policy_document" "read_only" {
statement {
actions = [
"s3:ListBucket",
"s3:GetObject",
"s3:GetBucketLocation",
]
effect = "Allow"
resources = [
"${var.bucket_arn}/*",
var.bucket_arn,
]
}
}
I can look up an existing policy with
data "aws_iam_policy" "existing" {
name = "read-only-s3-${terraform.workspace}"
}
and potentially merge that with the new policy using
data "aws_iam_policy_document" "merged" {
source_json = [
data.aws_iam_policy_document.read_only.json,
data.aws_iam_policy.existing.json
]
}
and then create the resource
resource "aws_iam_policy" "read_only_policy" {
name = "read-only-s3-${terraform.workspace}"
path = "/"
policy = data.aws_iam_policy_document.merged.json
}
But this fails if there's no data.aws_iam_policy.existing
because AWS cannot find it so terraform fails with an error.
There's a great deal of documentation about how to merge policies in the policy document reference, but there's very little indication of how to determine if there's an existing policy.
I could recreate the entire policy if I could find the existing one and merge it with the new one, or even if I just knew the names of the buckets in the existing policy. But the existing policies are created in other root modules. And there's no way to look up buckets other than by their name (no tags
or filter
on data "aws_s3_bucket"
).
Is there a way to determine that there's an existing policy and get without throwing an error? Then I could get its policy document and use the source_json
approach.
Is there a way that I can merge a new policy document onto whatever exists (or not)?
Open to other approaches. Really would prefer to keep this in IAM and not go to bucket policies because they are so opaque and decentralized.