Terraform decouple Security Group dependency

我是研究僧i 提交于 2020-01-25 06:49:47

问题


This is tested with Terraform v0.12.9

I generally manage security groups and security group rules as separate resources, as in the below example:

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]
}

The implementation for this would look something like the below:

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
  ]
}

Problem

I want this to work if the outputs from the module.service aren't created. In that scenario my expectation is that length(var.inbound_security_group_ids) should evaluate to 0 resulting in the security group rules not being created

What actually happens is that length(var.inbound_security_group_ids) evaluates to 2 when module.service isn't created. This is presumably because it is an array of two blank strings ["", ""]

According to the Terraform documentation I can handle this with the compact function, which removes empty strings from an array.

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]
}

The problem with this, however, is that Terraform is unable to determine the plan because it doesn't know what var.inbound_security_group_ids evaluates to until apply-time. This is the error message (for context):

The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on.

Question

Is it possible to decouple a security group like this so that it will still be created even when the source_security_group_id attribute has no values?


回答1:


It's often easier to work with lists or sets that might be empty in Terraform than to work with individual values that might not be set, for a reason related to what you've observed: it separates whether the value is set from what the value actually is, so that the presence of the value can be known even if the value itself isn't known.

In this case, you might approach that by changing how you return the security group ids from your service module, so that each of those outputs is a list of security group ids rather than a single string that might be either a valid security group id or an empty string:

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,
  )
}

If either security_group_ids_one or security_group_ids_two is known to be an empty list then concat will ignore it entirely. If they are enabled then you can arrange for them to be a known list with one element whose value is unknown, and thus length(var.inbound_security_group_ids) will still have a known value in all cases.



来源:https://stackoverflow.com/questions/58607536/terraform-decouple-security-group-dependency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!