7 Days on a 2-Point Story

So, with just a bit of rough estimation, I have about a decade’s worth of experience with developing infrastructure as code with Terraform. You’d think I’d be good with it by now. But then, I pick up a simple looking enough Jira ticket last sprint.

Their system can create one or more interface endpoints in AWS, and they’re currently doing it for S3, and Secrets Manager. So far so good. But that Terraform module is only opening up port 443 to a small number of subnets on the VPC, and they need them to be accessible to all non-production CIDRs.

Here’s where me and the Jira ticket come in. I need to either find the list of non-production CIDRs as a prefix-list , or just let people enter them as configuration. I choose the latter as the prefix list in question didn’t exist in the right AWS accounts. Then I create a new Security Group , add an egress rule to it for each CIDR in question, add an ingress rule it for each CIDR, and here’s where it all fell down. Associate that new Security Group with the interface endpoint.

Problem is, I need the id of each interface endpoint. I’m working inside the module that’s creating it. It’s outputting something it calls a map , all seems well. We’re still on day 1.

All is not well.

That monstrosity of an output data structure isn’t a map. I’m still not sure exactly what it is. A list or tuple for sure. A list with 1 item. Said item is a map I think. That map has 2 separate nested maps. I tried about 100 things to walk into that map to use as a “for_each” in my resource. And nothing worked. And each change I made had to be checked into Git before I could test it due to the nature of our system.

Every team mate I spoke to had different thoughts about how I should approach it. I kept rewriting it in different ways, moved the code from one module to another. Nothing worked. Until I realised there was a simpler, true map, that was being used to configure the mess, and I could just use THAT as my for_each.

The clue was in the description of the output data structure:

Map of Interface VPC Endpoints deployed to this VPC, using keys supplied in var.interface_vpc_endpoints.

In the end, it was these 4 lines of code that did the job.

resource "aws_network_interface_sg_attachment" "sg_attachment" {
  for_each          = { for k, v in var.interface_vpc_endpoints : k => v if length(try(var.workload_testing_cidrs, "")) > 0 }
  security_group_id = aws_security_group.endpoint_workload_testing[0].id
  vpc_endpoint_id   = aws_vpc_endpoint.interface_endpoint[each.key].id
}

FML. That shouldn’t have been so complicated.

Random Food Side Note

I’m currently obsessed with kimchi. Can’t get enough of it and it’s delicious with smoked salmon or prawns.