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