# Route53 Resolver (Inbound/Outbound) ========================================== # Resolver Endpoints ----------------------------------------------------------- # Shared resource type for both directions; caller sets `direction` per entry. # INBOUND endpoints let external resolvers query into this VPC. # OUTBOUND endpoints let this VPC forward queries to external DNS servers. resource "aws_route53_resolver_endpoint" "this" { for_each = var.endpoints direction = each.value.direction resolver_endpoint_type = each.value.endpoint_type name = "${var.name_prefix}-${local.region_abbr}-resolver-ep-${each.value.endpoint_name_suffix}" security_group_ids = each.value.security_group_ids dynamic "ip_address" { for_each = each.value.interfaces content { subnet_id = ip_address.value.subnet_id ip = ip_address.value.ip } } tags = merge(var.tags, each.value.tags, local.module_tags, { Name = "${var.name_prefix}-${local.region_abbr}-resolver-ep-${each.value.endpoint_name_suffix}" resource-type = "r53-resolver-endpoint" }) lifecycle { precondition { condition = length("${var.name_prefix}-${local.region_abbr}-resolver-ep-${each.value.endpoint_name_suffix}") <= 64 error_message = "Assembled resolver endpoint name for '${each.key}' exceeds AWS's 64-character limit." } } } # Resolver Rules =============================================================== # Only meaningful for OUTBOUND endpoints. Forwards queries for domain_name # to the specified target IPs via the associated resolver endpoint. resource "aws_route53_resolver_rule" "this" { for_each = var.rules domain_name = each.value.domain_name rule_type = each.value.rule_type resolver_endpoint_id = aws_route53_resolver_endpoint.this[each.value.endpoint_key].id name = "${var.name_prefix}-${local.region_abbr}-resolver-rule-${each.value.rule_name_suffix}" dynamic "target_ip" { for_each = each.value.target_ips content { ip = target_ip.value.ip port = target_ip.value.port } } tags = merge(var.tags, each.value.tags, local.module_tags, { Name = "${var.name_prefix}-${local.region_abbr}-resolver-rule-${each.value.rule_name_suffix}" resource-type = "r53-resolver-rule" }) lifecycle { precondition { condition = var.endpoints[each.value.endpoint_key].direction == "OUTBOUND" error_message = "endpoint_key '${each.value.endpoint_key}' for rule '${each.key}' must reference an OUTBOUND endpoint." } precondition { condition = length("${var.name_prefix}-${local.region_abbr}-resolver-rule-${each.value.rule_name_suffix}") <= 64 error_message = "Assembled resolver rule name for '${each.key}' exceeds AWS's 64-character limit." } } } # Rule Associations ============================================================= # Associates each rule with one or more VPCs. Flattened since a rule can # target multiple VPCs and each association is its own resource. resource "aws_route53_resolver_rule_association" "this" { for_each = { for pair in flatten([ for rule_key, rule in var.rules : [ for vpc_id in rule.vpc_ids : { key = "${rule_key}-${vpc_id}" rule_id = rule_key vpc_id = vpc_id } ] ]) : pair.key => pair } resolver_rule_id = aws_route53_resolver_rule.this[each.value.rule_id].id vpc_id = each.value.vpc_id }