如何在Terraform中处理嵌套数组?从本地映射提取记录至Route53
Got it, let's break down how to handle nested arrays in Terraform for your Route53 use case. I’ve dealt with this exact scenario before, so let’s walk through it step by step.
First, Let's Align on Your Current Setup
Based on your description, I assume your locals block looks something like this, with nested records arrays inside each CNAME entry:
locals { cname_records = { "app" = { zone_id = "ZXXXXXXXXXXXXXX" # Your Route53 zone ID ttl = 300 records = [ "app.example.com.", "www.app.example.com." ] } "api" = { zone_id = "ZYYYYYYYYYYYYYY" ttl = 300 records = [ "api.example.com.", "v1.api.example.com." ] } } }
And your problematic aws_route53_record resource looks like this, with the records field unpopulated:
resource "aws_route53_record" "cname" { for_each = local.cname_records zone_id = each.value.zone_id name = each.key type = "CNAME" ttl = each.value.ttl records = # ❌ This is the problem area you're stuck on }
The Simple Fix for Your Basic Case
The solution is straightforward—you can directly reference the nested records array using each.value.records. Here's the corrected resource:
resource "aws_route53_record" "cname" { for_each = local.cname_records zone_id = each.value.zone_id name = each.key type = "CNAME" ttl = each.value.ttl records = each.value.records # ✅ Correctly pulls the nested array }
Why This Works
When you use for_each with local.cname_records, each iteration of each.value represents the entire map for a single CNAME entry (e.g., the app entry with zone_id, ttl, and records). Since the Route53 records field accepts a list of strings, this direct reference perfectly matches the required input type.
Handling More Complex Nested Structures (If You Need It)
If your locals have a deeper nested structure (e.g., grouping records under parent domains), you’ll need to flatten the structure first using Terraform’s for expressions and flatten function. For example, if your locals look like this:
locals { domains = { "example.com" = { zone_id = "ZXXXXXXXXXXXXXX" cnames = [ { name = "app" ttl = 300 records = ["app.example.com."] }, { name = "www" ttl = 300 records = ["www.example.com."] } ] } } }
You can transform this into a flat map suitable for for_each like so:
resource "aws_route53_record" "cname" { for_each = { for domain, domain_details in local.domains : for cname in domain_details.cnames : "${domain}-${cname.name}" => merge(cname, { zone_id = domain_details.zone_id }) } zone_id = each.value.zone_id name = each.value.name type = "CNAME" ttl = each.value.ttl records = each.value.records # Still works for the flattened entries }
The nested for loop converts the 2-level structure into a single-level map, and merge combines the parent domain's zone_id with each CNAME's details so you can access all fields easily.
Quick Validation Tip
Before running terraform apply, you can test your nested array extraction using the Terraform console:
terraform console
Then run this command to verify you’re pulling the correct records:
local.cname_records["app"].records
You should see the array of CNAME values printed out—this confirms your reference is working correctly.
内容的提问来源于stack exchange,提问作者jadejoe

