获取一组子网的 CIDR 块

Getting the CIDR block of a set of subnets

我正在尝试获取一组提供参数的子网 ID 的 CIDR 块。

data "aws_subnet" "target" {
  for_each = "${toset(var.subnet_ids)}"
  id       = "${each.value}"
}

resource "aws_security_group" "registry" {
  vpc_id = "${var.vpc_id}"
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["${data.aws_subnet.target.*.cidr_block}"]
  }
  tags = {
    Name = "${var.name}"
  }
}

我得到的错误是:

cidr_blocks = "${data.aws_subnet.target.*.cidr_block}"

This object does not have an attribute named "cidr_block".

Terraform 配置:

Terraform v0.12.24
+ provider.aws v2.55.0
+ provider.template v2.1.2

感谢能提供帮助的人!

您应该对地图的值使用 splat 表达式。

resource "aws_security_group" "registry" {
  vpc_id = "${var.vpc_id}"
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = values(data.aws_subnet.target).*.cidr_block
  }
  tags = {
    Name = "${var.name}"
  }
}

我认为这里的问题是 for_each 参数使 data.aws_subnet.target 显示为映射值,并且 splat 运算符 .* 被定义为空操作,如果它适用于列表或集合以外的任何事物。因此,此处的表达式评估采用以下步骤:

  • 首先评估 data.aws_subnet.target,生成一个对象映射,其键是来自 var.subnet_ids 的字符串,大概看起来像 subnet-12345.
  • 然后将 .* 应用于该地图。因为它是一张地图,所以会再次产生相同的结果。
  • 然后将 .cidr_block 应用到该映射,但失败了,因为它的键是子网 ID,而不是子网对象的属性。

为了在这里得到想要的结果,我们可以使用values忽略键并将映射中的值作为列表:

cidr_blocks = values(data.aws_subnet.target).*.cidr_block

因为 values(...) 的结果是一个列表,.* 运算符将按预期运行并尝试在列表的每个元素中找到 cidr_block 属性。

另一种选择是使用 for expression,它是适用于任何集合类型值的 splat 语法的概括:

cidr_blocks = [for s in data.aws_subnet.target : s.cidr_block]