VPC Endpoint Service Allowed Principals Trust Boundaries
Overview
This check ensures that your VPC endpoint services only allow trusted AWS accounts (principals) to connect. VPC endpoint services let you expose your internal services to other AWS accounts through AWS PrivateLink. If you allow untrusted accounts or use wildcards (*), anyone could potentially connect to your private services.
Risk
When VPC endpoint services allow untrusted principals:
- Data exposure: Unauthorized accounts can establish private connections to your services
- Unauthorized access: Untrusted parties could access internal APIs or resources
- Service abuse: Uncontrolled access can overload your backend services
- Trust chain issues: In multi-account environments, improper trust relationships create security gaps
Remediation Steps
Prerequisites
You need:
- Access to the AWS Console with permissions to modify VPC endpoint services
- A list of AWS account IDs that should be trusted to access your endpoint service
Required IAM permissions
Your IAM user or role needs these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVpcEndpointServices",
"ec2:DescribeVpcEndpointServicePermissions",
"ec2:ModifyVpcEndpointServicePermissions"
],
"Resource": "*"
}
]
}
AWS Console Method
- Sign in to the AWS VPC Console
- In the left navigation, click Endpoint services
- Select the endpoint service flagged by Prowler
- Click the Allowed principals tab
- Click Edit allowed principals
- Review each principal in the list:
- Remove any wildcard entries (
*) - Remove any account IDs you do not recognize or trust
- Keep only verified, trusted account ARNs
- Remove any wildcard entries (
- Click Save changes
Important: If you need to allow specific accounts, add them in the format:
arn:aws:iam::123456789012:root (replace with the trusted account ID)
AWS CLI (optional)
List your VPC endpoint services:
aws ec2 describe-vpc-endpoint-services \
--region us-east-1 \
--filters "Name=service-state,Values=Available" \
--query 'ServiceDetails[?Owner!=`amazon`].ServiceId' \
--output table
View current allowed principals for a service:
aws ec2 describe-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0
Remove an untrusted principal:
aws ec2 modify-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0 \
--remove-allowed-principals "arn:aws:iam::111111111111:root"
Remove a wildcard entry:
aws ec2 modify-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0 \
--remove-allowed-principals "*"
Add a trusted principal:
aws ec2 modify-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0 \
--add-allowed-principals "arn:aws:iam::123456789012:root"
Batch update (remove untrusted, add trusted):
aws ec2 modify-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0 \
--remove-allowed-principals "*" "arn:aws:iam::111111111111:root" \
--add-allowed-principals "arn:aws:iam::222222222222:root" "arn:aws:iam::333333333333:root"
CloudFormation (optional)
Use AWS::EC2::VPCEndpointServicePermissions to manage allowed principals declaratively:
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Endpoint Service with restricted allowed principals
Parameters:
ServiceId:
Type: String
Description: The ID of the VPC endpoint service
TrustedAccountId:
Type: String
Description: The AWS account ID trusted to access this endpoint service
AllowedPattern: '^\d{12}$'
ConstraintDescription: Must be a valid 12-digit AWS account ID
Resources:
EndpointServicePermissions:
Type: AWS::EC2::VPCEndpointServicePermissions
Properties:
ServiceId: !Ref ServiceId
AllowedPrincipals:
- !Sub 'arn:aws:iam::${TrustedAccountId}:root'
Outputs:
ServiceId:
Description: The VPC endpoint service ID
Value: !Ref ServiceId
Deploy the stack:
aws cloudformation deploy \
--region us-east-1 \
--stack-name vpc-endpoint-service-permissions \
--template-file template.yaml \
--parameter-overrides \
ServiceId=vpce-svc-0123456789abcdef0 \
TrustedAccountId=123456789012
Multiple trusted accounts:
Resources:
EndpointServicePermissions:
Type: AWS::EC2::VPCEndpointServicePermissions
Properties:
ServiceId: !Ref ServiceId
AllowedPrincipals:
- !Sub 'arn:aws:iam::${TrustedAccount1}:root'
- !Sub 'arn:aws:iam::${TrustedAccount2}:root'
- !Sub 'arn:aws:iam::${TrustedAccount3}:root'
No allowed principals (most restrictive):
Resources:
EndpointServicePermissions:
Type: AWS::EC2::VPCEndpointServicePermissions
Properties:
ServiceId: !Ref ServiceId
AllowedPrincipals: []
Terraform (optional)
Use aws_vpc_endpoint_service_allowed_principal to manage trusted accounts:
variable "service_id" {
description = "The ID of the VPC endpoint service"
type = string
}
variable "trusted_account_ids" {
description = "List of trusted AWS account IDs allowed to access the endpoint service"
type = list(string)
default = []
}
# Add trusted principals
resource "aws_vpc_endpoint_service_allowed_principal" "trusted" {
for_each = toset(var.trusted_account_ids)
vpc_endpoint_service_id = var.service_id
principal_arn = "arn:aws:iam::${each.value}:root"
}
Example usage:
module "endpoint_service_permissions" {
source = "./modules/vpc-endpoint-permissions"
service_id = "vpce-svc-0123456789abcdef0"
trusted_account_ids = [
"111111111111",
"222222222222"
]
}
Important: Terraform only manages the principals you explicitly define. To remove untrusted principals, you may need to:
- Import existing principals into Terraform state
- Or manually remove them via CLI/Console first
Using data source to reference existing service:
data "aws_vpc_endpoint_service" "example" {
service_name = "com.amazonaws.vpce.us-east-1.vpce-svc-0123456789abcdef0"
}
resource "aws_vpc_endpoint_service_allowed_principal" "trusted" {
vpc_endpoint_service_id = data.aws_vpc_endpoint_service.example.id
principal_arn = "arn:aws:iam::123456789012:root"
}
Verification
After making changes, verify that only trusted principals remain:
- In the AWS Console, go to VPC > Endpoint services
- Select your endpoint service and click the Allowed principals tab
- Confirm:
- No wildcard (
*) entries exist - Only recognized, trusted account ARNs are listed
- No wildcard (
CLI verification
# List all allowed principals for the service
aws ec2 describe-vpc-endpoint-service-permissions \
--region us-east-1 \
--service-id vpce-svc-0123456789abcdef0 \
--query 'AllowedPrincipals[].Principal' \
--output table
Expected output: Only trusted account ARNs should appear. No * entries.
Re-run Prowler to confirm:
prowler aws --checks vpc_endpoint_services_allowed_principals_trust_boundaries --region us-east-1
Additional Resources
- AWS PrivateLink Documentation
- Managing Permissions for VPC Endpoint Services
- AWS PrivateLink Quotas
- Prowler Check Documentation
Notes
- Impact of removing principals: Existing VPC endpoint connections from removed principals will continue to work. However, they will not be able to create new connections.
- Acceptance required: Even trusted principals must have their connection requests accepted (unless you enable automatic acceptance).
- Multi-account environments: Maintain a centralized list of trusted account IDs. Review this list regularly as organizational structure changes.
- Organization-level trust: Consider using AWS Organizations SCPs to enforce endpoint service policies across accounts.
- Principal types: You can allow specific IAM users or roles instead of entire accounts by using their full ARN (e.g.,
arn:aws:iam::123456789012:role/ServiceRole). Note that ARNs with path components are not supported.