AWS VPC Endpoint Policies: S3, DynamoDB, PrivateLink, and Real Examples
A VPC endpoint policy is a resource-based JSON policy you attach to a VPC endpoint to control which AWS services and resources traffic can reach through that endpoint. It acts as a filter at the network boundary: even if an IAM role has broad permissions, a restrictive endpoint policy limits what that role can do through the endpoint. This guide explains how endpoint policies work for gateway and interface endpoints, how they combine with IAM and bucket policies, and walks through real S3, DynamoDB, and PrivateLink examples.
What is an AWS VPC endpoint policy?
A VPC endpoint policy is a JSON document attached to a VPC endpoint, not to an IAM principal or to a resource like an S3 bucket. It uses IAM policy language (Version, Statement, Effect, Principal, Action, Resource, Condition) and controls which requests are allowed to pass through the endpoint.
Every VPC endpoint starts with a default policy that allows all actions by all principals on all resources. That default provides connectivity but no additional restriction. When you replace it with a custom policy, you define exactly which principals can perform which actions on which resources through that endpoint.
An endpoint policy cannot grant access by itself. The effective permission for any request is the intersection of the endpoint policy, the IAM policy on the calling principal, and any resource-based policy on the target service. If any one of those denies or fails to allow the action, the request is denied.
Simple explanation
Analogy
Think of a VPC endpoint as a private hallway between your office building (VPC) and a specific department (AWS service). The endpoint policy is the security guard at the hallway door. Even if you have a company badge (IAM permissions) that grants access to many departments, the guard only lets you through if your destination is on the approved list for that hallway.
In practice: an application running in a private subnet can use S3, but only for one approved bucket through one approved path. If the app tries to reach an S3 bucket in a different account, even one the IAM role technically has access to, the endpoint policy blocks it.
Why this matters
Many compliance frameworks require that traffic between workloads and storage services never leave a private network. An EC2 instance or Lambda function accessing S3 over the public internet, even with encrypted data, may violate data handling requirements or expose traffic to interception risk.
VPC endpoints solve the routing problem by keeping traffic on the AWS backbone. Endpoint policies go further by restricting which resources can be accessed through that private path. This reduces accidental data exfiltration risk: even if an attacker compromises a workload inside your VPC, endpoint policies can prevent them from copying data to an S3 bucket they control.
A misconfigured IAM role with broad S3 access is far less dangerous if the endpoint policy only allows access to two specific buckets. Endpoint policies tighten the blast radius when things go wrong. That layered approach is a core pattern in AWS security architecture.
How it works
When a workload in your VPC makes a request to an AWS service through a VPC endpoint, the request passes through several layers of control:
- Workload sends request. An EC2 instance, Lambda function, or container makes an API call to an AWS service.
- Route or DNS resolution. For gateway endpoints, a route table entry directs traffic to the endpoint. For interface endpoints, private DNS resolves the service hostname to a private IP.
- Endpoint policy evaluation. The VPC endpoint checks whether the request matches the attached policy. If the policy does not allow the action, the request is denied here.
- IAM policy evaluation. AWS checks whether the calling principal’s IAM policies allow the action.
- Resource policy evaluation. If the target service has a resource-based policy (like an S3 bucket policy), that policy is also evaluated.
The request succeeds only if all applicable controls allow it. No single policy can override a deny from another layer.
For gateway endpoints, traffic routing depends on route table configuration. For interface endpoints, traffic routing depends on private DNS settings and security group rules on the endpoint’s ENI. Both must be correctly configured before the endpoint policy is even evaluated.
Gateway vs interface endpoint policies
AWS offers two types of VPC endpoints, and their policy behavior differs in important ways.
| Feature | Gateway endpoint | Interface endpoint (PrivateLink) |
|---|---|---|
| Supported services | S3 and DynamoDB only | Most AWS services (KMS, Secrets Manager, SQS, SNS, EC2 APIs, and many more) |
| Routing model | Route table entry directs traffic to the endpoint | Private DNS resolves service hostname to a private IP on an ENI |
| IP / DNS behavior | No private IP. Works as a routing-level construct. | Creates an ENI with a private IP in each selected subnet |
| Security groups | Not applicable | Required. Controls which traffic reaches the ENI. |
| Cost | No hourly charge | Hourly charge per AZ plus data processing charges (pricing varies by region and service) |
| Common use cases | Private S3 and DynamoDB access from private subnets | Private access to KMS, Secrets Manager, and other services from private subnets |
| Policy Principal caveat | Principal must be "*". Scope access using conditions like aws:PrincipalArn. | Principal can be a specific IAM ARN or "*" |
| Endpoint policy support | Always supported | Most services support it, but not all. Verify per service. |
For more on how PrivateLink works with interface endpoints, see the PrivateLink overview.
When to use this
Endpoint policies are most useful when you need to restrict what a private workload can reach through a specific network path. Common scenarios include:
- Restrict an application to one S3 bucket. A processing pipeline in a private subnet should only read from and write to its own bucket, not any other bucket in the account or in other accounts.
- Restrict private workloads to a small set of DynamoDB tables. A microservice that only needs the
ordersandproductstables should not be able to scan every table in the account through the endpoint. - Privately access KMS or Secrets Manager. Workloads in private subnets that need to encrypt data or retrieve secrets can use interface endpoints with policies that restrict access to specific keys or secrets.
- Reduce exfiltration paths. Even if a workload is compromised, a restrictive endpoint policy prevents it from copying data to an attacker-controlled S3 bucket or DynamoDB table in another account.
- Meet compliance requirements. Some regulatory frameworks require network-level controls in addition to identity-based controls. Endpoint policies satisfy this layer.
When endpoint policies are not enough
An endpoint policy controls traffic flowing through one specific endpoint. It does not protect traffic that takes a different path (through an internet gateway, a different endpoint, or VPC peering) and it cannot enforce controls on the target resource itself. You still need:
- Least-privilege IAM policies. Endpoint policies are a safety net, not a replacement. The IAM policy on each principal should already follow least privilege. See the IAM access denied troubleshooting guide if policy interactions produce unexpected denies.
- Resource-based policies. An S3 bucket policy can enforce that all access must come through a specific VPC endpoint using the
aws:SourceVpcecondition. Without this, someone accessing the bucket from outside your VPC bypasses the endpoint policy entirely. - Service control policies (SCPs). In multi-account environments, SCPs set organization-wide guardrails. They operate at the account or OU level and are evaluated before endpoint policies.
Do not rely on endpoint policies alone. Use them alongside IAM, resource policies, and SCPs for comprehensive access control. An endpoint policy that blocks bucket X means nothing if the workload can reach bucket X through a NAT gateway instead.
VPC endpoint policy vs IAM policy vs bucket policy vs SCP
| Control type | Where it is attached | What it can restrict | Typical use | Can it grant access on its own? |
|---|---|---|---|---|
| VPC endpoint policy | VPC endpoint | Actions, resources, and principals allowed through the endpoint | Network-level restriction on service access from within the VPC | No. Must intersect with IAM and resource policies. |
| IAM policy | IAM user, role, or group | What the principal can do across all AWS services | Identity-based least-privilege access | Yes (for actions on resources without resource policies) |
| S3 bucket policy | S3 bucket | Who can access the bucket and under what conditions | Cross-account access, enforcing VPC endpoint usage, public access rules | Yes (can grant cross-account access) |
| Service control policy (SCP) | AWS Organization OU or account | Maximum permissions for all principals in the account | Organization-wide guardrails and compliance boundaries | No. Sets a ceiling, does not grant permissions. |
Analogy
Think of each control as a gate in a series. IAM is the first gate, the endpoint policy is the second, the resource policy is the third, and the SCP is the fence around the whole property. A request must pass through every gate to reach its destination. One locked gate stops the request, no matter how wide open the others are.
Example: S3 gateway endpoint policy
This policy restricts an S3 gateway endpoint so that only specific actions on one bucket are allowed. All other S3 access through this endpoint is denied.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificBucketOnly",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::company-app-data",
"arn:aws:s3:::company-app-data/*"
]
}
]
}This policy allows GetObject, PutObject, and ListBucket on the company-app-data bucket. Any attempt to access a different bucket, including attacker-controlled buckets in other accounts, is denied at the endpoint.
Notice that Principal is "*". Gateway endpoint policies require this. To scope access to specific IAM roles, add a condition:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificRoleOnly",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::company-app-data",
"arn:aws:s3:::company-app-data/*"
],
"Condition": {
"ArnEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/app-processing-role"
}
}
}
]
}This version restricts the endpoint to a single IAM role using the aws:PrincipalArn condition. Only the app-processing-role can use this endpoint to reach S3.
Some AWS services (CloudFormation, CodeDeploy, SSM) fetch assets from AWS-managed S3 buckets during operations. If your workloads depend on these services, you may need to add a statement allowing access to specific AWS-managed buckets required by those services. Evaluate this on a per-service basis rather than broadly allowing all aws-* buckets.
Complementary S3 bucket policy using aws:SourceVpce
An endpoint policy only controls traffic that flows through the endpoint. To enforce that all access to a bucket must come through the endpoint, add a bucket policy with a deny condition. Learn more about IAM policy conditions for details on how condition keys work.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAccessNotFromVPCEndpoint",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::company-app-data",
"arn:aws:s3:::company-app-data/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-0a1b2c3d4e5f67890"
}
}
}
]
}This bucket policy denies all S3 actions on company-app-data unless the request arrives through the specified VPC endpoint. Combined with the endpoint policy above, you get two-layer control: the bucket rejects non-endpoint traffic, and the endpoint restricts which buckets are reachable.
If you apply an aws:SourceVpce deny on a bucket before the endpoint is working correctly, you block all access to the bucket, including console access. Always test the endpoint first, and consider adding an exception for a break-glass IAM role. Getting this wrong can require an S3 support ticket to fix.
Example: DynamoDB gateway endpoint policy
This policy restricts a DynamoDB gateway endpoint to allow only specific operations on two tables.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificTablesOnly",
"Effect": "Allow",
"Principal": "*",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:us-east-1:123456789012:table/orders",
"arn:aws:dynamodb:us-east-1:123456789012:table/products"
]
}
]
}This allows GetItem, PutItem, Query, and UpdateItem on the orders and products tables only. Attempts to access any other table, or to perform other operations like Scan or DeleteTable, are denied at the endpoint. The IAM policy on the calling role must also allow these actions for requests to succeed.
Even if a developer accidentally attaches a policy with dynamodb:* on * to a role, the endpoint policy prevents that role from touching any table outside the approved set. It acts as a safety net for human error.
Example: interface endpoint policy
Not all services that support interface endpoints also support endpoint policies. Before writing a policy, check whether the service supports it:
aws ec2 describe-vpc-endpoint-services \
--service-name com.amazonaws.us-east-1.secretsmanager \
--query "ServiceDetails[*].VpcEndpointPolicySupported"If the result is true, you can attach a custom policy. Here is an example for a Secrets Manager interface endpoint that restricts access to secrets with a specific prefix:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificSecrets",
"Effect": "Allow",
"Principal": "*",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/app/*"
}
]
}This policy allows the endpoint to be used only for retrieving secrets whose names start with prod/app/. Any other Secrets Manager call through this endpoint is denied.
Interface endpoints create ENIs in your VPC. The security group on each ENI must allow inbound traffic on port 443 from your workload subnets. If the security group blocks the traffic, requests will time out silently instead of returning a clear policy error.
How to verify your policy is working
After creating or modifying an endpoint, verify that it is correctly configured and that your policy produces the expected allow and deny behavior.
Describe the endpoint
aws ec2 describe-vpc-endpoints \
--vpc-endpoint-ids vpce-0a1b2c3d4e5f67890 \
--query "VpcEndpoints[*].[VpcEndpointId,ServiceName,State,PolicyDocument]"Confirm that the state is available and that the policy document matches what you expect.
Confirm route table associations (gateway endpoints)
aws ec2 describe-vpc-endpoints \
--vpc-endpoint-ids vpce-0a1b2c3d4e5f67890 \
--query "VpcEndpoints[*].RouteTableIds"Verify that the route tables for the subnets your workloads run in are listed. If a subnet’s route table is missing, traffic from that subnet will not use the endpoint. See the route tables guide for more on how route table associations work.
Confirm DNS and security groups (interface endpoints)
For interface endpoints, confirm that private DNS is enabled (if desired) and that the security group allows inbound HTTPS (port 443) from your workload subnets.
aws ec2 describe-vpc-endpoints \
--vpc-endpoint-ids vpce-0a1b2c3d4e5f67890 \
--query "VpcEndpoints[*].[PrivateDnsEnabled,Groups]"Test an allowed action
aws s3 ls s3://company-app-data/ --region us-east-1This should succeed if the endpoint policy, IAM policy, and bucket policy all allow the action.
Test an expected deny
aws s3 ls s3://some-other-bucket/ --region us-east-1This should fail with an access denied error if the endpoint policy restricts access to company-app-data only. If the command succeeds, traffic may not be routing through the endpoint. Check the route table or DNS resolution. For help interpreting access denied errors, see the IAM access denied troubleshooting guide.
1. Endpoint state is available. 2. Route tables (gateway) or security groups (interface) are correctly associated. 3. An allowed action succeeds. 4. A blocked action returns Access Denied. If step 4 passes but step 3 fails, the IAM policy or resource policy is likely the issue, not the endpoint policy.
Common mistakes
- Forgetting route table associations for gateway endpoints. Creating a gateway endpoint does nothing if the route tables for your workload subnets are not associated with it. Traffic continues to flow through the internet gateway or NAT gateway until the route table is updated.
- Assuming endpoint policies replace IAM or resource policies. Endpoint policies are one control layer. A request must be allowed by the endpoint policy, the IAM policy, and any resource-based policy. Relying on the endpoint policy alone leaves other access paths unprotected.
- Using interface endpoints without configuring security groups. Interface endpoints create ENIs in your VPC. If the security group attached to the ENI does not allow inbound HTTPS (port 443) from your workload subnets, requests will time out rather than return a policy error. For more on troubleshooting network issues, check the networking guide.
- Not checking whether a service supports endpoint policies. Not all services that support VPC endpoints also support custom endpoint policies. Attaching a restrictive policy to an endpoint for a service that ignores policies gives you a false sense of security. Always verify with
describe-vpc-endpoint-services. - Writing policies broader than intended. A statement with
"Action": "*"and"Resource": "*"on a targeted endpoint still allows every action on every resource for that service. Be explicit about actions and resources to get meaningful restriction. - Locking yourself out with bucket policy deny statements. Applying an
aws:SourceVpcedeny on a bucket before the endpoint is working correctly can block all access, including console access. Test the endpoint first and include a break-glass exception.
Summary
- A VPC endpoint policy is a resource-based policy attached to the endpoint that controls which principals, actions, and resources are allowed through it.
- Endpoint policies cannot grant access on their own. The effective permission is the intersection of the endpoint policy, IAM policy, and any resource-based policy.
- Gateway endpoints (S3 and DynamoDB) are free and route-table-based. Interface endpoints (most other services) use ENIs and have hourly charges.
- Gateway endpoint policies require
Principal: "*". Useaws:PrincipalArnconditions to scope access to specific roles. - Combine endpoint policies with S3 bucket policies using
aws:SourceVpcefor layered access control. - Not all services support endpoint policies. Verify with
describe-vpc-endpoint-servicesbefore relying on them. - Endpoint policies are one layer in a defense-in-depth model alongside IAM, resource policies, and SCPs.
Frequently asked questions
What is a VPC endpoint policy?
A VPC endpoint policy is a resource-based JSON policy attached directly to a VPC endpoint. It controls which AWS principals, actions, and resources are allowed through that endpoint. Endpoint policies use IAM policy syntax but are separate from IAM policies. Both must allow a request for it to succeed.
What is the difference between a gateway endpoint and an interface endpoint?
Gateway endpoints are available for S3 and DynamoDB only, work by adding entries to route tables, and have no hourly charge. Interface endpoints (powered by PrivateLink) create Elastic Network Interfaces with private IPs, support most other AWS services, require security groups, and have hourly and data-processing charges.
Does an endpoint policy replace IAM policies?
No. An endpoint policy cannot grant access by itself. It restricts what is allowed through the endpoint, but the request must also be permitted by the IAM policy on the calling principal and any resource-based policy on the target. The effective result is the intersection of all controls.
Do all AWS services support endpoint policies?
No. Most services that support VPC endpoints also support endpoint policies, but not all. You can check whether a specific service supports endpoint policies by running aws ec2 describe-vpc-endpoint-services with the --query ServiceDetails[*].VpcEndpointPolicySupported filter.
What is the difference between a VPC endpoint policy and an S3 bucket policy?
A VPC endpoint policy is attached to the endpoint and controls what any traffic flowing through that endpoint can reach. An S3 bucket policy is attached to the bucket and controls who can access the bucket from any path. They are complementary. Use both for layered access control.