Terraform AWS VPC Module and VPC Endpoints: Production Patterns

The VPC is the foundation of everything you build on AWS. Get the networking wrong and you'll be fighting connectivity issues, security problems, and painful re-architectures for months. The terraform-aws-modules/vpc/aws module is the most popular Terraform module on the registry, and for good reason - it handles all the complexity of VPC creation while giving you full control over the design. This guide covers how to use this module effectively for real-world AWS deployments and how to extend it with VPC endpoints for private connectivity.

Why the VPC Module Matters

A production VPC involves a lot of resources: the VPC itself, subnets across multiple AZs, route tables, internet gateways, NAT gateways, NACLs, VPC endpoints, and more. Writing all of that from scratch is 200+ lines of Terraform. The VPC module packages it into a single, well-tested module call.

The simplest useful VPC has public and private subnets across multiple availability zones.

```hcl
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "my-production-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
privatesubnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public
subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

NAT Gateway for private subnet internet access

enablenatgateway = true
singlenatgateway = true # One NAT for cost savings (use false for HA)

DNS support (required for many AWS services)

enablednshostnames = true
enablednssupport = true
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
```

This creates:
- 1 VPC
- 3 public subnets
- 3 private subnets
- 1 internet gateway
- 1 NAT gateway with an Elastic IP
- Route tables for public and private subnets
- Route table associations

That's about 20 resources from a single module call.

Adding Database Subnets

For RDS and other database services, you'll want dedicated subnets with no internet access at all.

hcl module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.5.0" name = "production-vpc" cidr = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b", "us-east-1c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] database_subnets = ["10.0.201.0/24",

Another common production pattern shows:

hcl module "vpc" { source = "terraform-aws-modules/vpc/aws" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] enable_nat_gateway = true enable_vpn_gateway = true tags = { Terraform = "true" Environment = "dev" } }

By default this module will provision new Elastic IPs for the VPC's NAT Gateways. This means that when creating a new VPC, new IPs are allocated, and when that VPC is destroyed those IPs are released. Sometimes it is handy to keep the same IPs even after the VPC is destroyed and re-created. To that end, it is possible to assign existing IPs to the NAT Gateways.

Warning
v6.x of the module still supports creating a VPC Flow Log within the root (VPC) module. However, this is deprecated behavior and will be removed in v7.0.0. Please use the standalone flow log module instead.

VPC Endpoints with the Official Module

The Terraform AWS VPC Endpoint Module is designed to create VPC endpoints on a existing VPC in your AWS infrastructure. This module offers the ability to automatically generate a dedicated security group for all Interface endpoints when the createendpointsg variable is set to true, we recommend this setting to be set.

  • This module is easy to use with simplified examples
  • Removes the complexity of managing multiple resources manually
  • Deploys the needed resources faster

Examples available here
NOTE: These examples use the latest version of this module Charges apply. See here for more details.

A minimum example using the Boldlink module:

hcl module "minimum_vpc_endpoints" { source = "boldlink/vpc-endpoints/aws/" version = "<latest_version_nr>" vpc_id = local.vpc_id tags = var.tags vpc_endpoints = [ { service_name = "com.amazonaws.${local.region}.dynamodb" vpc_endpoint_type = "Gateway" name = "DynamoDB" route_table_ids = flatten(local.route_table_ids) policy = data.aws_iam_policy_document.ddb_endpoint_policy.json } ] }

You may notice a skipped Checkov alert (CKV2AWS5) in the complete example of our Terraform module for VPC endpoints. This alert is intentionally skipped as our VPC endpoints are configured to utilize security groups only for specific Interface VPC endpoints. The security group attached is specifically designed to allow SSL/TLS inbound traffic on port 443. We have determined that the attachment of security groups to other resources is not applicable in this context.

AWS VPC Endpoints Terraform Sub-Module

Terraform sub-module which creates VPC endpoint resources on AWS.

Usage
See examples directory for working examples to reference:

```hcl
module "endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
vpcid = "vpc-12345678"
security
group_ids = ["sg-12345678"]
endpoints = {
s3 = {

interface endpoint

service = "s3"
privatednsenabled = true
tags = { Name = "s3-vpc-endpoint" }
},
dynamodb = {

gateway endpoint

service = "dynamodb"
routetableids = ["rt-12322456", "rt-43433343", "rt-11223344"]
tags = { Name = "dynamodb-vpc-endpoint" }
},
sns = {
service = "sns"
subnetids = ["subnet-12345678", "subnet-87654321"]
tags = { Name = "sns-vpc-endpoint" }
},
sqs = {
service = "sqs"
private
dnsenabled = true
security
groupids = ["sg-987654321"]
subnet
ids = ["subnet-12345678", "subnet-87654321"]
tags = { Name = "sqs-vpc-endpoint" }
},
}
tags = {
Owner = "user"
Environment = "dev"
}
}
```

Examples
- Complete-VPC with VPC Endpoints.

Requirements

Name Version
terraform >= 0.12.26
aws >= 3.15

Providers

Name Version
aws >= 3.15

Modules

No modules.

Resources

Name Type
awsvpcendpoint.this resource
awsvpcendpoint_service.this data source

Inputs

Name Description Type Default Required
create Determines whether resources will be created bool true no
endpoints A map of interface and/or gateway endpoints containing their properties

Note that interface endpoints create an elastic network interface (ENI) in your subnet, allowing for private connectivity using private IP addresses.

Interface vs Gateway Endpoint Configuration

A local module example for a Gateway endpoint:

hcl module "vpce_endpoint" { source = "./vpc-endpoint" vpc_id = module.networking.dev_proj_1_vpc_id service_name = "com.amazonaws.eu-west-1.s3" vpc_endpoint_type = "Gateway" route_table_ids = [module.networking.dev_proj_1_private_route_table_ids] }

vpc-endpoint/main.tf

```hcl
variable "vpcid" {}
variable "service
name" {}
variable "vpcendpointtype" {}
variable "routetableids" {}

resource "awsvpcendpoint" "s3" {
vpcid = var.vpcid
servicename = var.servicename
vpcendpointtype = var.vpcendpointtype
routetableids = var.routetableids
tags = {
Name = "dev-proj-1-vpce-s3"
}
}

variable "vpc_id" {
type = string
description = "VPC ID"
}

variable "service_name" {
type = string
description = "AWS Service Name for VPC Endpoint"
}

variable "vpcendpointtype" {
type = string
description = "VPC Endpoint Type (Gateway/Interface)"
}

variable "routetableids" {
type = list(string)
description = "List of Route Table IDs"
}
```

After establishing a secure connection to the VPC endpoint, we can now access and list the S3 buckets.

This guide walks you through setting up a VPC, creating subnets, configuring route tables, and finally creating VPC endpoints using Terraform.

Module Interface Details

For the Boldlink VPC endpoints module:

Requirements

Name Version
terraform >= 0.14.11
aws >= 4.60.0

Providers

Name Version
aws 5.46.0

No modules.

Resources

Name Type
awssecuritygroup.allow_443 resource
awsvpcendpoint.endpoint resource
aws_vpc.selected data source

Inputs

Name Description Type Default Required
createendpointsg Specify whether to create Security Group for Interface endpoints bool false no
securitygroupname The name to assign to the interfaces security group string null no
tags A map of tags to assign to the resources map(string) {} no
vpc_endpoints Configuration lists for vpc endpoints any [] no
vpc_id The ID of the VPC in which the endpoint will be used. string n/a yes

Outputs

Name Description
arn The Amazon Resource Name (ARN) of the VPC endpoint.
cidr_blocks The list of CIDR blocks for the exposed AWS service. Applicable for endpoints of type Gateway.
dns_entry The DNS entries for the VPC Endpoint

Production Best Practices

Combining the VPC module with VPC endpoints creates a secure, private networking foundation. The VPC module handles the heavy lifting of subnets, NAT gateways, route tables, and internet gateways. The VPC endpoints module then adds private connectivity to AWS services without traversing the public internet.

When using interface endpoints, ensure security groups only allow SSL/TLS inbound traffic on port 443. The module can automatically generate a dedicated security group for all Interface endpoints when createendpointsg is set to true.

For gateway endpoints like DynamoDB and S3, route table associations are required. For interface endpoints, subnet selection and security group association are required.

Conclusion

Using terraform-aws-modules/vpc/aws for VPC creation and the dedicated VPC endpoints sub-module or companion modules for endpoint creation reduces configuration errors and speeds delivery. The VPC module abstracts 200+ lines of networking resources into a single call with explicit parameters for AZs, subnets, NAT gateways, DNS support, and tagging. The endpoints sub-module provides a declarative map for interface and gateway endpoints with support for private DNS, security groups, subnet selection, and route table binding.

Together these modules enable repeatable, production-grade AWS networking with private service connectivity, cost-controlled NAT placement, and clear separation of public, private, and database tiers. Adopting the modules ensures consistency across environments and avoids manual drift while keeping full control over the design.

Sources

  1. OneUptime Blog
  2. TerraformFoundation GitHub
  3. TerraformGuru
  4. Terraform AWS Modules VPC GitHub
  5. LinkedIn Pulse

Related Posts