使用Terraform Google Provider创建防火墙规则时获取子网IPv6前缀报错
问题场景
尝试通过Terraform的Google Provider创建防火墙规则,需要从VPC的所有子网中提取IP前缀作为source_ranges,但在遍历子网数据源时遇到以下错误:
用户原代码
data "google_compute_network" "vpc" { name = "my-vpc" project = "my-project" } data "google_compute_subnetwork" "subnetwork" { for_each = toset(data.google_compute_network.vpc.subnetworks_self_links) self_link = each.value } resource "google_compute_firewall" "composer-firewall-rule" { name = "allow-egress-from-composer-control-plane" description = "Allow Egress traffic from k8 nodes to Control Plane" network = data.google_compute_network.vpc project = var.DEPLOY_PROJECT priority = 980 allow { protocol = "all" } direction = "EGRESS" disabled = false source_ranges = [data.google_compute_subnetwork.subnetwork.self_link.external_ipv6_prefix] }
报错信息
Error: Missing resource instance key
on modules\firewall_rules\main.tf line 23, in resource "google_compute_firewall" "composer-firewall-rule"
23: source_ranges = [data.google_compute_subnetwork.subnetwork.self_link.external_ipv6_prefix]Because data.google_compute_subnetwork.subnetwork has "for_each" set, its attributes must be accessed using a specific instance key.
For example, to correlate with indices of a referring resource, use:
data.google_compute_subnetwork.subnetwork[each.key]
错误原因
data.google_compute_subnetwork.subnetwork使用了for_each,因此它是一个映射类型的数据源集合,无法直接通过.self_link访问单个实例的属性,必须遍历所有实例提取所需值。
解决方案
场景1:获取所有子网的external_ipv6_prefix
修改防火墙规则的source_ranges配置,通过values()+for表达式+flatten()提取所有非空的IPv6前缀:
resource "google_compute_firewall" "composer-firewall-rule" { name = "allow-egress-from-composer-control-plane" description = "Allow Egress traffic from k8 nodes to Control Plane" network = data.google_compute_network.vpc project = var.DEPLOY_PROJECT priority = 980 allow { protocol = "all" } direction = "EGRESS" disabled = false # 提取所有子网的external_ipv6_prefix,过滤空值并扁平化列表 source_ranges = flatten([ for subnet in values(data.google_compute_subnetwork.subnetwork) : subnet.external_ipv6_prefix != "" ? [subnet.external_ipv6_prefix] : [] ]) }
场景2:获取所有子网的二级IP范围(即用户提到的"secondary IP")
如果需要提取子网的secondary_ip_ranges中的CIDR,调整为以下配置:
resource "google_compute_firewall" "composer-firewall-rule" { name = "allow-egress-from-composer-control-plane" description = "Allow Egress traffic from k8 nodes to Control Plane" network = data.google_compute_network.vpc project = var.DEPLOY_PROJECT priority = 980 allow { protocol = "all" } direction = "EGRESS" disabled = false # 提取所有子网的二级IP范围CIDR source_ranges = flatten([ for subnet in values(data.google_compute_subnetwork.subnetwork) : [for secondary_range in subnet.secondary_ip_ranges : secondary_range.ip_cidr_range] ]) }
代码说明
values(data.google_compute_subnetwork.subnetwork):将映射类型的子网数据源转换为实例列表for表达式:遍历每个子网实例,提取目标IP前缀/二级IP范围flatten():将嵌套的列表结构转为一维数组,符合source_ranges的参数格式要求
内容的提问来源于stack exchange,提问作者Dinesh

