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.83k stars 9.18k forks source link

[Bug]: aws_instance use of ipv6_address_count to ipv6_addresses forces replacement #39433

Open johnalotoski opened 1 month ago

johnalotoski commented 1 month ago

Terraform Core Version

OpenTofu 1.7.1

AWS Provider Version

5.66.0

Affected Resource(s)

Expected Behavior

The auto-assigned ipv6 should be updated to the explicitly declared ipv6. The instance should not be force replaced. Unassignment of an auto-assigned ipv6 with application of a custom ipv6 can be performed through the aws console UI without destroying the instance.

Actual Behavior

The instance will be force replaced.

Relevant Error/Panic Output Snippet

# aws_instance.xyz[0] must be replaced
-/+ resource "aws_instance" "xyz" {
      ...
      ~ ipv6_address_count                   = 1 -> (known after apply)
      ~ ipv6_addresses                       = [ # forces replacement
          - "$AUTO_ASSIGNED_IPV6",
          + "$CUSTOM_IPV6",
        ]

Terraform Configuration Files

{
  "data": {
    "aws_ami": {
      "nixos_x86_64-linux_eu_central_1": {
        "filter": [
          {
            "name": "name",
            "values": [
              "nixos/24.05*"
            ]
          },
          {
            "name": "architecture",
            "values": [
              "x86_64"
            ]
          }
        ],
        "most_recent": true,
        "owners": [
          "427812963091"
        ],
        "provider": "aws.eu_central_1"
      }
    },
    "aws_availability_zones": {
      "eu_central_1": {
        "filter": [
          {
            "name": "opt-in-status",
            "values": [
              "opt-in-not-required"
            ]
          }
        ],
        "provider": "aws.eu_central_1"
      }
    },
    "aws_caller_identity": {
      "current": {}
    },
    "aws_internet_gateway": {
      "eu_central_1": {
        "depends_on": [
          "data.aws_vpc.eu_central_1"
        ],
        "filter": [
          {
            "name": "attachment.vpc-id",
            "values": [
              "${data.aws_vpc.eu_central_1.id}"
            ]
          }
        ],
        "provider": "aws.eu_central_1"
      }
    },
    "aws_region": {
      "current": {}
    },
    "aws_route53_zone": {
      "selected": {
        "name": "$DNS_ZONE"
      }
    },
    "aws_route_table": {
      "eu_central_1": {
        "depends_on": [
          "data.aws_vpc.eu_central_1"
        ],
        "provider": "aws.eu_central_1",
        "route_table_id": "${data.aws_vpc.eu_central_1.main_route_table_id}"
      }
    },
    "aws_subnet": {
      "eu_central_1": {
        "availability_zone": "${element(data.aws_availability_zones.eu_central_1.names, each.key)}",
        "default_for_az": true,
        "for_each": "${{for i, az in data.aws_availability_zones.eu_central_1.names : i => az}}",
        "provider": "aws.eu_central_1"
      }
    },
    "aws_vpc": {
      "eu_central_1": {
        "default": true,
        "provider": "aws.eu_central_1"
      }
    }
  },
  "provider": {
    "aws": [
      {
        "alias": "eu_central_1",
        "region": "eu-central-1"
      }
    ]
  },
  "resource": {
    "aws_default_route_table": {
      "eu_central_1": {
        "default_route_table_id": "${data.aws_vpc.eu_central_1.main_route_table_id}",
        "provider": "aws.eu_central_1",
        "route": [
          {
            "cidr_block": "0.0.0.0/0",
            "core_network_arn": "${null}",
            "destination_prefix_list_id": "${null}",
            "egress_only_gateway_id": "${null}",
            "gateway_id": "${data.aws_internet_gateway.eu_central_1.id}",
            "instance_id": "${null}",
            "ipv6_cidr_block": "${null}",
            "nat_gateway_id": "${null}",
            "network_interface_id": "${null}",
            "transit_gateway_id": "${null}",
            "vpc_endpoint_id": "${null}",
            "vpc_peering_connection_id": "${null}"
          },
          {
            "cidr_block": "${null}",
            "core_network_arn": "${null}",
            "destination_prefix_list_id": "${null}",
            "egress_only_gateway_id": "${null}",
            "gateway_id": "${data.aws_internet_gateway.eu_central_1.id}",
            "instance_id": "${null}",
            "ipv6_cidr_block": "::/0",
            "nat_gateway_id": "${null}",
            "network_interface_id": "${null}",
            "transit_gateway_id": "${null}",
            "vpc_endpoint_id": "${null}",
            "vpc_peering_connection_id": "${null}"
          }
        ]
      }
    },
    "aws_default_subnet": {
      "eu_central_1": {
        "availability_zone": "${each.value.availability_zone}",
        "for_each": "${data.aws_subnet.eu_central_1}",
        "ipv6_cidr_block": "${data.aws_vpc.eu_central_1.ipv6_cidr_block == \"\" ? null : cidrsubnet(data.aws_vpc.eu_central_1.ipv6_cidr_block, 64 - parseint(tolist(regex(\"/([0-9]+)$\", data.aws_vpc.eu_central_1.ipv6_cidr_block))[0], 10), each.key)}",
        "provider": "aws.eu_central_1"
      }
    },
    "aws_default_vpc": {
      "eu_central_1": {
        "assign_generated_ipv6_cidr_block": true,
        "provider": "aws.eu_central_1"
      }
    },
    "aws_eip": {
      "instance-xyz": {
        "count": 1,
        "instance": "${aws_instance.instance-xyz[0].id}",
        "provider": "aws.eu_central_1"
      }
    },
    "aws_eip_association": {
      "instance-xyz": {
        "allocation_id": "${aws_eip.instance-xyz[0].id}",
        "count": 1,
        "instance_id": "${aws_instance.instance-xyz[0].id}",
        "provider": "aws.eu_central_1"
      }
    },
    "aws_iam_instance_profile": {
      "ec2_profile": {
        "name": "ec2Profile",
        "role": "${aws_iam_role.ec2_role.name}"
      }
    },
    "aws_iam_policy": {
      "kms_user": {
        "name": "kmsUser",
        "policy": "{\"Statement\":[{\"Action\":[\"kms:Decrypt\",\"kms:DescribeKey\"],\"Condition\":{\"ForAnyValue:StringLike\":{\"kms:ResourceAliases\":\"alias/kmsKey\"}},\"Effect\":\"Allow\",\"Resource\":\"arn:aws:kms:*:${data.aws_caller_identity.current.account_id}:key/*\"}],\"Version\":\"2012-10-17\"}"
      }
    },
    "aws_iam_role": {
      "ec2_role": {
        "assume_role_policy": "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}",
        "name": "ec2Role"
      }
    },
    "aws_iam_role_policy_attachment": {
      "ec2_role_policy_attachment_kms_user": {
        "policy_arn": "${aws_iam_policy.kms_user.arn}",
        "role": "${aws_iam_role.ec2_role.name}"
      }
    },
    "aws_instance": {
      "instance-xyz": {
        "ami": "${data.aws_ami.nixos_x86_64-linux_eu_central_1.id}",
        "count": 1,
        "iam_instance_profile": "${aws_iam_instance_profile.ec2_profile.name}",
        "instance_type": "c5ad.large",
        "ipv6_address_count": "${data.aws_vpc.eu_central_1.ipv6_cidr_block == \"\" ? null : 1}",
        "key_name": "${aws_key_pair.bootstrap_eu_central_1[0].key_name}",
        "lifecycle": [
          {
            "ignore_changes": [
              "ami",
              "user_data"
            ]
          }
        ],
        "metadata_options": {
          "http_endpoint": "enabled",
          "http_put_response_hop_limit": 2,
          "http_tokens": "optional"
        },
        "monitoring": true,
        "provider": "aws.eu_central_1",
        "root_block_device": {
          "delete_on_termination": true,
          "iops": 3000,
          "throughput": 125,
          "volume_size": 80,
          "volume_type": "gp3"
        },
        "vpc_security_group_ids": [
          "${aws_security_group.common_eu_central_1[0].id}"
        ]
      }
    },
    "aws_key_pair": {
      "bootstrap_eu_central_1": {
        "count": 1,
        "key_name": "bootstrap",
        "provider": "aws.eu_central_1",
        "public_key": "${tls_private_key.bootstrap.public_key_openssh}"
      }
    },
    "aws_security_group": {
      "common_eu_central_1": {
        "count": 1,
        "description": "Allow common ports",
        "egress": [
          {
            "cidr_blocks": [
              "0.0.0.0/0"
            ],
            "description": "Allow outbound traffic",
            "from_port": 0,
            "ipv6_cidr_blocks": [
              "::/0"
            ],
            "prefix_list_ids": [],
            "protocol": "-1",
            "security_groups": [],
            "self": true,
            "to_port": 0
          }
        ],
        "ingress": [
          {
            "cidr_blocks": [
              "0.0.0.0/0"
            ],
            "description": "Allow SSH",
            "from_port": 22,
            "ipv6_cidr_blocks": [
              "::/0"
            ],
            "prefix_list_ids": [],
            "protocol": "tcp",
            "security_groups": [],
            "self": true,
            "to_port": 22
          }
        ],
        "lifecycle": [
          {
            "create_before_destroy": true
          }
        ],
        "name": "common",
        "provider": "aws.eu_central_1"
      }
    },
    "tls_private_key": {
      "bootstrap": {
        "algorithm": "ED25519"
      }
    }
  },
  "terraform": {
    "backend": {
      "s3": {
        "bucket": "bucket",
        "dynamodb_table": "terraform",
        "key": "terraform",
        "region": "eu-central-1"
      }
    },
    "required_providers": {
      "aws": {
        "source": "opentofu/aws"
      },
      "local": {
        "source": "opentofu/local"
      },
      "null": {
        "source": "opentofu/null"
      },
      "tls": {
        "source": "opentofu/tls"
      }
    }
  }
}

Steps to Reproduce

Debug Output

No response

Panic Output

Important Factoids

No response

References

A similar issue appears to have been reported in #33707 which led to fixing of the force replacement on adjusting ipv6_address_count or ipv6_addresses, although it does not fix force replacement by switching from one to the other. Going from auto-assigned ipv6 to static declared ipv6 or vice-versa may be a common, or at least not rare, use case.

Would you like to implement a fix?

No

github-actions[bot] commented 1 month ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

hfinucane commented 1 month ago

I wrote #37262 for this, I couldn't get any traction. It doesn't look like its totally bitrotted yet.

johnalotoski commented 1 month ago

I wrote #37262 for this, I couldn't get any traction. It doesn't look like its totally bitrotted yet.

Oh, that would be great to get merged! Let's see if we can get a few more :+1: to help get it moving.

Will that PR also cover the use case of switching from a declared ipv6_address_count with no declared ipv6_addresses list/set to only a declared ipv6_addresses list/set without a forced re-create?