Search code examples
amazon-web-servicesterraformterraform-provider-awsamazon-ses

How to refer parent resource in child resource when using terraform map (and for_each)


I have the following code which works fine.

resource "aws_ses_email_identity" "main_from_email" {
  email = "[email protected]"
}

data "aws_iam_policy_document" "main_from_email_policy_document" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = [aws_ses_email_identity.main_from_email.arn]

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

resource "aws_ses_identity_policy" "email_notif_policy" {
  identity = aws_ses_email_identity.main_from_email.arn
  name     = "${local.namespace}-ses_main_from_email_policy"
  policy   = data.aws_iam_policy_document.main_from_email_policy_document.json
}

The above code is working fine. But the email is hard coded. I would like to have the (email) resources to be created based on some configuration provided in terraform.tfvars as follows:

clientemails = {
  "client1" = { "email" = "[email protected]" }
  "client2" = { "email" = "[email protected]" }
}

I modified main resource as follows:

resource "aws_ses_email_identity" "main_from_email_map" {
  for_each = var.clientemails
  email    = each.value.email
}

But, I don't know how I can modify "aws_iam_policy_document" and "aws_ses_identity_policy" to follow "aws_ses_email_identity".

How do I modify my terraform script to honor "clientemails" configuration?


Solution

  • This should be relatively straight forward to do:

    resource "aws_ses_email_identity" "main_from_email_map" {
      for_each = var.clientemails
      email    = each.value.email
    }
    
    data "aws_iam_policy_document" "main_from_email_policy_document" {
      statement {
        actions   = ["SES:SendEmail", "SES:SendRawEmail"]
        resources = values(aws_ses_email_identity.main_from_email_map)[*].arn
    
        principals {
          identifiers = ["*"]
          type        = "AWS"
        }
      }
    }
    
    resource "aws_ses_identity_policy" "email_notif_policy" {
      for_each = aws_ses_email_identity.main_from_email_map
      identity = each.value.arn
      name     = "${local.namespace}-ses_main_from_email_policy"
      policy   = data.aws_iam_policy_document.main_from_email_policy_document.json
    }
    

    Here, there will be a single policy which will allow all the same actions for all the SES email identity ARNs. To achieve this, since the SES email identity resource was created using for_each meta-argument, the values built-in function [1] was used to fetch all the values of the ARN attribute for all the keys (hence the [*] part).

    There could be a way to modify the data source with for_each if needed (i.e., to create a policy per client email):

    data "aws_iam_policy_document" "main_from_email_policy_document" {
      for_each = aws_ses_email_identity.main_from_email_map
      statement {
        actions   = ["SES:SendEmail", "SES:SendRawEmail"]
        resources = [each.value.arn]
    
        principals {
          identifiers = ["*"]
          type        = "AWS"
        }
      }
    }
    

    Then, you would also have to fix the SES identity policy:

    resource "aws_ses_identity_policy" "email_notif_policy" {
      for_each = aws_ses_email_identity.main_from_email_map
      identity = each.value.arn
      name     = "${local.namespace}-ses_main_from_email_policy"
      policy   = data.aws_iam_policy_document.main_from_email_policy_document[each.key].json
    }
    

    The code where for_each meta-argument is used with the resources (e.g., aws_ses_email_identity.main_from_email_map) is called for_each chaining [2].


    [1] https://developer.hashicorp.com/terraform/language/functions/values

    [2] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#chaining-for_each-between-resources