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.85k stars 9.19k forks source link

[Bug]: `aws_subnet` throws `IPv6 CIDR <CIDR> is invalid` error #31913

Open ghost opened 1 year ago

ghost commented 1 year ago

Terraform Core Version

1.4.6

AWS Provider Version

5.2.0

Affected Resource(s)

aws_subnet

Expected Behavior

The subnet should be provisioned with the statically defined IPv4 and automatically defined IPv6 supernets and subnets.

I am unable to auto assign IPv6 cidr ranges to new aws_subnets.

I understand this subnet has to be a /64, which it is. It's being calculated out of the /56 automatically generated for the VPC from AWS. I'm not sure why this is not working as that is a valid IPv6 subnet.

Actual Behavior

The subnet is not created as I'm told the IPv6 CIDR for the subnet is not correct.

Relevant Error/Panic Output Snippet

╷
│ Error: creating EC2 Subnet: InvalidSubnet.Range: The IPv6 CIDR '2600:1f18:7cb4:2e01::/64' is invalid.
│       status code: 400, request id: 1d9ac8ef-12a8-4637-b4ab-9dea6845f810
│ 
│   with aws_subnet.ClientSubnetAZ1,
│   on client_vpc.tf line 14, in resource "aws_subnet" "ClientSubnetAZ1":
│   14: resource "aws_subnet" "ClientSubnetAZ1" {
│ 
╵

Terraform Configuration Files

terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = ">= 5.2.0"
  }
}

provider "aws" {
  region = var.awsRegion
}

variable "awsRegion" {
  description = "aws region"
  type        = string
  default     = "us-east-2"
}

variable "awsAz1" {
  description = "Availability zone, will dynamically choose one if left empty"
  type        = string
  default     = null
}

variable "awsAz2" {
  description = "Availability zone, will dynamically choose one if left empty"
  type        = string
  default     = null
}

data "aws_availability_zones" "available" {
  state = "available"
}

variable "ClientSubnetCIDR" {
  default = "10.1.0.0/16"
  type = string
}

variable "ClientSubnetAZ1" {
  default = "10.1.1.0/24"
  type = string
}

locals {
  awsAz1 = var.awsAz1 != null ? var.awsAz1 : data.aws_availability_zones.available.names[0]
}

resource "aws_vpc" "ClientVPC" {
  enable_dns_support = false
  cidr_block = var.ClientSubnetCIDR
  assign_generated_ipv6_cidr_block = "true"  
}

resource "aws_subnet" "ClientSubnetAZ1" {
  vpc_id = aws_vpc.ClientVPC.id
  cidr_block = var.ClientSubnetAZ1
  availability_zone = local.awsAz1
  ipv6_cidr_block = "${cidrsubnet(aws_vpc.ClientVPC.ipv6_cidr_block, 8, 1)}"
  assign_ipv6_address_on_creation = true
}

Steps to Reproduce

Simply run the plan as shown above.

Debug Output

2023-06-12T16:09:02.008-0400 [WARN]  Provider "registry.terraform.io/hashicorp/aws" produced an invalid plan for aws_vpc.ClientVPC, but we are tolerating it because it is using the legacy plugin SDK.
    The following problems may be the cause of any confusing errors from downstream operations:
      - .ipv6_ipam_pool_id: planned value cty.StringVal("") for a non-computed attribute
      - .ipv6_netmask_length: planned value cty.NumberIntVal(0) for a non-computed attribute
      - .instance_tenancy: planned value cty.StringVal("default") for a non-computed attribute
2023-06-12T16:09:02.011-0400 [WARN]  Provider "registry.terraform.io/hashicorp/aws" produced an invalid plan for aws_subnet.ClientSubnetAZ1, but we are tolerating it because it is using the legacy plugin SDK.
    The following problems may be the cause of any confusing errors from downstream operations:
      - .enable_resource_name_dns_aaaa_record_on_launch: planned value cty.False for a non-computed attribute
      - .enable_dns64: planned value cty.False for a non-computed attribute
      - .enable_resource_name_dns_a_record_on_launch: planned value cty.False for a non-computed attribute
      - .map_public_ip_on_launch: planned value cty.False for a non-computed attribute
      - .ipv6_native: planned value cty.False for a non-computed attribute
2023-06-12T16:09:05.653-0400 [WARN]  Provider "registry.terraform.io/hashicorp/aws" produced an invalid plan for aws_subnet.ClientSubnetAZ1, but we are tolerating it because it is using the legacy plugin SDK.
    The following problems may be the cause of any confusing errors from downstream operations:
      - .enable_resource_name_dns_a_record_on_launch: planned value cty.False for a non-computed attribute
      - .enable_resource_name_dns_aaaa_record_on_launch: planned value cty.False for a non-computed attribute
      - .ipv6_native: planned value cty.False for a non-computed attribute
      - .map_public_ip_on_launch: planned value cty.False for a non-computed attribute
      - .enable_dns64: planned value cty.False for a non-computed attribute
2023-06-12T16:09:06.048-0400 [ERROR] provider.terraform-provider-aws_v5.2.0_x5: Response contains error diagnostic: @caller=github.com/hashicorp/terraform-plugin-go@v0.15.0/tfprotov5/internal/diag/diagnostics.go:55 diagnostic_detail= diagnostic_summary="creating EC2 Subnet: InvalidSubnet.Range: The IPv6 CIDR '2600:1f18:7cb4:2e01::/64' is invalid.
    status code: 400, request id: 1d9ac8ef-12a8-4637-b4ab-9dea6845f810" tf_proto_version=5.3 tf_req_id=919995df-aebf-45c7-2c65-cdf0b7b991a0 @module=sdk.proto diagnostic_severity=ERROR tf_provider_addr=registry.terraform.io/hashicorp/aws tf_resource_type=aws_subnet tf_rpc=ApplyResourceChange timestamp=2023-06-12T16:09:06.048-0400
2023-06-12T16:09:06.093-0400 [ERROR] vertex "aws_subnet.ClientSubnetAZ1" error: creating EC2 Subnet: InvalidSubnet.Range: The IPv6 CIDR '2600:1f18:7cb4:2e01::/64' is invalid.
    status code: 400, request id: 1d9ac8ef-12a8-4637-b4ab-9dea6845f810

Panic Output

No response

Important Factoids

No response

References

No response

Would you like to implement a fix?

None

felipempda commented 1 year ago

I think it's not a bug but rather a limitation of AWS Availability Zones. If you don't explicitly specify a zone there is a chance you might endup in a Local Zone and they do not support IPV6:

 The only Local Zones that support IPv6 are us-west-2-lax-1a and use-west-2-lax-1b.

I was able to simulate your problem using a local zone:

variable "awsAz1" {
  description = "Availability zone, will dynamically choose one if left empty"
  type        = string
  default     = "us-east-1-atl-1a" #   local-zone causes your error 
}

But if you choose a normal zone there is no error:

variable "awsAz1" {
  description = "Availability zone, will dynamically choose one if left empty"
  type        = string
  default     = "us-east-1a" #   normal zone no error
}

It's because data from availability zones is returning a local zone as first element:

Using terraform console:

> data.aws_availability_zones.available.names
tolist([
  "us-east-1-atl-1a",
  "us-east-1-bos-1a",
  "us-east-1-bue-1a",
  "us-east-1-chi-1a",
  "us-east-1-dfw-1a",
  "us-east-1-iah-1a",
  "us-east-1-lim-1a",
  "us-east-1-mci-1a",
  "us-east-1-mia-1a",
  "us-east-1-msp-1a",
  "us-east-1-nyc-1a",
  "us-east-1-phl-1a",
  "us-east-1-qro-1a",
  "us-east-1-scl-1a",
  "us-east-1-wl1-atl-wlz-1",
  "us-east-1-wl1-bna-wlz-1",
  "us-east-1-wl1-bos-wlz-1",
  "us-east-1-wl1-chi-wlz-1",
  "us-east-1-wl1-clt-wlz-1",
  "us-east-1-wl1-dfw-wlz-1",
  "us-east-1-wl1-dtw-wlz-1",
  "us-east-1-wl1-iah-wlz-1",
  "us-east-1-wl1-mia-wlz-1",
  "us-east-1-wl1-msp-wlz-1",
  "us-east-1-wl1-nyc-wlz-1",
  "us-east-1-wl1-tpa-wlz-1",
  "us-east-1-wl1-was-wlz-1",
  "us-east-1a",   # those should have been the first ones in my opinion
  "us-east-1b",
  "us-east-1c",
  "us-east-1d",
  "us-east-1e",
  "us-east-1f",
])

There are some filters you can specify to exclude local zones:

data "aws_availability_zones" "available" {
  state = "available"

  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]  # exclude local zones
  }
}

Which will not show those strange zones:

> data.aws_availability_zones.available.names
tolist([
  "us-east-1a",
  "us-east-1b",
  "us-east-1c",
  "us-east-1d",
  "us-east-1e",
  "us-east-1f",
])

Let us see if that works for you.