Home > Software engineering >  conflicting issue for aws_security_group_rule attributes cidr_blocks and source_security_group_id
conflicting issue for aws_security_group_rule attributes cidr_blocks and source_security_group_id

Time:12-20

Below is the locals sg_rules output I am getting check the value for cidr_blocks and security_group_id variables. At a time either of the values will be

"security_group_id" = tostring(null)

or

"cidr blocks" = tolist([])

Locals Outputs :

sg_rules = {
    "testsg_1-ingress-1521-tcp-10.80.0.10/32" => {
    "cidr blocks" = tolist(["10.80.0.10/32",]) 
    "description" = "1521 tcp ingress" 
    "from_port" = 1521 
    "protocol" = "tcp" 
    "security_group_id" = tostring(null) 
    "sg_name" = "testsg_1"
    "to_port" = 1521 
    "type" = "ingress" 
  },
    "testsg_2-ingress-1524-tcp-sg-23423439" => {
    "cidr blocks" = tolist([]) 
    "description" = "1524 tcp ingress" 
    "from_port" = 1524 
    "protocol" = "tcp" 
    "security_group_id" = "sg-23423439"
    "sg_name" = "testsg_2"
    "to_port" = 1524 
    "type" = "ingress" 
  }
}

using the above local in the aws_security_group_rule resource like below getting conflicting error, that both cidr_blocks and source_security_group_id should not exist at the same time.

resource "aws_security_group_rule" "tcp_cidr_blocks" {
  for_each  = { for key, sg_rule in local.sg_rules : key => sg_rule }
  type      = each.value.type
  from_port = each.value.from_port
  to_port   = each.value.to_port
  cidr_blocks              = each.value.cidr_blocks
  source_security_group_id = each.value.security_group_id
  protocol                 = each.value.protocol
  security_group_id        = aws_security_group.security_groups.id
}

what I am expecting as either of inputs are null, at a time, so it shouldn't conflict and use either cidr_blocks or source_security_group_id at a time.

Error:

Error: Conflicting configuration arguments\n\n with 
module.sg.aws_security_group_ru1e.tcp_cidr_blocks[\"testsg_2-ingress-1524-tcp-sg-23423439\"],\n on sg/main.tf line 30, in resource 
\"aws_security_group_rule\" \"tcp_cidr_blocks\" : \n 30: 
source_security_group_id 
= each.value.security_group_id\n\n\"security_group_id\": 
conflicts with cidr_blocks\n", 

CodePudding user response:

There are a couple of issues with the current code, one being the => which is not a valid syntax in Terraform:

enter image description here

The second is explicitly casting to types, e.g., tolist(["10.80.0.10/32",]) and tostring(null). If the local variable sg_rules is fixed to look like this:

sg_rules = {
    "testsg_1-ingress-1521-tcp-10.80.0.10/32" = {
      "cidr_blocks"       = ["10.80.0.10/32", ] # <---- list instead of type casting
      "description"       = "1521 tcp ingress"
      "from_port"         = 1521
      "protocol"          = "tcp"
      "security_group_id" = "" # <---- empty string instead of type casting
      "sg_name"           = "testsg_1"
      "to_port"           = 1521
      "type"              = "ingress"
    },
    "testsg_2-ingress-1524-tcp-sg-23423439" = {
      "cidr_blocks"       = [""] # <---- empty list of strings instead of type casting
      "description"       = "1524 tcp ingress"
      "from_port"         = 1524
      "protocol"          = "tcp"
      "security_group_id" = "sg-23423439"
      "sg_name"           = "testsg_2"
      "to_port"           = 1524
      "type"              = "ingress"
    }
  }

Following that change, using the ternary operator on your code will result in terraform plan working:

resource "aws_security_group_rule" "tcp_cidr_blocks" {
  for_each                 = local.sg_rules
  type                     = each.value.type
  from_port                = each.value.from_port
  to_port                  = each.value.to_port
  cidr_blocks              = each.value.cidr_blocks != [""] ? each.value.cidr_blocks : null
  source_security_group_id = each.value.security_group_id != "" ? each.value.security_group_id : null
  protocol                 = each.value.protocol
  security_group_id        = aws_security_group.security_groups.id
}

Setting cidr_blocks or source_security_group_id to null will tell terraform to treat it is an absence of the argument which means it will not complain about conflicting arguments.

CodePudding user response:

The second object in your example has:

  • "cidr blocks" = tolist([])
  • "security_group_id" = "sg-23423439"

An empty list is not null, so for this object both of the arguments are set at once.

If you set the CIDR blocks attribute to tolist(null) instead then you will have a null value for that argument, which may allow this validation rule to pass.

This validation rule is implemented by the hashicorp/aws provider in its aws_security_group_rule implementation and so exactly how it will interpret these cases is decided by how the logic in the provider is written -- the provider could potentially choose to treat an empty list the same as unset -- but a null value for a resource argument is always exactly equivalent to leaving it unset and so making sure at least one of them is really null is the most robust way to configure this, which should work regardless of how the provider plugin is implemented.

CodePudding user response:

You can fix this error by using the ternary operator to check for the existence of the security_group_id or the cidr_blocks values. If one of them exists, then you can assign it to the respective argument in the aws_security_group_rule resource.

For example, you can use the following code:

resource "aws_security_group_rule" "tcp_cidr_blocks" {
  for_each  = { for key, sg_rule in local.sg_rules : key => sg_rule }
  type      = each.value.type
  from_port = each.value.from_port
  to_port   = each.value.to_port
  cidr_blocks              = each.value.security_group_id != null ? [] : each.value.cidr_blocks
  source_security_group_id = each.value.security_group_id != null ? each.value.security_group_id : null
  protocol                 = each.value.protocol
  security_group_id        = aws_security_group.security_groups.id
}
  • Related