How to Configure VPC Endpoints and AWS PrivateLink for EC2?
This article explains how to configure AWS VPC Endpoints and AWS PrivateLink so isolated Amazon EC2 instances in private subnets can securely access AWS APIs without needing an Internet Gateway or NAT Gateway. By setting up Gateway Endpoints for Amazon S3 and DynamoDB alongside Interface Endpoints powered by AWS PrivateLink for other AWS services, you keep all network traffic entirely within the AWS backbone network. You will learn the architectural differences between endpoint types, how to configure security groups and route tables, how to enable private DNS resolution, and how to apply endpoint policies to enforce least-privilege access.
Understanding VPC Endpoints and AWS PrivateLink
When Amazon EC2 instances are deployed in isolated private subnets without internet routing (no Internet Gateway and no NAT Gateway), standard requests to public AWS service endpoints fail because traffic has no path to reach public IP addresses. VPC Endpoints solve this by providing private connectivity between your Virtual Private Cloud (VPC) and supported AWS services.
There are two primary types of VPC Endpoints used to reach AWS APIs:
- Interface VPC Endpoints (AWS PrivateLink): Powered by AWS PrivateLink, Interface Endpoints provision an Elastic Network Interface (ENI) with a private IP address directly inside your subnet. Traffic destined for an AWS API (such as Amazon SQS, AWS KMS, Amazon CloudWatch, or AWS Systems Manager) is directed to this private IP address via DNS resolution.
- Gateway VPC Endpoints: Used exclusively for Amazon S3 and Amazon DynamoDB. Instead of creating an ENI inside your subnet, a Gateway Endpoint acts as a target in your VPC route table. Traffic destined for S3 or DynamoDB is routed using an AWS-managed prefix list directly over the AWS private network.
Prerequisites for Isolated EC2 Connectivity
Before creating VPC Endpoints, ensure your VPC and EC2 environment meet the following network and identity requirements:
- VPC DNS Settings: For Interface Endpoints to
seamlessly override public service hostnames (like
sqs.us-east-1.amazonaws.com) with private IP addresses, your VPC must have bothenableDnsHostnamesandenableDnsSupportset totrue. - IAM Instance Profile: Isolated EC2 instances still require AWS Identity and Access Management (IAM) permissions to authenticate API calls. Attach an IAM role with the necessary policies to your EC2 instance.
- Network Capacity: Ensure your target private subnets have available IPv4 addresses so AWS PrivateLink can allocate an ENI per Availability Zone.
To verify and enable DNS settings on your VPC using the AWS CLI, run the following commands:
aws ec2 modify-vpc-attribute \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--enable-dns-support "{\"Value\":true}"
aws ec2 modify-vpc-attribute \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--enable-dns-hostnames "{\"Value\":true}"Step 1: Configure Security Groups for Interface Endpoints
Because Interface Endpoints deploy Elastic Network Interfaces into your subnets, they are protected by VPC Security Groups. You must create a Security Group for the VPC Endpoint that allows inbound HTTPS (port 443) traffic from your isolated EC2 instances.
- Create a Security Group specifically for your VPC Endpoints (e.g.,
vpce-security-group). - Add an inbound rule permitting TCP port
443from the Security Group attached to your isolated EC2 instances, or from the CIDR block of your private subnets (such as10.0.1.0/24). - Ensure your EC2 instance Security Group allows outbound TCP port
443traffic to the endpoint Security Group or VPC CIDR.
Using the AWS CLI, you can create the endpoint Security Group and
authorize ingress traffic from a VPC CIDR of
10.0.0.0/16:
aws ec2 create-security-group \
--group-name vpce-tls-sg \
--description "Allow HTTPS from VPC to Interface Endpoints" \
--vpc-id vpc-0a1b2c3d4e5f6g7h8
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 443 \
--cidr 10.0.0.0/16Step 2: Create an Interface VPC Endpoint (AWS PrivateLink)
To allow an isolated EC2 instance to communicate with most AWS APIs (for example, AWS KMS, Amazon EC2 API, or AWS Systems Manager), create an Interface VPC Endpoint.
Using the AWS Management Console
- Open the Amazon VPC Console and navigate to Endpoints in the left navigation pane.
- Choose Create endpoint.
- Enter a name tag (for example,
vpce-kms-private). - Under Service category, keep AWS services selected.
- In the Services list, filter for your desired
service (e.g.,
com.amazonaws.us-east-1.kms) and ensure the Type is Interface. - Select your target VPC.
- Under Additional settings, ensure Enable DNS name (Private DNS) is checked. This creates a Route 53 private hosted zone managed by AWS so existing SDKs and CLI commands automatically resolve standard regional endpoints to the private ENI IP addresses without code changes.
- Select the Subnets (one per Availability Zone where your isolated EC2 instances reside).
- Select the Security group created in Step 1
(
vpce-tls-sg). - Under Policy, choose Full access or define a custom VPC Endpoint Policy to restrict which principals and resources can be accessed through this endpoint.
- Click Create endpoint.
Using the AWS CLI
You can create the same Interface Endpoint with Private DNS enabled via the AWS CLI:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.us-east-1.kms \
--subnet-ids subnet-01111111111111111 subnet-02222222222222222 \
--security-group-ids sg-0123456789abcdef0 \
--private-dns-enabledRequired Endpoints for AWS Systems Manager Session Manager
If your EC2 instances are completely isolated and you want shell access without SSH keys, bastions, or public IP addresses, configure the following Interface Endpoints for AWS Systems Manager (SSM):
com.amazonaws.<region>.ssm(Systems Manager core service)com.amazonaws.<region>.ssmmessages(Session Manager channel communication)com.amazonaws.<region>.ec2messages(Run Command and SSM Agent messaging)
Step 3: Create a Gateway VPC Endpoint for S3 and DynamoDB
For Amazon S3 and Amazon DynamoDB, Gateway Endpoints are generally preferred for general API access because they incur no hourly or data-processing charges and scale automatically via your VPC route tables (note that S3 also supports Interface Endpoints if you require access from on-premises networks via VPN or Direct Connect).
Using the AWS Management Console
- In the Amazon VPC Console, navigate to Endpoints and click Create endpoint.
- Select AWS services and search for
com.amazonaws.<region>.s3with the Gateway type. - Select your VPC.
- Select the Route tables associated with your
isolated private subnets. AWS will automatically inject a route linking
the S3 prefix list (e.g.,
pl-63a5400a) to the Gateway Endpoint ID (vpce-xxxx). - Configure your endpoint policy and click Create endpoint.
Using the AWS CLI
Run the following command to provision an S3 Gateway Endpoint and attach it to your private route table:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--vpc-endpoint-type Gateway \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids rtb-0987654321fedcba0Step 4: Harden Access with VPC Endpoint Policies
By default, VPC Endpoints allow full access to the target service for any IAM principal in the VPC that has valid IAM credentials. To implement defense-in-depth and prevent data exfiltration from isolated instances to unauthorized external AWS accounts, attach a restrictive VPC Endpoint Policy.
For example, the following policy restricts an S3 Gateway Endpoint so
EC2 instances can only read and write objects within your organization's
specific bucket (my-isolated-app-bucket), blocking access
to any external S3 buckets:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictToSpecificBucket",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-isolated-app-bucket",
"arn:aws:s3:::my-isolated-app-bucket/*"
]
}
]
}Note that if your isolated EC2 instances use yum,
dnf, or apt to install packages from Amazon
Linux or Ubuntu repositories hosted on S3, or pull container images from
Amazon ECR (which stores image layers in S3), you must also permit
s3:GetObject to the respective AWS-owned regional S3
buckets in your S3 Gateway Endpoint policy.
Step 5: Verify Private Connectivity from the EC2 Instance
Once your endpoints transition to the Available state,
connect to your isolated EC2 instance (for example, via AWS Systems
Manager Session Manager) and verify that traffic is resolving and
routing privately.
1. Verify DNS Resolution for Interface Endpoints
Use dig or nslookup to verify that the
standard AWS service hostname resolves to a private IP address inside
your VPC CIDR range rather than a public IP address:
dig +short kms.us-east-1.amazonaws.comIf Private DNS is working properly, the output will show the private
IPv4 addresses of the endpoint ENIs inside your subnets (such as
10.0.1.45 and 10.0.2.88).
2. Test TCP Connectivity and API Execution
Test port 443 connectivity and run an AWS CLI command against the service:
aws kms list-keys --region us-east-1
aws s3 ls s3://my-isolated-app-bucket --region us-east-1If both commands return results without hanging or timing out, your isolated EC2 instance is successfully communicating with AWS APIs over AWS PrivateLink and Gateway Endpoints without traversing the public internet.
Troubleshooting Common Issues
- Connection Timeouts
(
Connect timeout on endpoint URL):- For Interface Endpoints, verify that Private DNS is
enabled on the endpoint and that
enableDnsSupportandenableDnsHostnamesare enabled on the VPC. Check that the endpoint's Security Group allows inbound TCP port443from the EC2 instance's private IP or Security Group. - For Gateway Endpoints, verify that the route table
associated with the EC2 instance's subnet contains a route targeting the
vpce-...ID for the service's prefix list, and ensure Network ACLs allow ephemeral return traffic.
- For Interface Endpoints, verify that Private DNS is
enabled on the endpoint and that
- Region Mismatch: VPC Endpoints are regional
constructs. If your EC2 instance and VPC Endpoints are in
us-east-1, ensure your AWS CLI or SDK explicitly targetsus-east-1(e.g.,AWS_DEFAULT_REGION=us-east-1). Cross-region API calls will attempt to route to the internet unless inter-region VPC peering and custom DNS routing are configured. - Access Denied (
AccessDeniedor403 Forbidden): When a call fails immediately with an authorization error rather than a network timeout, PrivateLink connectivity is functioning properly. Check three places: the EC2 instance's IAM Role policy, the VPC Endpoint Policy, and any resource-based policy on the target service (such as an S3 bucket policy or KMS key policy, especially if it uses anaws:SourceVpceoraws:SourceVpccondition).