1
votes

I am learning about terraform modules and my objective is to build module which takes in a collection of s3 Buckets, and then creates and applies to them some iam policies.

What I have tried so far was to have some sort of a for loop, where I generate the policies and attach them to the buckets. For reference, my code looks something like this:

data "aws_iam_policy_document" "foo_iam_policy" {
  statement {
    sid       = ""
    effect    = "Allow"
    resources = [
    for arn in var.s3_buckets_arn :
    "${arn}/*"
    ]

    actions = [
      "s3:GetObject",
      "s3:GetObjectVersion",
    ]
  }

  statement {
    sid       = ""
    effect    = "Allow"
    resources = var.s3_buckets_arn
    actions = ["s3:*"]
  }
}


resource "aws_iam_policy" "foo_iam_policy" {
  name        = "foo-iam-policy"
  path        = "/"
  description = "IAM policy for foo to access S3"
  policy      = data.aws_iam_policy_document.foo_iam_policy.json
}

data "aws_iam_policy_document" "foo_assume_rule_policy" {
  statement {
    effect  = "Allow"
    actions = [
      "sts:AssumeRole"]

    principals {
      type        = "AWS"
      identifiers = [
        var.foo_iam_user_arn]
    }
    condition {
      test     = "StringEquals"
      values   = var.foo_external_ids
      variable = "sts:ExternalId"
    }
  }
}

resource "aws_iam_role" "foo_role" {
  name               = "foo-role"
  assume_role_policy = data.aws_iam_policy_document.foo_assume_rule_policy.json
}

resource "aws_iam_role_policy_attachment" "foo_attach_s3_policy" {
  role       = aws_iam_role.foo_role.name
  policy_arn = aws_iam_policy.foo_iam_policy.arn
}

data "aws_iam_policy_document" "foo_policy_source" {
  for_each = toset(var.s3_buckets_arn)
  //  arn = each.key
  statement {
    sid    = "VPCAllow"
    effect = "Allow"

    resources = [
      each.key,
      "${each.key}/*",
    ]

    actions = [
      "s3:*"]

    condition {
      test     = "StringEquals"
      variable = "aws:SourceVpc"
      values   = [
        "vpc-01010101"]
    }

    principals {
      type        = "*"
      identifiers = [
        "*"]
    }
  }
}

I don't know if what I have tried makes much sense, or if there is a better way to loop through buckets and generate policies. My question is: what is the best practice for such cases where one wants to provide a list of buckets and loop through them to attach policies?

On a side note, I have encountered an error with my approach:

The “for_each” value depends on resource attributes that cannot be determined (Terraform)

1

1 Answers

1
votes

To attach a bucket policy to a bucket you should use aws_s3_bucket_policy, not aws_iam_policy_document. Also if the buckets already exist, probably it would be better to fetch their data first using data source aws_s3_bucket:

data "aws_s3_bucket" "selected" {
  # s3_buckets_names easier to use then s3_buckets_arns 
  for_each = toset(var.s3_buckets_names)

  bucket = each.value
}

Then, you can iterate over the selected buckets and add your policy to it:

resource "aws_s3_bucket_policy" "bucket_policie" {

  for_each = data.aws_s3_bucket.selected

  bucket = each.key

  policy = "your policy document"
}