Find Trust Boundaries in VPC Endpoint Connections
Overview
This check ensures that your VPC endpoint policies restrict access to only trusted AWS accounts. VPC endpoints allow private connections between your VPC and AWS services without using the public internet. If these endpoints allow access from untrusted accounts, they can become a security risk.
Risk
When VPC endpoint policies are too permissive, principals from untrusted AWS accounts can access AWS services as if they were inside your VPC. This breaks network segmentation and can lead to:
- Unauthorized access to your data and resources
- Data exfiltration through your private connection
- Unexpected costs from unauthorized usage
- Compliance violations in multi-account environments
Remediation Steps
Prerequisites
- AWS Console access with permissions to modify VPC endpoints
- A list of trusted AWS account IDs that should have access
Required IAM permissions
Your IAM user or role needs these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVpcEndpoints",
"ec2:ModifyVpcEndpoint"
],
"Resource": "*"
}
]
}
AWS Console Method
- Open the VPC Console at https://console.aws.amazon.com/vpc/
- In the left navigation, click Endpoints
- Select the VPC endpoint you want to secure
- Click Actions and choose Manage policy
- Replace the existing policy with one that restricts access to trusted accounts:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictToTrustedAccounts",
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalAccount": [
"123456789012",
"987654321098"
]
}
}
}
]
}
- Replace the account IDs with your own account and any trusted partner accounts
- Click Save
AWS CLI (optional)
List all VPC endpoints and their current policies:
aws ec2 describe-vpc-endpoints \
--region us-east-1 \
--query 'VpcEndpoints[*].{ID:VpcEndpointId,Service:ServiceName,Policy:PolicyDocument}' \
--output json
Update an endpoint with a restricted policy:
First, create a policy file named endpoint-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictToTrustedAccounts",
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalAccount": [
"123456789012",
"987654321098"
]
}
}
}
]
}
Then apply it:
aws ec2 modify-vpc-endpoint \
--vpc-endpoint-id vpce-0123456789abcdef0 \
--policy-document file://endpoint-policy.json \
--region us-east-1
Reset to default policy (allows full access - use with caution):
aws ec2 modify-vpc-endpoint \
--vpc-endpoint-id vpce-0123456789abcdef0 \
--reset-policy \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Endpoint with restricted trust boundary policy
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC ID where the endpoint will be created
ServiceName:
Type: String
Description: The AWS service name (e.g., com.amazonaws.us-east-1.s3)
TrustedAccountId:
Type: String
Description: AWS Account ID allowed to use this endpoint
AllowedPattern: "^[0-9]{12}$"
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Subnet IDs for interface endpoints (leave empty for gateway endpoints)
Default: ""
Resources:
VpcEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref VpcId
ServiceName: !Ref ServiceName
VpcEndpointType: Interface
SubnetIds: !Ref SubnetIds
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: RestrictToTrustedAccounts
Effect: Allow
Principal: '*'
Action: '*'
Resource: '*'
Condition:
StringEquals:
aws:PrincipalAccount:
- !Ref TrustedAccountId
- !Ref AWS::AccountId
Outputs:
VpcEndpointId:
Description: ID of the created VPC endpoint
Value: !Ref VpcEndpoint
Deploy the stack:
aws cloudformation deploy \
--template-file vpc-endpoint.yaml \
--stack-name secure-vpc-endpoint \
--parameter-overrides \
VpcId=vpc-0123456789abcdef0 \
ServiceName=com.amazonaws.us-east-1.s3 \
TrustedAccountId=987654321098 \
SubnetIds=subnet-0123456789abcdef0,subnet-0fedcba9876543210 \
--region us-east-1
Terraform (optional)
variable "vpc_id" {
description = "VPC ID where the endpoint will be created"
type = string
}
variable "service_name" {
description = "The AWS service name (e.g., com.amazonaws.us-east-1.s3)"
type = string
}
variable "trusted_account_ids" {
description = "List of AWS Account IDs allowed to use this endpoint"
type = list(string)
}
variable "subnet_ids" {
description = "Subnet IDs for interface endpoints"
type = list(string)
default = []
}
data "aws_caller_identity" "current" {}
resource "aws_vpc_endpoint" "restricted" {
vpc_id = var.vpc_id
service_name = var.service_name
vpc_endpoint_type = "Interface"
subnet_ids = var.subnet_ids
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "RestrictToTrustedAccounts"
Effect = "Allow"
Principal = "*"
Action = "*"
Resource = "*"
Condition = {
StringEquals = {
"aws:PrincipalAccount" = concat(
[data.aws_caller_identity.current.account_id],
var.trusted_account_ids
)
}
}
}
]
})
tags = {
Name = "restricted-vpc-endpoint"
}
}
output "vpc_endpoint_id" {
description = "ID of the created VPC endpoint"
value = aws_vpc_endpoint.restricted.id
}
Example terraform.tfvars:
vpc_id = "vpc-0123456789abcdef0"
service_name = "com.amazonaws.us-east-1.s3"
trusted_account_ids = ["987654321098", "111122223333"]
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
Apply the configuration:
terraform init
terraform plan
terraform apply
Verification
After updating the endpoint policy, verify the change was applied:
- In the VPC Console, go to Endpoints
- Select your endpoint and review the Policy tab
- Confirm only your trusted account IDs are listed in the condition
CLI verification commands
Check the current policy on an endpoint:
aws ec2 describe-vpc-endpoints \
--vpc-endpoint-ids vpce-0123456789abcdef0 \
--region us-east-1 \
--query 'VpcEndpoints[0].PolicyDocument' \
--output json | jq .
List all endpoints and extract account IDs from their policies:
aws ec2 describe-vpc-endpoints \
--region us-east-1 \
--query 'VpcEndpoints[*].{ID:VpcEndpointId,Service:ServiceName}' \
--output table
Additional Resources
- AWS VPC Endpoints Documentation
- Control Access to VPC Endpoints Using Endpoint Policies
- IAM Condition Keys for VPC Endpoints
- AWS PrivateLink Best Practices
Notes
-
Not all endpoints support custom policies: Some AWS services have endpoints that do not allow policy modifications. This check excludes those endpoints automatically.
-
Gateway vs Interface endpoints: Gateway endpoints (for S3 and DynamoDB) use route table associations, while interface endpoints create ENIs in your subnets. Both support endpoint policies.
-
Wildcard principals with conditions: The policy uses
Principal: "*"with aConditionblock. This is the recommended approach because it allows you to control access via conditions rather than listing specific principals. -
Multi-account environments: In AWS Organizations, consider using Service Control Policies (SCPs) alongside endpoint policies for defense in depth.
-
Testing changes: Before applying restrictive policies in production, test in a non-production environment to ensure legitimate workloads are not blocked.