hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.73k stars 9.09k forks source link

[Bug]: `aws_security_group_rule`: Changes to `cidr_blocks` causes `Error: [WARN] A duplicate Security Group rule was found` #38526

Open YakDriver opened 1 month ago

YakDriver commented 1 month ago

This is a specific scenario related to a family of longstanding challenges with aws_security_group and aws_security_group_rule causing A duplicate Security Group rule was found. There are two purposes to this issue:

  1. Shine light on a specific aspect of the bug
  2. Act as an umbrella for the family of issues (see References below 👇 )

IMPORTANT NOTE

We highly recommend using aws_vpc_security_group_egress_rule and aws_vpc_security_group_ingress_rule instead of aws_security_group_rule. It may be useful to think of aws_security_group_rule as semi deprecated.

Terraform Core Version

1.9.2

AWS Provider Version

5.59.0

Affected Resource(s)

Expected Behavior

Applying configuration should succeed recreating missing cidr_blocks.

Actual Behavior

Applying the configuration, after an out-of-band change to the CIDR blocks, causes an error.

Relevant Error/Panic Output Snippet

Error: [WARN] A duplicate Security Group rule was found on (sg-0738e88c121d67831). This may be
a side effect of a now-fixed Terraform issue causing two security groups with
identical attributes but different source_security_group_ids to overwrite each
other in the state. See https://github.com/hashicorp/terraform/pull/2376 for more
information and instructions for recovery. Error: InvalidPermission.Duplicate: the specified rule "peer: 19.0.0.0/24, TCP, from port: 636, to port: 636, ALLOW" already exists
       status code: 400, request id: 7b3a6f74-2027-4370-b44f-148f9028faf6

   with aws_security_group_rule.ec2_sg_rule_ecp_636[0],
   on main.tf line 25, in resource "aws_security_group_rule" "ec2_sg_rule_ecp_636":
   25: resource "aws_security_group_rule" "ec2_sg_rule_ecp_636" {

Terraform Configuration Files

resource "aws_security_group_rule" "ec2_sg_rule_ecp_636" {
  count             = 1
  description       = "Allow LDAP from on-premise"
  from_port         = 636
  protocol          = "tcp"
  security_group_id = aws_security_group.example.id
  to_port           = 636
  cidr_blocks       = ["19.0.0.0/24", "17.0.0.0/24", "20.0.0.0/24"]
  type              = "ingress"
}

Steps to Reproduce

  1. Apply configuration
  2. Remove one of the CIDR blocks with CLI or Console
  3. Apply configuration

References

There seem to be many error reports in the same neighborhood:

Would you like to implement a fix?

None

github-actions[bot] commented 1 month ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

YakDriver commented 1 month ago

Potential workarounds:

GOOD: One rule per aws_security_group_rule resource

resource "aws_security_group_rule" "example" {
  description       = "Allow LDAP from on-premise"
  from_port         = 636
  protocol          = "tcp"
  security_group_id = aws_security_group.example.id
  to_port           = 636
  cidr_blocks       = ["18.0.0.0/24"]
  type              = "ingress"
}

resource "aws_security_group_rule" "example2" {
  description       = "Allow LDAP from on-premise"
  from_port         = 636
  protocol          = "tcp"
  security_group_id = aws_security_group.example.id
  to_port           = 636
  cidr_blocks       = ["19.0.0.0/24"]
  type              = "ingress"
}

BETTER: One rule per aws_security_group_rule resource (for_each)

variable "my_list" {
  type = list(string)
  default = ["18.0.0.0/24", "19.0.0.0/24"]
}

resource "aws_security_group_rule" "example" {
  for_each          = toset(var.my_list)
  description       = "Allow LDAP from on-premise"
  from_port         = 636
  protocol          = "tcp"
  security_group_id = aws_security_group.example.id
  to_port           = 636
  cidr_blocks       = [each.value]
  type              = "ingress"
}

BEST: One rule per aws_vpc_security_group_ingress_rule resource

variable "my_list" {
  type = list(string)
  default = ["18.0.0.0/24", "19.0.0.0/24"]
}

resource "aws_vpc_security_group_ingress_rule" "example" {
  for_each          = toset(var.my_list)
  description       = "Allow LDAP from on-premise"
  from_port         = 636
  ip_protocol       = "tcp"
  security_group_id = aws_security_group.example.id
  to_port           = 636
  cidr_ipv4         = each.value
}
YakDriver commented 1 month ago

For fans of history, the error message below was penned by Mitchell Hashimoto 9 years ago. Most error messages have moved to a more modern style. This one has been left as a tribute.

[WARN] A duplicate Security Group rule was found on (<id>). This may be
a side effect of a now-fixed Terraform issue causing two security groups with
identical attributes but different source_security_group_ids to overwrite each
other in the state. See https://github.com/hashicorp/terraform/pull/2376 for more
information and instructions for recovery. Error: <error>