Error: Cycle: local.security_groups (expand), aws_security_group.this

Need help in troubleshooting the cycle error in below configuration. i cannot locate any reference to workbench_service in any of the security groups. the locals file is as below:

locals {
  security_groups = {
    ALB_Internal_rules_workbench_prod = {
      ingress = {
        WCC_user_redirect = {
          description = "Wcc Internal users connect to ALB_Internal_rules_workbench_prod"
          type        = "ingress"
          port        = 8080
          protocol    = "tcp"
          cidr_blocks = var.workstation_subnets
        }
        WCC_workspaces_redirect = {
          description = "Workspaces users connect to ALB_Internal_rules_workbench_prod"
          port        = 8080
          protocol    = "tcp"
          cidr_blocks = var.workspace_subnets
        }
      }
      egress = {
        all = {
          description = "Traffic to workbench service"
          type        = "egress"
          port        = 8080
          protocol    = "tcp"
          //cidr_blocks = ["10.103.8.0/24"]
          source_security_group_rule = aws_security_group.this["workbench_service"].id
        }
      }
    }
workbench_service = {
      ingress = {
        from_ALB_Internal_rules_workbench_prod = {
          description = "Traffic from ALB_Internal_rules_workbench_prod"
          type        = "ingress"
          port        = 8080
          protocol    = "tcp"
          //source_security_group = aws_security_group.this["ALB_Internal_rules_workbench_prod"].id
          cidr_blocks = ["10.103.8.0/24"]
        }
      }
      egress = {
        all = {
          type        = "egress"
          port        = 0
          protocol    = "-1"
          protocl     = "tcp"
          cidr_blocks = ["10.103.8.0/24"]
        }
        https = {
          description = "HTTPS traffic from ecs services"
          type        = "egress"
          port        = 443
          protocol    = "tcp"
          cidr_blocks = ["0.0.0.0/0"]
        }
         efs = {
          description           = "workbench to efs mount points"
          type                  = "egress"
          port                  = 2049
          protocol              = "tcp"
          //source_security_group = aws_security_group.this["efs_mount_sg"].id
          cidr_blocks = ["10.103.8.0/24"]
        }
      }
    }
  }


  security_group_rules_flat = flatten([
    for rule_key, rule_value in local.security_groups : [
      for rule_type_key, rule_type_attr in rule_value : [
        for rule, rule_attr in rule_type_attr : {
          security_group            = rule_key
          protocol                  = rule_attr.protocol
          port                      = try(rule_attr.port, null)
          from_port                 = try(rule_attr.from_port, null)
          to_port                   = try(rule_attr.to_port, null)
          type                      = rule_type_key
          name                      = rule
          description               = try(rule_attr.description, null)
          cidr_blocks               = try(rule_attr.cidr_blocks, null)
          source_security_group_key = try(rule_attr.source_security_group_key, null)
        }
      ]
    ]
  ])
  security_group_rules = { for rule in local.security_group_rules_flat : "${rule.security_group}.${rule.type}.${rule.name}" => rule }
}

the security groups are defined in sg.tf file as below:

resource "aws_security_group" "this" {
  for_each = local.security_groups

  name        = "${var.cluster_name}/${each.key}"
  description = "Security group for ${var.cluster_name}/${each.key}"
  vpc_id      = var.vpc_id_prod
  tags        = merge(var.tags, { Name = "${var.cluster_name}/${each.key}" })
}

resource "aws_security_group_rule" "this" {
  for_each = local.security_group_rules

  security_group_id        = aws_security_group.this[each.value.security_group].id
  description              = try(each.value.description, null)
  type                     = each.value.type
  from_port                = coalesce(each.value.port, each.value.from_port)
  to_port                  = coalesce(each.value.port, each.value.to_port)
  protocol                 = each.value.protocol
  cidr_blocks              = try(each.value.cidr_blocks, null)
  source_security_group_id = try(coalesce(each.value.source_security_group_id, aws_security_group.this[each.value.source_security_group_key].id), null)
}

The terraform validate is generating below error as mentioned in the subject:

Error: Cycle: aws_security_group.this, local.security_groups (expand)

1 answer

  • answered 2022-05-04 12:31 Matt Schuchard

    The reason for the dependency cycle is because your aws_security_group.this depends on local.security_groups, and your nested local.security_groups.ALB_Internal_rules_workbench_prod.egress.all.source_security_group_rule causes a dependency on aws_security_group.this. You unfortunately cannot avoid this by changing to for_each = toset(keys(local.security_groups)).

    You will need to fix this by decoupling the security group names from the local.security_groups with the security group rules from the local.security_groups. The names will need to be a set or a list converted to set, and the security group rules can remain in the structure you have above. For example:

    locals {
      security_group_names = toset(["ALB_Internal_rules_workbench_prod", "workbench_service"])
    }
    

    and then:

    resource "aws_security_group" "this" {
      for_each = local.security_group_names
      ...
    }
    

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum