title: Terraform decouple Security Group dependency
body: <p>This is tested with <strong>Terraform v0.12.9</strong></p>
  
  <p>I generally manage security groups and security group rules as separate resources, as in the below example:</p>
  
  <pre><code>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]
  }
  </code></pre>
  
  <p>The implementation for this would look something like the below:</p>
  
  <pre><code>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
    ]
  }
  </code></pre>
  
  <p><strong>Problem</strong></p>
  
  <p>I want this to work if the outputs from the <code>module.service</code> aren't created.  In that scenario my expectation is that <code>length(var.inbound_security_group_ids)</code> should evaluate to <code>0</code> resulting in the security group rules not being created</p>
  
  <p>What actually happens is that <code>length(var.inbound_security_group_ids)</code> evaluates to <code>2</code> when <code>module.service</code> isn't created.  This is presumably because it is an array of two blank strings <code>["", ""]</code></p>
  
  <p>According to the <a href="https://www.terraform.io/docs/configuration/functions/compact.html" rel="nofollow noreferrer">Terraform documentation</a> I can handle this with the <code>compact</code> function, which removes empty strings from an array.</p>
  
  <pre><code>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]
  }
  </code></pre>
  
  <p>The problem with this, however, is that Terraform is unable to determine the <code>plan</code> because it doesn't know what <code>var.inbound_security_group_ids</code> evaluates to until <code>apply-time</code>.  This is the error message (for context):</p>
  
  <blockquote>
    <p>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.</p>
  </blockquote>
  
  <p><strong>Question</strong></p>
  
  <p>Is it possible to decouple a security group like this so that it will still be created even when the <code>source_security_group_id</code> attribute has no values?</p>