How can I attach a generic policy to more than 1 bucket, while having the bucket arn dynamically?

Viewed 115

I am learning terraform and currently attempting to attach a policy to a created bucket. More specifically, the policy I want to attach has the same permissions/structure but the only difference is the resources section. I will illustrate with an example:

Let's say I create an s3 bucket like:

module "happy_bucket" {
  source = "outer space"
  name   = "happy-bucket"
}

And another bucket like:

module "sad_bucket" {
  source = "outer space"
  name   = "sad-bucket"
}

And now I have a policy that looks like:

data "aws_iam_policy_document" "some_policy" {
  statement {
    effect = "Allow"
    resources = [module.some_bucket.bucket_arn]
    actions = ["s3:GetObject", "s3:GetObjectVersion"]
  }
}

And now I would like to attach "some_policy" to both "sad-bucket" and "happy-bucket". But I want to do that without having to repeat myself by creating the policy two times (because I need the .bucket_arn to be based on the bucket). In other words, I want to create one generic policy, and attach it to the 2 buckets I created (while picking up the arn dynamically).

1 Answers

Bucket policies require principals, so you need to add that to your some_policy. Having said that, if you want to keep using aws_iam_policy_document you use for_each to iterate over your buckets.

For example, if your module is:

variable "name" {}

resource "aws_s3_bucket" "b" {
  bucket = var.name
}


output "bucket_arn" {
    value = aws_s3_bucket.b.arn
}

output "bucket_name" {
    value = aws_s3_bucket.b.id
}

then in parent module, you can:



module "happy_bucket" {
  source = "./modules/buckets"
  name = "happy-bucket-231123124ff"
}

module "sad_bucket" {
  source = "./modules/buckets"
  name = "sad-bucket-231123124ff"
}

locals {
  my_buckets = {for bucket in [module.happy_bucket, module.sad_bucket]: 
                bucket.bucket_name => bucket}
}

data "aws_iam_policy_document" "some_policy" {

  for_each = local.my_buckets

  statement {
    effect = "Allow"
    resources = ["${each.value.bucket_arn}/*"]
    actions = ["s3:GetObject", "s3:GetObjectVersion"]
    principals {
        type = "AWS"
        identifiers = ["*"]
    }
  }  
}

resource "aws_s3_bucket_policy" "bucket_policie" {

  for_each = local.my_buckets

  bucket = each.key

  policy = data.aws_iam_policy_document.some_policy[each.key].json

}

Related