Amazon VPC Interface Endpoints should have ENIs in more than one subnet
Overview
This check verifies that your VPC interface endpoints have network interfaces (ENIs) deployed across multiple subnets. Since AWS does not allow you to create VPC endpoints in two subnets within the same Availability Zone, having multiple subnets means your endpoint spans multiple AZs.
Interface endpoints provide private connectivity between your VPC and AWS services without requiring traffic to traverse the public internet. Deploying them across multiple AZs ensures your private connectivity remains available even if one AZ experiences issues.
Risk
If your VPC interface endpoint exists in only a single subnet (and therefore a single AZ):
- Availability impact: An AZ outage could disrupt access to AWS services through the endpoint
- Fallback to public internet: Applications may be forced to route traffic over the public internet, exposing sensitive data to potential interception
- Single point of failure: A localized networking issue could break connectivity to critical services
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify VPC endpoints
- At least two subnets in different Availability Zones within your VPC
AWS Console Method
- Open the VPC Console at https://console.aws.amazon.com/vpc/
- In the left navigation, click Endpoints
- Select the interface endpoint that needs additional subnets
- Click Actions, then Manage subnets
- Check the box next to a subnet in a different Availability Zone
- Click Modify subnets
The endpoint will now have ENIs in multiple AZs, improving its availability.
AWS CLI (optional)
Add a Subnet to an Existing Endpoint
First, identify your VPC endpoint and a subnet in a different AZ:
# List your VPC endpoints
aws ec2 describe-vpc-endpoints \
--region us-east-1 \
--query "VpcEndpoints[?VpcEndpointType=='Interface'].[VpcEndpointId,ServiceName,SubnetIds]" \
--output table
Then add the additional subnet:
aws ec2 modify-vpc-endpoint \
--region us-east-1 \
--vpc-endpoint-id <your-endpoint-id> \
--add-subnet-ids <subnet-id-in-different-az>
Replace:
<your-endpoint-id>with the endpoint ID (e.g.,vpce-0123456789abcdef0)<subnet-id-in-different-az>with a subnet in a different AZ (e.g.,subnet-abcdef1234567890)
Create a New Multi-AZ Endpoint
aws ec2 create-vpc-endpoint \
--region us-east-1 \
--vpc-id <your-vpc-id> \
--service-name com.amazonaws.us-east-1.secretsmanager \
--vpc-endpoint-type Interface \
--subnet-ids <subnet-az1> <subnet-az2> \
--security-group-ids <security-group-id> \
--private-dns-enabled
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Interface Endpoint with Multi-AZ configuration
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: The VPC ID where the endpoint will be created
SubnetId1:
Type: AWS::EC2::Subnet::Id
Description: First subnet ID (in AZ-1)
SubnetId2:
Type: AWS::EC2::Subnet::Id
Description: Second subnet ID (in AZ-2)
SecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: Security group for the VPC endpoint
ServiceName:
Type: String
Description: The AWS service name for the endpoint
Default: com.amazonaws.us-east-1.secretsmanager
Resources:
VpcEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VpcId
ServiceName: !Ref ServiceName
VpcEndpointType: Interface
SubnetIds:
- !Ref SubnetId1
- !Ref SubnetId2
SecurityGroupIds:
- !Ref SecurityGroupId
PrivateDnsEnabled: true
Outputs:
VpcEndpointId:
Description: The ID of the VPC endpoint
Value: !Ref VpcEndpoint
Deploy the stack:
aws cloudformation deploy \
--region us-east-1 \
--template-file template.yaml \
--stack-name multi-az-vpc-endpoint \
--parameter-overrides \
VpcId=<your-vpc-id> \
SubnetId1=<subnet-in-az1> \
SubnetId2=<subnet-in-az2> \
SecurityGroupId=<your-security-group>
Terraform (optional)
variable "vpc_id" {
description = "The VPC ID where the endpoint will be created"
type = string
}
variable "subnet_ids" {
description = "List of subnet IDs in different AZs for the VPC endpoint"
type = list(string)
}
variable "security_group_ids" {
description = "List of security group IDs for the VPC endpoint"
type = list(string)
}
variable "service_name" {
description = "The AWS service name for the endpoint"
type = string
default = "com.amazonaws.us-east-1.secretsmanager"
}
resource "aws_vpc_endpoint" "multi_az_endpoint" {
vpc_id = var.vpc_id
service_name = var.service_name
vpc_endpoint_type = "Interface"
subnet_ids = var.subnet_ids
security_group_ids = var.security_group_ids
private_dns_enabled = true
tags = {
Name = "multi-az-interface-endpoint"
}
}
output "vpc_endpoint_id" {
description = "The ID of the VPC endpoint"
value = aws_vpc_endpoint.multi_az_endpoint.id
}
Example terraform.tfvars:
vpc_id = "vpc-0123456789abcdef0"
subnet_ids = ["subnet-aaaaa11111", "subnet-bbbbb22222"]
security_group_ids = ["sg-0123456789abcdef0"]
service_name = "com.amazonaws.us-east-1.secretsmanager"
Verification
After making changes, confirm your endpoint now spans multiple subnets:
- In the VPC Console, go to Endpoints
- Select your endpoint and view the Subnets tab
- Verify that at least two subnets from different Availability Zones are listed
CLI verification
aws ec2 describe-vpc-endpoints \
--region us-east-1 \
--vpc-endpoint-ids <your-endpoint-id> \
--query "VpcEndpoints[0].SubnetIds" \
--output table
You should see multiple subnet IDs in the output. To confirm they are in different AZs:
aws ec2 describe-subnets \
--region us-east-1 \
--subnet-ids <subnet-id-1> <subnet-id-2> \
--query "Subnets[*].[SubnetId,AvailabilityZone]" \
--output table
Additional Resources
Notes
- Gateway endpoints (used for S3 and DynamoDB) are regional by design and do not require multi-AZ subnet configuration. This check applies only to interface endpoints.
- Each subnet you add will create an additional ENI, which may have associated costs.
- Ensure your security groups allow the necessary traffic to the endpoint ENIs from your application subnets.
- If you enable private DNS for the endpoint, applications can use the standard AWS service endpoint DNS names and traffic will automatically route through the VPC endpoint.