Nesting for_each loops and configuring multiple regions in Python

Viewed 23

We have a long(ish) list of ip addresses to trust, for services published by CloudFlare, and rather than asking each team that publishes a service from an account in aws to implement this in their security groups / acls etc. I thought a prefix list would be perfect. I would like to set this up in a central account, that is then shared to all the child accounts across the aws Organisation. Ideally, I would like to avoid declaring more resources than necessary, so I am using for_each loops and a dynamic entry. So far so good. However, prefix lists are not a global object, meaning they need to be created per region, and Terraform requires that this is set on the Provider level. Is there a way to have a single resource declaration work with a single local map to dynamically manage all these moving parts? It seems the fewest steps I can do, is to have a resource declaration per region, and then a local map per provider, which is already making 6 "blocks" for only 3 regions, + 2 lists for ipv4 and ipv6...

Here's the code example:

locals {
    # The two ip lists to add to appropriate prefix lists
    cloudflare-ips = {
        prefixlist_cloudflare_ipv4 = {
            ips = [
                "10.0.0.0/32",
                "173.245.48.0/20",
                ...
            ],
            type    =   "IPv4",
        },
        prefixlist_cloudflare_ipv6 = {
            ips = [
                "2400:cb00::/32",
                "2606:4700::/32",
                ...
            ],
            type    =   "IPv6",
        }
    }
}

# Generate multipel predix lists from the map of ipv4 and ipv6 addresses
resource "aws_ec2_managed_prefix_list" "cloudflare-ipv4" {
    for_each       = local.cloudflare-ips
    name           = "cloudflare_${each.value.type}"
    # Here is where I have to add a provider for the region, and this cannot be done within any type of loop ?
    provider       = aws.ap-southeast-1
    address_family = each.value.type
    max_entries    = 50

    dynamic "entry" {
            for_each        = tolist( each.value.ips ) 
        content {
            cidr            = entry.value
            description     = "CloudFlare ${entry.key}"
        }
    }
}

I've tried including a list of strings with region / provider names and calling these directly from inside the loop, but even though it can evaluate a string (e.g. provider = "aws.ap-southeast-1") it does not accept reading from the local map like so:

    provider       = each.value.region

with error: │ The provider argument requires a provider type name, optionally followed by a period and then a configuration alias.

I guess the next step would be to make this into a module ? Any other suggestions... ?

1 Answers

this cannot be done within any type of loop

That's correct. You can't have dynamic provider, thus you can't use any loops and variables. Its value must be hardcoded.

Related