What's the safest way to migrate from inline rules in aws_security_group to aws_vpc_security_group_[ingress|egress]_rule?

I’m trying to migrate my security group rules from inline definitions to standalone aws_vpc_security_group_[ingress|egress]_rule resources. Here’s an example:

Before:

resource "aws_security_group" "example" {
  name        = "example"
  description = "example"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "example"
  }
}

After:

resource "aws_security_group" "example" {
  name        = "example"
  description = "example"
  vpc_id      = aws_vpc.main.id

  tags = {
    Name = "example"
  }
}

resource "aws_vpc_security_group_ingress_rule" "example" {
  security_group_id = aws_security_group.example.id

  cidr_ipv4   = "10.0.0.0/8"
  from_port   = 80
  to_port     = 80
  ip_protocol = "tcp"
}

resource "aws_vpc_security_group_egress_rule" "example" {
  security_group_id = aws_security_group.example.id

  cidr_ipv4   = "0.0.0.0/0"
  ip_protocol = "-1"
}

Simply removing the inline rules and adding the new standalone rule resources results in the following error during apply:

│ operation error EC2: AuthorizeSecurityGroupEgress, https response error StatusCode: 400, RequestID: 7d770367-11a9-4ed9-b9e1-1adb9dadaf7a, api error
│ InvalidPermission.Duplicate: the specified rule “peer: 0.0.0.0/0, ALL, ALLOW” already exists

While I could manually delete the inline rules through the AWS Management Console first, this would temporarily disrupt network connectivity, which is not acceptable in our production environment.

What would be the safest migration approach that ensures zero downtime and maintains the existing security group rules throughout the process?

@castor Not sure if it’s the best approach, but here is one that’s relatively safe albeit somewhat manual.

After you add the aws_vpc_security_group_ingress_rule and aws_vpc_security_group_egress_rule resources and remove the ingress and egress arguments from aws_security_group.example, you can use the terraform import command to manually import the resource into the state using the security group rule ID. You can find the IDs in the security group in the AWS Management Console. Here is an example for the ingress rule:

terraform import aws_vpc_security_group_ingress_rule.example sgr-0137accf1468bb8a7

When I tried to just remove the ingress and egress arguments, terraform apply does not detect any changes, meaning that removing them will leave the actual rules alone. This gives you the opportunity to establish the stand-alone resources as above.