You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Terraform中通过嵌套for_each循环实现多区域AWS托管前缀列表的统一配置?

Simplifying Multi-Region Cloudflare Managed Prefix Lists in Terraform

Great question—this is a common pain point when dealing with multi-region Terraform resources that require provider scoping. The core issue here is that Terraform won’t let you dynamically generate provider references in loops, but we can work around this with predefined provider aliases and composite for_each keys to avoid repetitive code blocks. Here are two clean, maintainable solutions:

Solution 1: Composite For-Each with Predefined Provider Aliases

First, define provider aliases for every region you need to deploy to. Then, create a composite local map that combines regions, IP types (IPv4/IPv6), and their respective configurations. This lets you loop through all combinations while statically referencing the correct provider alias.

Step 1: Configure Multi-Region Providers

# Define provider aliases for each target region
provider "aws" {
  alias  = "ap_southeast_1"
  region = "ap-southeast-1"
}

provider "aws" {
  alias  = "us_east_1"
  region = "us-east-1"
}

provider "aws" {
  alias  = "eu_west_1"
  region = "eu-west-1"
}

Step 2: Build Composite Configuration Map

locals {
  # Map regions to their provider aliases and human-readable names
  regions = {
    ap_southeast_1 = { alias = aws.ap_southeast_1, name = "ap-southeast-1" }
    us_east_1      = { alias = aws.us_east_1, name = "us-east-1" }
    eu_west_1      = { alias = aws.eu_west_1, name = "eu-west-1" }
  }

  # Cloudflare IP sets grouped by address family
  cloudflare_ip_sets = {
    ipv4 = {
      ips             = ["10.0.0.0/32", "173.245.48.0/20", ...]
      address_family  = "IPv4"
      max_entries     = 50
    }
    ipv6 = {
      ips             = ["2400:cb00::/32", "2606:4700::/32", ...]
      address_family  = "IPv6"
      max_entries     = 50
    }
  }

  # Create all region × IP type combinations
  prefix_list_combinations = merge([
    for region_key, region in local.regions : {
      for ip_type, ip_set in local.cloudflare_ip_sets :
      "${region_key}_${ip_type}" => {
        region           = region
        ip_set           = ip_set
        prefix_list_name = "cloudflare_${ip_type}_${region.name}"
      }
    }
  ]...)
}

Step 3: Deploy Prefix Lists in a Single Resource Block

resource "aws_ec2_managed_prefix_list" "cloudflare" {
  for_each = local.prefix_list_combinations

  # Static reference to the region's provider alias (no dynamic strings!)
  provider = each.value.region.alias

  name               = each.value.prefix_list_name
  address_family     = each.value.ip_set.address_family
  max_entries        = each.value.ip_set.max_entries

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

This approach keeps your code DRY: add a new region or IP set by only updating the regions or cloudflare_ip_sets locals—no extra resource blocks needed.

Solution 2: Encapsulate in a Reusable Module

If you need to reuse this logic across projects or teams, wrap the prefix list creation in a Terraform module. This keeps your root module clean and makes the configuration portable.

Module Code (modules/cloudflare_prefix_list/main.tf)

variable "name" {
  type        = string
  description = "Name of the managed prefix list"
}

variable "address_family" {
  type        = string
  description = "IP address family (IPv4/IPv6)"
}

variable "max_entries" {
  type        = number
  description = "Maximum number of entries in the prefix list"
}

variable "ips" {
  type        = list(string)
  description = "List of Cloudflare IP CIDRs"
}

resource "aws_ec2_managed_prefix_list" "main" {
  name               = var.name
  address_family     = var.address_family
  max_entries        = var.max_entries

  dynamic "entry" {
    for_each = tolist(var.ips)
    content {
      cidr        = entry.value
      description = "Cloudflare IP ${entry.key}"
    }
  }
}

Root Module Usage

# Reuse the multi-region provider aliases from Solution 1
# Reuse the `regions`, `cloudflare_ip_sets`, and `prefix_list_combinations` locals from Solution 1

module "cloudflare_prefix_lists" {
  for_each = local.prefix_list_combinations

  source             = "./modules/cloudflare_prefix_list"
  provider           = each.value.region.alias

  name               = each.value.prefix_list_name
  address_family     = each.value.ip_set.address_family
  max_entries        = each.value.ip_set.max_entries
  ips                = each.value.ip_set.ips
}

Modules are ideal for standardizing infrastructure across your AWS organization—other teams can reference this module to deploy the same Cloudflare prefix lists without duplicating code.

Why Your Initial Dynamic Provider Attempt Failed

Terraform requires the provider argument to be a static reference to a provider alias (e.g., aws.ap_southeast_1), not a dynamically generated string. By predefining aliases and mapping them in your locals, you avoid this restriction while keeping your configuration flexible.

内容的提问来源于stack exchange,提问作者riice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:32:42