Sunday, September 21, 2025
AWS and MongoDB Atlas: High-Performance Connection with VPC Peering and Terraform


Introduction
The following post is a summary of how to establish a high-performance connection between private workloads in AWS and MongoDB Atlas services.
Atlas is a cloud platform that simplifies the deployment, operation, and scalability of MongoDB databases.
Context
A common reason to consider Atlas services is when you need your MongoDB deployment to have high availability, security, automated backups, and smooth integration with your cloud provider, whether AWS, Azure, or GCP, without the need to manage servers.
Scope
For this post, we will implement VPC Peering, which in short enables secure and private communication between resources hosted in your VPC and Atlas-managed instances without exposing them to the internet.
In addition, to demonstrate subnet connectivity, you will create a pair of EC2 instances within a public network as bastions without access to Atlas. Finally, we will deploy another instance in a private subnet with the ability to access Atlas services.
The following high-level diagram shows the target architecture we are going to implement.

TLDR
All source code can be found in the following repository.
Implementation
For this post we assume that accounts have already been created in both AWS and Atlas.
Otherwise, you can use the following links:
VPC
We start by defining our VPC in us-east-1. At a minimum you must ensure the creation of two subnets. To optimize costs we specify the creation of only one NAT Gateway by setting single_nat_gateway.
It’s important to keep in mind the network segments we are going to work with. For this post we defined 10.0.0.0/16.
// main.tf
// AZ Availables
data "aws_availability_zones" "available" {
state = "available"
}
locals {
vpc_name = "vpc-${var.project_name}"
## Use 3 AZs form data.aws_availability_zones.available.names
azs = slice(data.aws_availability_zones.available.names, 0, 3)
vpc_cidr_block = "10.0.0.0/16"
# Generate 3 private subnets (/24 each)
private_subnets = [
for i in range(3) : cidrsubnet(local.vpc_cidr_block, 8, i)
]
# Generate 3 public subnets (/24 each), offset to avoid overlap
public_subnets = [
for i in range(3) : cidrsubnet(local.vpc_cidr_block, 8, i + 100)
]
additional_public_subnet_tags
local.vpc_name
local.vpc_cidr_block
local.azs
local.private_subnets
local.public_subnets
merge(
local.additional_public_subnet_tags,
)
merge(
local.additional_private_subnet_tags,
)
local.tags
MongoDB Cluster
Next we move on to creating the necessary resources for the MongoDB cluster in Atlas, defining the Mongo Atlas CIDR block as 10.8.0.0/21. It’s important to use the same region between AWS and Atlas.
This ensures there is no overlap between segments and prevents conflicts when setting up VPC peering.
locals {
mongodb_org_id = data.mongodbatlas_roles_org_id.warike_development_mongodb_atlas_org_id
mongodb_project_name = var.mongodbatlas_project_name
mongodb_cluster_name = "cluster-${local.project_name}"
mongodb_provider_name = "AWS"
mongodb_region_name = "US_EAST_1"
mongodb_main_database_name = "database-${random_pet.warike_development_atlas_database.id}"
mongodb_administrator_username = "administrator-${random_string.warike_development_atlas_username.id}"
mongodb_administrator_password = random_password.warike_development_atlas_password.result
atlas_cidr_block = "10.8.0.0/21"
local.mongodb_project_name
data.mongodbatlas_roles_org_id.warike_development_mongodb_atlas_org_id.org_id
local.tags
local.mongodb_administrator_username
local.mongodb_administrator_password
mongodbatlas_project.warike_development_mongodb_atlas_project.id
local.mongodb_main_database_name
random_password.warike_development_atlas_password,
random_string.warike_development_atlas_username,
random_pet.warike_development_atlas_database
mongodbatlas_project.warike_development_mongodb_atlas_project.id
local.mongodb_cluster_name
local.mongodb_provider_name
local.mongodb_region_name
local.tags
After applying the changes we can see the cluster being created in the Atlas platform. Once the process finishes we can view the final result.
The following image shows the MongoDB Atlas dashboard with the cluster created.

VPC Peering
locals {
aws_private_cidr_block = module.vpc.private_subnets_cidr_blocks[0]
mongodb_ip_list = {
"AWS" = local.aws_private_cidr_block,
"MyIP" = var.my_ip
}
}
data "aws_caller_identity" "current" {}
## MongoDB Atlas Network Container
resource "mongodbatlas_network_container" "warike_development_mongodb_atlas_network_container" {
project_id = mongodbatlas_project.warike_development_mongodb_atlas_project.id
atlas_cidr_block = local.atlas_cidr_block
provider_name = local.mongodb_provider_name
region_name = local.mongodb_region_name
}
## MongoDB Atlas Project IP Access List from local mongodb_ip_list
resource "mongodbatlas_project_ip_access_list" "warike_development_mongodb_atlas_ip_access" {
for_each = local.mongodb_ip_list
project_id mongodbatlas_project.warike_development_mongodb_atlas_project.id
each.value
each.key
mongodbatlas_network_container.warike_development_mongodb_atlas_network_container.id
mongodbatlas_project.warike_development_mongodb_atlas_project.id
local.mongodb_provider_name
local.aws_region
module.vpc.vpc_id
data.aws_caller_identity.current.account_id
local.aws_private_cidr_block
mongodbatlas_network_peering.warike_development_mongodb_atlas_network_peering.connection_id
local.project_name
module.vpc.private_route_table_ids
local.atlas_cidr_block
mongodbatlas_network_peering.warike_development_mongodb_atlas_network_peering.connection_id
aws_vpc_peering_connection_accepter.warike_development_mongodb_atlas_vpc_peering_connection_accepter
The next image shows the MongoDB Atlas dashboard with the mapping of the first private subnet segment 10.0.0.0/24, and the Atlas segment 10.8.0.0/21.

Additionally, we can observe the counterpart from our AWS account.

Compute instances
Let’s go ahead and deploy the EC2 instances inside their respective subnets. Additionally, I’ll add the VPC CIDR and my IP so we can move between machines over SSH.
locals {
key_name = "key-${local.project_name}"
key_pair = var.key_pair
instances = {
bastion = {
name = "bastion-${local.project_name}"
type = "t2.micro"
subnet_id = module.vpc.public_subnets[0]
associate_public_ip_address = true
}
internal = {
name = "internal-$"
module.vpc.private_subnets
local.vpc_cidr_block,
var.my_ip
local.key_name
local.key_pair
local.instances
data.aws_ami.latest_amazon_linux.id
each.value.type
each.value.subnet_id
each.value.associate_public_ip_address
aws_key_pair.warike_sandbox_instaces_key_pair.key_name
aws_security_group.warike_sandbox_instances_security_group.id,
each.value.name
each.value.type
module.vpc.vpc_id
local.whitelist_cidr_blocks
-
-
local.whitelist_cidr_blocks
Testing
To test the implementation the first step is knowing the connection string we need to connect to.
We can retrieve it from the following output:
## MongoDB Atlas standard connection string
output "atlas_connection_string" {
value = mongodbatlas_advanced_cluster.warike_development_mongodb_atlas_cluster.connection_strings.standard
}Once we have the connection string, we can try logging into the instances. Below are the commands to access both the instance in the public subnet and the one in the private subnet:
ssh -A -i aws-key.pem ec2-user@<public-ip-bastion>
ssh -A -i aws-key.pem -J ec2-user@<public-ip-bastion> ec2-user@<private-ip-internal>Next, you should install MongoSH on each instance:
echo "[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-7.0.asc" | sudo tee /etc/yum.repos.d/mongodb-org-7.0.repo
sudo yum install -y mongodb-mongosh
mongosh --version
With everything installed, you can attempt the connection:
mongosh "mongodb://<credentials>@<url>:27017/?ssl=true&authSource=admin&replicaSet=atlas-zogrp0-shard-0"
Bastion
As expected, when trying to connect from the Bastion in the public subnet we get a timeout.
Current Mongosh Log ID: 68cd84a4ab953eefb8ce5f46
Connecting to: mongodb://<credentials>@<url>:27017/?ssl=true&authSource=admin&replicaSet=atlas-zogrp0-shard-0
MongoServerSelectionError: Server selection timed out after 30000 ms. It looks like this is a MongoDB Atlas cluster. Please ensure that your Network Access List allows connections from your IP.Internal
Also as expected, when connecting from the Internal instance in the private subnet we get a successful connection.
Current Mongosh Log ID: 68cd843bc940d026fece5f46
Connecting to: mongodb://<credentials>@<url>:27017/?ssl=true&authSource=admin&replicaSet=atlas-zogrp0-shard-0
Using MongoDB: 8.0.13
Using Mongosh: 2.5.8
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).
You can opt-out by running the disableTelemetry() command.
Deprecation warnings:
- Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.
Atlas atlas-zogrp0-shard-0 [primary] test>I can see that as a success.
Conclusions
The process of creating a VPC Peering connection is quite straightforward and efficient. In addition, setting up a secure configuration is simple and well-documented.
This becomes especially important when considering the externalization of the MongoDB service.