Amazon web services Terraform解耦安全组依赖项

Amazon web services Terraform解耦安全组依赖项,amazon-web-services,terraform,aws-security-group,Amazon Web Services,Terraform,Aws Security Group,这是用地形v0.12.9进行测试的 我通常将安全组和安全组规则作为单独的资源进行管理,如下例所示: resource "aws_security_group" "this" { count = var.create ? 1 : 0 name_prefix = "${var.security_group_name}_" vpc_id = var.vpc_id lifecycle { create_before_destroy = true } }

这是用地形v0.12.9进行测试的

我通常将安全组和安全组规则作为单独的资源进行管理,如下例所示:

resource "aws_security_group" "this" {
  count       = var.create ? 1 : 0
  name_prefix = "${var.security_group_name}_"
  vpc_id      = var.vpc_id

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "ingress_rules" {
  count                     = var.create ? length(var.inbound_security_group_ids) : 0

  security_group_id         = aws_security_group.this[0].id
  type                      = "ingress"

  from_port                 = var.from_port
  to_port                   = var.to_port
  protocol                  = "tcp"
  source_security_group_id  = var.inbound_security_group_ids[count.index]
}
这方面的实现如下所示:

module "test_module" {
  source                     = "../path/to/module/"

  create                     = true
  vpc_id                     = "vpc-xxxxxx"
  security_group_name        = "${var.service_name}-db"
  from_port                  = 1234
  to_port                    = 1234
  inbound_security_group_ids = [
    module.service.security_group_id_one,
    module.service.security_group_id_two
  ]
}
问题

如果未创建
模块.service
的输出,我希望此功能正常工作。在这种情况下,我的期望是
length(var.inbound\u security\u group\u id)
应计算为
0
,从而不会创建安全组规则

实际情况是,当未创建
模块服务时,
长度(var.inbound\u security\u group\u id)
的计算结果为
2
。这大概是因为它是由两个空白字符串组成的数组
[“”,“”]

根据,我可以使用
compact
函数处理这个问题,该函数从数组中删除空字符串

resource "aws_security_group_rule" "ingress_rules" {
  count                     = var.create ? length(compact(var.inbound_security_group_ids)) : 0

  security_group_id         = aws_security_group.this[0].id
  type                      = "ingress"

  from_port                 = var.from_port
  to_port                   = var.to_port
  protocol                  = "tcp"
  source_security_group_id  = var.inbound_security_group_ids[count.index]
}
然而,问题是Terraform无法确定
计划
,因为它不知道
变量入站安全组ID
的计算结果,直到
应用时间
。这是错误消息(用于上下文):

“计数”值取决于无法确定的资源属性 在应用之前,Terraform无法预测将创建多少实例。 要解决此问题,请使用-target参数首先仅应用 计数所依赖的资源

问题


有没有可能将这样的安全组解耦,这样即使
源安全组id
属性没有值,它也会被创建?

在Terraform中使用可能为空的列表或集合通常比使用可能未设置的单个值更容易,原因与您观察到的情况有关:它将值是否设置与实际值分开,这样即使值本身未知,也可以知道值的存在

在这种情况下,您可以通过更改从
服务
模块返回安全组id的方式来实现这一点,以便这些输出中的每一个都是安全组id的列表,而不是可能是有效安全组id或空字符串的单个字符串:

module "test_module" {
  source                     = "../path/to/module/"

  create                     = true
  vpc_id                     = "vpc-xxxxxx"
  security_group_name        = "${var.service_name}-db"
  from_port                  = 1234
  to_port                    = 1234
  inbound_security_group_ids = concat(
    module.service.security_group_ids_one,
    module.service.security_group_ids_two,
  )
}

如果已知
security\u group\u id\u one
security\u group\u id\u two
为空列表,则
concat
将完全忽略它。如果启用了它们,则可以将它们安排为一个已知列表,其中包含一个值未知的元素,因此
长度(var.inbound\u security\u group\u id)
在所有情况下都会有一个已知的值。

在Terraform中使用可能为空的列表或集合通常比使用可能未设置的单个值更容易,原因与您观察到的情况有关:它将值是否设置与实际值区分开来,因此,即使值本身未知,也可以知道值的存在

在这种情况下,您可以通过更改从
服务
模块返回安全组id的方式来实现这一点,以便这些输出中的每一个都是安全组id的列表,而不是可能是有效安全组id或空字符串的单个字符串:

module "test_module" {
  source                     = "../path/to/module/"

  create                     = true
  vpc_id                     = "vpc-xxxxxx"
  security_group_name        = "${var.service_name}-db"
  from_port                  = 1234
  to_port                    = 1234
  inbound_security_group_ids = concat(
    module.service.security_group_ids_one,
    module.service.security_group_ids_two,
  )
}
如果已知
security\u group\u id\u one
security\u group\u id\u two
为空列表,则
concat
将完全忽略它。如果启用了它们,则可以将它们安排为一个已知列表,其中包含一个值未知的元素,因此
length(var.inbound\u security\u group\u ids)
在所有情况下仍具有已知值