Skip to main content

Amazon EC2 Should Use VPC Endpoints

Overview

This check verifies that your VPCs have an interface VPC endpoint configured for the Amazon EC2 service. VPC endpoints allow your resources to communicate with EC2 APIs privately, without sending traffic over the public internet.

Risk

Without a VPC endpoint for EC2, API calls from your VPC to the EC2 service travel through the public internet. This creates several risks:

  • Data exposure: Network traffic could be intercepted or monitored
  • DNS hijacking: Attackers could redirect your API calls to malicious endpoints
  • Availability issues: If your NAT gateway or internet gateway fails, EC2 API calls will stop working
  • Compliance gaps: Many compliance frameworks require keeping sensitive traffic off the public internet

Remediation Steps

Prerequisites

You will need:

  • Access to the AWS Console with permissions to create VPC endpoints
  • A VPC with at least one private subnet
  • A security group that allows HTTPS traffic (port 443)
Required IAM permissions

To create VPC endpoints, your IAM user or role needs these permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateVpcEndpoint",
"ec2:DescribeVpcEndpoints",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeVpcs",
"ec2:ModifyVpcEndpoint"
],
"Resource": "*"
}
]
}

AWS Console Method

  1. Open the VPC console at https://console.aws.amazon.com/vpc/
  2. In the left navigation, click Endpoints
  3. Click Create endpoint
  4. For Name tag, enter a descriptive name (e.g., ec2-endpoint)
  5. Under Service category, select AWS services
  6. In the Services search box, type ec2 and select com.amazonaws.us-east-1.ec2
  7. For VPC, select the VPC that needs the endpoint
  8. Under Subnets, select at least one subnet in each Availability Zone where you have resources
  9. For Security groups, select a security group that allows inbound HTTPS (port 443) from your VPC CIDR
  10. Leave Policy set to Full access (you can restrict this later if needed)
  11. Click Create endpoint

The endpoint will show "Pending" status briefly, then change to "Available" within a few minutes.

AWS CLI

First, identify your VPC ID, subnet IDs, and security group ID:

# List your VPCs
aws ec2 describe-vpcs \
--region us-east-1 \
--query 'Vpcs[*].[VpcId,Tags[?Key==`Name`].Value|[0]]' \
--output table

# List subnets in a specific VPC
aws ec2 describe-subnets \
--region us-east-1 \
--filters "Name=vpc-id,Values=<your-vpc-id>" \
--query 'Subnets[*].[SubnetId,AvailabilityZone,Tags[?Key==`Name`].Value|[0]]' \
--output table

Create the VPC endpoint:

aws ec2 create-vpc-endpoint \
--region us-east-1 \
--vpc-id <your-vpc-id> \
--service-name com.amazonaws.us-east-1.ec2 \
--vpc-endpoint-type Interface \
--subnet-ids <subnet-id-1> <subnet-id-2> \
--security-group-ids <your-security-group-id> \
--private-dns-enabled

Example with real values:

aws ec2 create-vpc-endpoint \
--region us-east-1 \
--vpc-id vpc-0abc123def456789 \
--service-name com.amazonaws.us-east-1.ec2 \
--vpc-endpoint-type Interface \
--subnet-ids subnet-0123456789abcdef0 subnet-0fedcba9876543210 \
--security-group-ids sg-0123456789abcdef0 \
--private-dns-enabled
CloudFormation
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Endpoint for Amazon EC2 Service

Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: The ID of the VPC where the endpoint will be created

SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: The subnet IDs where the endpoint network interfaces will be created

SecurityGroupIds:
Type: List<AWS::EC2::SecurityGroup::Id>
Description: Security group IDs to associate with the endpoint

Resources:
EC2VPCEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VpcId
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ec2'
VpcEndpointType: Interface
SubnetIds: !Ref SubnetIds
SecurityGroupIds: !Ref SecurityGroupIds
PrivateDnsEnabled: true

Outputs:
EndpointId:
Description: The ID of the VPC endpoint
Value: !Ref EC2VPCEndpoint

EndpointDnsEntries:
Description: DNS entries for the VPC endpoint
Value: !Join
- ', '
- !GetAtt EC2VPCEndpoint.DnsEntries

Deploy the stack:

aws cloudformation create-stack \
--region us-east-1 \
--stack-name ec2-vpc-endpoint \
--template-body file://template.yaml \
--parameters \
ParameterKey=VpcId,ParameterValue=<your-vpc-id> \
ParameterKey=SubnetIds,ParameterValue="<subnet-id-1>,<subnet-id-2>" \
ParameterKey=SecurityGroupIds,ParameterValue=<your-security-group-id>
Terraform
variable "vpc_id" {
description = "The ID of the VPC where the endpoint will be created"
type = string
}

variable "subnet_ids" {
description = "The subnet IDs where the endpoint network interfaces will be created"
type = list(string)
}

variable "security_group_ids" {
description = "Security group IDs to associate with the endpoint"
type = list(string)
}

resource "aws_vpc_endpoint" "ec2" {
vpc_id = var.vpc_id
service_name = "com.amazonaws.us-east-1.ec2"
vpc_endpoint_type = "Interface"
subnet_ids = var.subnet_ids
security_group_ids = var.security_group_ids
private_dns_enabled = true

tags = {
Name = "ec2-vpc-endpoint"
}
}

output "endpoint_id" {
description = "The ID of the VPC endpoint"
value = aws_vpc_endpoint.ec2.id
}

output "dns_entry" {
description = "DNS entries for the VPC endpoint"
value = aws_vpc_endpoint.ec2.dns_entry
}

Apply the configuration:

terraform init
terraform apply -var="vpc_id=<your-vpc-id>" \
-var='subnet_ids=["<subnet-id-1>","<subnet-id-2>"]' \
-var='security_group_ids=["<your-security-group-id>"]'

Verification

After creating the endpoint, verify it is working:

  1. In the VPC console, go to Endpoints
  2. Find your new endpoint and confirm the Status shows Available
  3. Check that Private DNS names enabled shows Yes
CLI verification
# List EC2 VPC endpoints
aws ec2 describe-vpc-endpoints \
--region us-east-1 \
--filters "Name=service-name,Values=com.amazonaws.us-east-1.ec2" \
--query 'VpcEndpoints[*].[VpcEndpointId,VpcId,State,PrivateDnsEnabled]' \
--output table

Expected output shows available state and True for private DNS:

------------------------------------------------------------------
| DescribeVpcEndpoints |
+---------------------------+---------------+-----------+---------+
| vpce-0abc123def456789 | vpc-0xyz... | available| True |
+---------------------------+---------------+-----------+---------+

Additional Resources

Notes

  • Pricing: Interface VPC endpoints are charged hourly plus data processing fees. Check current pricing before deploying to multiple AZs.
  • Private DNS: When private DNS is enabled, EC2 API calls from your VPC automatically route through the endpoint. No application changes are needed.
  • Security groups: The security group must allow inbound HTTPS (port 443) from the IP ranges that will use the endpoint.
  • Multiple AZs: For high availability, create endpoint network interfaces in multiple Availability Zones.
  • Endpoint policies: You can add an endpoint policy to restrict which EC2 actions are allowed through the endpoint, adding another layer of access control.