A Terraform primitive module for creating and managing AWS VPC Endpoints. VPC endpoints allow resources inside a VPC to communicate privately with AWS services and VPC endpoint services without requiring internet gateways, NAT devices, VPN connections, or AWS Direct Connect connections.
This module supports all three endpoint types — Interface, Gateway, and GatewayLoadBalancer — and conditionally applies the correct set of arguments for each type. An optional resource-based access policy can be attached to restrict which principals and actions are permitted through the endpoint.
- All Endpoint Types: Supports Interface (PrivateLink), Gateway (S3/DynamoDB), and GatewayLoadBalancer endpoints
- Type-Aware Configuration: Automatically scopes subnet IDs, security groups, route table IDs, and private DNS to the correct endpoint type
- Custom Access Policies: Attach an IAM resource policy via
aws_vpc_endpoint_policyto restrict endpoint access; omit for default full-access - DNS Customization: Configurable
dns_optionsblock for Interface endpoints including dualstack and IPv6 record types - IP Address Types: Supports
ipv4,dualstack, andipv6address families - Flexible Tagging: Pass any tag map; applied directly to the endpoint resource
- Input Validation: Built-in validation for
vpc_endpoint_typeandip_address_typevalues
module "vpc_endpoint" {
source = "github.com/launchbynttdata/tf-aws-module_primitive-vpc_endpoint?ref=1.0.0"
vpc_id = "vpc-0abc123"
service_name = "com.amazonaws.us-east-1.s3"
vpc_endpoint_type = "Interface"
private_dns_enabled = false
subnet_ids = ["subnet-aaa", "subnet-bbb"]
security_group_ids = ["sg-123"]
tags = {
Environment = "production"
Application = "my-app"
}
}module "vpc_endpoint" {
source = "github.com/launchbynttdata/tf-aws-module_primitive-vpc_endpoint?ref=1.0.0"
vpc_id = "vpc-0abc123"
service_name = "com.amazonaws.us-east-1.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = ["rtb-aaa", "rtb-bbb"]
tags = {
Environment = "production"
}
}module "vpc_endpoint" {
source = "github.com/launchbynttdata/tf-aws-module_primitive-vpc_endpoint?ref=1.0.0"
vpc_id = "vpc-0abc123"
service_name = "com.amazonaws.us-east-1.execute-api"
vpc_endpoint_type = "Interface"
private_dns_enabled = true
subnet_ids = ["subnet-aaa"]
security_group_ids = ["sg-123"]
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "AllowSpecificAPI"
Effect = "Allow"
Principal = "*"
Action = ["execute-api:Invoke"]
Resource = "arn:aws:execute-api:us-east-1:123456789012:abc123/*"
}]
})
tags = {
Environment = "production"
Application = "my-api"
}
}module "vpc_endpoint" {
source = "github.com/launchbynttdata/tf-aws-module_primitive-vpc_endpoint?ref=1.0.0"
vpc_id = "vpc-0abc123"
service_name = "com.amazonaws.vpce.us-east-1.vpce-svc-0abc123"
vpc_endpoint_type = "GatewayLoadBalancer"
subnet_ids = ["subnet-aaa"]
tags = {
Environment = "production"
}
}AWS VPC endpoint types each require a different set of arguments. This module automatically scopes attributes to the appropriate type:
| Attribute | Interface | Gateway | GatewayLoadBalancer |
|---|---|---|---|
subnet_ids |
✅ | ❌ | ✅ |
security_group_ids |
✅ | ❌ | ❌ |
private_dns_enabled |
✅ | ❌ | ❌ |
route_table_ids |
❌ | ✅ | ❌ |
dns_options |
✅ | ❌ | ❌ |
Passing attributes for a different type is silently ignored by the module — they are not forwarded to the resource.
When policy is null (default), AWS applies a default policy that grants full access to the service. To restrict access, provide a JSON policy string. The policy is managed via a separate aws_vpc_endpoint_policy resource, which allows it to be updated independently of the endpoint itself.
Setting private_dns_enabled = true requires that the VPC has both enableDnsSupport and enableDnsHostnames enabled. Without these VPC settings, the endpoint will fail to provision private DNS entries.
AWS service names follow the pattern com.amazonaws.<region>.<service> (e.g., com.amazonaws.us-east-1.s3). For partner or custom services, the name follows com.amazonaws.vpce.<region>.<service-id>. Use the AWS CLI or console to discover available service names for your region.
Install required development dependencies:
make configure-dependencies
make configure-git-hooksThis installs:
- Terraform
- Go
- Pre-commit hooks
- Other development tools specified in
.tool-versions
Tests are implemented using Terraform Test Framework for input validation, Terratest + LCAF testing framework for post-deploy integration, and conftest / Regula for policy validation.
# Run the full test suite (Terraform plan/apply tests + Go functional integration tests)
make test
# Run lint + full test suite (authoritative CI entrypoint)
make checkmake check is the authoritative top-level entrypoint used by CI and covers linting followed by all make test stages. make test is the module-level test stage used by that framework entrypoint and is useful for local development when you intentionally want to skip linting.
The make test target runs two stages via GNU Make's double-colon rule composition:
-
Terraform test framework suite (
tfmodule/test/terraform) — Runs all tests undertests/terraform/*.tftest.hcl:inputs_validation.tftest.hcl— plan-based input validation checks; no AWS credentials requiredexamples_complete_apply.tftest.hcl— apply-based integration test againstexamples/complete; requires AWS credentials and creates real resources
-
Go functional integration tests (
tfmodule/test/go) — Runstests/post_deploy_functional/via Terratest:- Deploys
examples/completeusingtest.tfvars, verifies the endpoint state via the AWS EC2 SDK, performs a lightweight tag write probe to confirm mutating access, then destroys all resources tests/post_deploy_functional_readonly/is excluded from this stage by design (see below)
- Deploys
tests/post_deploy_functional_readonly/ contains a non-destructive test (TestVpcEndpointPrimitiveReadOnly) that runs read-only SDK assertions against pre-existing infrastructure without calling terraform apply or terraform destroy. It is intentionally excluded from make test because it requires infrastructure to already be deployed.
To run it against a live environment:
cd tests/post_deploy_functional_readonly && go test -v -timeout 30m| Name | Version |
|---|---|
| terraform | ~> 1.10 |
| aws | ~> 5.100 |
| Name | Version |
|---|---|
| aws | 5.100.0 |
No modules.
| Name | Type |
|---|---|
| aws_vpc_endpoint.endpoint | resource |
| aws_vpc_endpoint_policy.endpoint | resource |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| vpc_id | The ID of the VPC in which to create the endpoint. | string |
n/a | yes |
| service_name | The service name for the endpoint (e.g. com.amazonaws.us-east-1.s3). | string |
n/a | yes |
| vpc_endpoint_type | The VPC endpoint type. Valid values: Interface, Gateway, GatewayLoadBalancer. | string |
"Interface" |
no |
| private_dns_enabled | Whether to enable private DNS for the endpoint. Applies to Interface endpoints only. Requires the VPC to have enableDnsSupport and enableDnsHostnames both set to true. | bool |
false |
no |
| subnet_ids | List of subnet IDs in which to create endpoint network interfaces. Applies to Interface and GatewayLoadBalancer endpoints. | list(string) |
null |
no |
| security_group_ids | List of security group IDs to associate with the endpoint network interfaces. Applies to Interface endpoints only. | list(string) |
[] |
no |
| dns_options | DNS options for the endpoint. Applies to Interface endpoints only. Set dns_record_ip_type to control whether A, AAAA, or dualstack records are created. Set private_dns_only_for_inbound_resolver_endpoint to true to restrict private DNS to Route 53 Resolver inbound endpoints. | object({ |
null |
no |
| route_table_ids | List of route table IDs to associate with the endpoint. Applies to Gateway endpoints only. The AWS provider will add prefix-list routes targeting this endpoint to each specified route table. | list(string) |
[] |
no |
| auto_accept | Accept the VPC endpoint request automatically. Only relevant for endpoint services in the same AWS account; cross-account requests require explicit acceptance by the service owner. | bool |
false |
no |
| ip_address_type | The IP address type for the endpoint. Valid values: ipv4, dualstack, ipv6. When null the service default is used. | string |
null |
no |
| policy | A JSON policy document to attach to the endpoint controlling which principals and actions are permitted. When null, AWS applies a default policy that allows full access to the service. | string |
null |
no |
| tags | Tags to apply to the VPC endpoint resource. | map(string) |
{} |
no |
| Name | Description |
|---|---|
| id | The ID of the VPC endpoint (e.g. vpce-0abc123). |
| arn | The Amazon Resource Name (ARN) of the VPC endpoint. |
| state | The current state of the VPC endpoint. Common values: pendingAcceptance, pending, available, deleting, deleted. |
| dns_entry | The DNS entries for the VPC endpoint. Each entry is an object containing dns_name (the hostname) and hosted_zone_id (the Route 53 hosted zone). Use these values to configure DNS resolution or alias records. |
| network_interface_ids | List of network interface IDs created for the endpoint ENIs. Populated for Interface type endpoints only. Useful for attaching additional security group rules or for network flow log analysis. |
| prefix_list_id | The managed prefix list ID representing the AWS service CIDR ranges. Populated for Gateway type endpoints only. Can be referenced in security group rules to allow traffic to the service without specifying IP ranges directly. |
| policy | The JSON access policy attached to the endpoint. Returns null when no custom policy was provided (AWS default full-access policy is in effect). |