Route53 Resolver Associations, problem with my module

Hey!

Versions

Terraform: 0.12.19
provider.aws: version = “3.2.0”

Background

Could I ask for a bit of guidance on the below?

We’ve started using route53 resolver to handle outbound dns from some of our VPCs.

I turned our configuration into a module which is responsible for the following resources:

  • aws_route53_resolver_endpoint
  • aws_route53_resolver_rule
  • aws_route53_resolver_rule_association

In our AWS account, we want all of the resolver rules to get attached to all VPCs.

Some of my aws_route53_resolver_rule_association resources get recreated, this happens when either a new VPC or a new Resolver Rule are added. I think it’s down to the design of my module but wanted to clarify.

What I’m doing

The resource I’m trying to create is this one:

resource “aws_route53_resolver_rule_association” “rule_to_forwarder” {
depends_on = [aws_route53_resolver_rule.forwarder]
vpc_id = a_vpc_id
resolver_rule_id = a_resolver_rule_id
}

As we want “all_rule_ids x all_vpc_ids”, I added two data sources to get these and return a list:

data “aws_route53_resolver_rules” “all” {rule_type = “FORWARD”} <-- get all forwarding rules, return a list

data “aws_vpcs” “all” {} <-- get all VPC IDs, return a list

Then I created this local variable to get the cartesian product of “all_rule_ids x all_vpc_ids”, loop through and store each combination
in a map.

locals {
all_vpcs_x_all_rules = [
for pair in setproduct(data.aws_vpcs.all.ids, data.aws_route53_resolver_rules.all.resolver_rule_ids) : {
vpc_id = pair[0]
resolver_rule_id = pair[1]
}
]
}

This returns a list of maps which I can loop through in the aws_route53_resolver_rule_association resource like so:

resource “aws_route53_resolver_rule_association” “rule_to_forwarder” {
depends_on = [aws_route53_resolver_rule.forwarder]
for_each = {
for index, pair in local.all_vpcs_x_all_rules : “${index}” => pair
}

vpc_id = each.value.vpc_id
resolver_rule_id = each.value.resolver_rule_id
}

Result

This configuration worked fine, when I first ran it. I recently added a new forwarder rule and the plan showed:

Plan: 46 to add, 0 to change, 38 to destroy.

The delta between 46 / 38 is 8. As I added a new forwarder rule and there are 8 VPC’s I expected the plan to show 8 to add.

So why the 38 to recreate?

Speculation

I have a couple of theories about why this might be, but not sure how to progress:

the data sources aws_route53_resolver_rules & aws_vpcs return unordered lists:

this would mean the all_vpcs_x_all_rules local var would always be a bit of a mess, changing every time the configuration was run. I don’t think this is true because running the job without adding a new resolver_rule_id has always been stable (no changes).

the data sources aws_route53_resolver_rules & aws_vpcs return ordered lists, but the new resolver rule ID could be anywhere in that list

for example say I have: rule_id_1, rule_id_3 and vpc_x

  • the module creates two attachments and stores in terraform state like this:

rule_id_1:vpc_x[0]
rule_id_3:vpc_x[1]

  • then I add a new rule, called rule_id_2
    • the module creates:

rule_id_1:vpc_x[0]
rule_id_3:vpc_x[1] -> rule_id_2:vpc_x[1] #forces replacement
rule_id_3:vpc_x[2]

Judging by it’s behaviour I think the latter is closer but I’m clutching a bit!

Any help is appreciated!