I'm setting up a VPC endpoint for a corresponding VPC service endpoint.
Our app calls the downstream service using a non- region or zone-specific name (routed to the VPCe).
We have 3 app subnets set on the VPCe (corresponding to 3 availability zones us-west-2a, -2b, -2c).
The service we're calling supports only 2 availability zones (us-west-2a, -2b).
When creating the endpoint (via CloudFormation) I get the following error:
The VPC endpoint service com.amazonaws.vpce.us-west-2.vpce-svc-01234567890123456 does not support the availability zone of the subnet: subnet-0abcdef0123456789. (Service: AmazonEC2; Status Code: 400; Error Code: InvalidParameter; Request ID: ...)
(Where that subnet is in AZ us-west-2c)
What's the fix here?
I can't leave out that subnet without preventing our app in that AZ from using the VPCe, right?
Seems like AWS expects the client and service AZs to match?
I must be misunderstanding something though. Would not expect it to be this rigid. (For example, if service us-west-2c goes down, requests from client us-west-2c should go to service us-west-2a or -2b. That's the whole point of AZs, right?)
Did some more research, and found:
client us-west-2c to a client VPCe in us-west-2a as long as the security group of the VPCe allows for it. The solution will have to involve manually checking for supported availability zones in the service.
This is possible. Here is an example using Terraform:
locals {
subnet_count = length(data.aws_availability_zones.non_local.names)
cidr_block = "10.0.0.0/16"
region = "us-east-1"
}
resource "aws_vpc" "demo" {
cidr_block = local.cidr_block
enable_dns_hostnames = true
...
}
resource "aws_subnet" "demo" {
count = local.subnet_count
vpc_id = aws_vpc.demo.id
cidr_block = cidrsubnet(local.cidr_block, ceil(log(local.subnet_count, 2)), count.index)
availability_zone = data.aws_availability_zones.non_local.names[count.index]
}
data "aws_availability_zones" "non_local" {
# No Local Zones
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones#by-filter
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
resource "aws_vpc_endpoint" "ses" {
vpc_id = aws_vpc.demo.id
service_name = "com.amazonaws.${local.region}.email-smtp"
vpc_endpoint_type = "Interface"
subnet_ids = data.aws_subnet_ids.ses.ids
}
data "aws_vpc_endpoint_service" "ses" {
service = "email-smtp"
}
data "aws_subnets" "ses" {
filter {
name = "vpc-id"
values = [aws_vpc.demo.id]
}
filter {
name = "subnet-id"
values = aws_subnet.demo.*.id
}
filter {
name = "availability-zone"
values = data.aws_vpc_endpoint_service.ses.availability_zones
}
}