# How to Deploy MongoDB Atlas with Terraform on AWS

**MongoDB Atlas** is the multi-cloud developer data platform that provides an integrated suite of cloud database and data services. We help to accelerate and simplify how you build resilient and performant global applications on the cloud provider of your choice.

**HashiCorp Terraform** is an Infrastructure-as-Code (IaC) tool that lets you define cloud resources in human-readable configuration files that you can version, reuse, and share. Hence, we built the **Terraform MongoDB Atlas Provider** that automates infrastructure deployments by making it easy to provision, manage, and control Atlas configurations as code on any of the three major cloud providers.

In addition, teams can also choose to deploy MongoDB Atlas through the MongoDB Atlas CLI (Command-Line Interface), Atlas Administration API, AWS CloudFormation, and as always, with the Atlas UI (User Interface).

In this blog post, we will learn how to deploy MongoDB Atlas hosted on AWS using Terraform. In addition, we will explore how to use Private Endpoints with AWS Private Link to provide increased security with private connectivity for your MongoDB Atlas cluster without exposing traffic to the public internet.

We designed this Quickstart for beginners with no experience with MongoDB Atlas, HashiCorp Terraform, or AWS and seeking to set up their first environment. Feel free to access all source code described below from this GitHub repo.

Let’s get started:

## Step 1: Create a MongoDB Atlas account

Sign up for a free MongoDB Atlas account, verify your email address, and log into your new account.

Already have an AWS account? Atlas supports paying for usage via the AWS Marketplace (AWS MP) without any upfront commitment — simply sign up for MongoDB Atlas via AWS Marketplace.

## Step 2: Generate MongoDB Atlas API access keys

Once you have an account created and are logged into MongoDB Atlas, you will need to generate an API key to authenticate the Terraform MongoDB Atlas Provider.

Go to the top of the Atlas UI, click the **Gear Icon** to the right of the organization name you created, click **Access Manager** in the lefthand menu bar, click the **API Keys** tab, and then click the green **Create API Key** box.

Enter a description for the API key that will help you remember what it’s being used for — for example “Terraform API Key.” Next, you’ll select the appropriate permission for what you want to accomplish with Terraform. Both the Organization Owner and Organization Project Creator roles (see role descriptions below) will provide access to complete this task, but by using the principle of least privilege, let’s select the Organization Project Creator role in the dropdown menu and click Next.

Make sure to copy your private key and store it in a secure location. After you leave this page, your full private key will **not**be accessible.

## Step 3: Add API Key Access List entry

MongoDB Atlas API keys have specific endpoints that require an API Key Access List. Creating an API Key Access List ensures that API calls must originate from IPs or CIDR ranges given access. As a good refresher, learn more about cloud networking.

On the same page, scroll down and click **Add Access List Entry**. If you are unsure of the IP address that you are running Terraform on (and you are performing this step from that machine), simply click **Use Current IP Address** and **Save**. Another option is to open up your IP Access List to all, but this comes with significant potential risk. To do this, you can add the following two CIDRs: **0.0.0.0/1** and **128.0.0.0/1**. These entries will open your IP Access List to at most 4,294,967,296 (or 2^32) IPv4 addresses and should be used with caution.

## Step 4: Set up billing method

Go to the lefthand menu bar and click **Billing** and then **Add Payment Method**. Follow the steps to ensure there is a valid payment method for your organization. Note when creating a free (forever) or M0 cluster tier, you can skip this step.

## Step 5: Install Terraform

Go to the official HashiCorp Terraform downloads page and follow the instructions to set up Terraform on the platform of your choice. For the purposes of this demo, we will be using an Ubuntu/Debian environment.

## Step 6: Defining the MongoDB Atlas Provider with environment variables

We will need to configure the MongoDB Atlas Provider using the MongoDB Atlas API Key you generated earlier (Step 2). We will be securely storing these secrets as Environment Variables.

First, go to the terminal window and create Environment Variables with the below commands. This prevents you from having to hard-code secrets directly into Terraform config files (which is not recommended):

```
export MONGODB_ATLAS_PUBLIC_KEY=""
export MONGODB_ATLAS_PRIVATE_KEY=""
```

Next, create in an empty directory with an empty file called **provider.tf**. Here we will input the following code to define the MongoDB Atlas Provider. This will automatically grab the most current version of the Terraform MongoDB Atlas Provider.

```
# Define the MongoDB Atlas Provider
terraform {
  required_providers {
    mongodbatlas = {
      source = "mongodb/mongodbatlas"
    }
  }
  required_version = ">= 0.13"
}
```

## Step 7: Creating variables.tf, terraform.tfvars, and main.tf files

We will now create a **variables.tf** file to declare all the Terraform variables used as part of this exercise and all of which are of type string. Next, we’ll define values (i.e. our secrets) for each of these variables in the **terraform.tfvars** file. Note as with most secrets, best practice is not to upload them (or the **terraform.tfvars** file itself) to public repos.

```
# Atlas Organization ID 
variable "atlas_org_id" {
  type        = string
  description = "Atlas Organization ID"
}
# Atlas Project Name
variable "atlas_project_name" {
  type        = string
  description = "Atlas Project Name"
}

# Atlas Project Environment
variable "environment" {
  type        = string
  description = "The environment to be built"
}

# Cluster Instance Size Name 
variable "cluster_instance_size_name" {
  type        = string
  description = "Cluster instance size name"
}

# Cloud Provider to Host Atlas Cluster
variable "cloud_provider" {
  type        = string
  description = "AWS or GCP or Azure"
}

# Atlas Region
variable "atlas_region" {
  type        = string
  description = "Atlas region where resources will be created"
}

# MongoDB Version 
variable "mongodb_version" {
  type        = string
  description = "MongoDB Version"
}

# IP Address Access
variable "ip_address" {
  type = string
  description = "IP address used to access Atlas cluster"
}
```

The example below specifies to use the most current MongoDB version (as of this writing), which is 6.0, a M10 cluster tier which is great for a robust development environment and will be deployed on AWS in the US\_WEST\_2 Atlas region. For specific details about all the available options besides M10 and US\_WEST\_2, please see the documentation.

```
atlas_org_id = ""
atlas_project_name = "myFirstProject"
environment = "dev"
cluster_instance_size_name = "M10"
cloud_provider = "AWS"
atlas_region = "US_WEST_2"
mongodb_version = "6.0"
ip_address = ""
```

Next, create a **main.tf** file, which we will populate together to create the minimum required resources to create and access your cluster: a MongoDB Atlas Project (Step 8), Database User/Password (Step 9), IP Access List (Step 10), and of course, the MongoDB Atlas Cluster itself (Step 11). We will then walk through how to create Terraform Outputs (Step 12) so you can access your Atlas cluster and then create a Private Endpoint with AWS PrivateLink (Step 13). If you are already familiar with any of these steps, feel free to skip ahead.

Note: As infrastructure resources get created, modified, or destroyed, several more files will be generated in your directory by Terraform (for example the **terraform.tfstate** file). It is best practice not to modify these additional files directly unless you know what you are doing.

## Step 8: Create MongoDB Atlas project

MongoDB Atlas Projects helps to organize and provide granular access controls to our resources inside our MongoDB Atlas Organization. Note MongoDB Atlas “Groups” and “Projects” are synonymous terms.

To create a Project using Terraform, we will need the **MongoDB Atlas Organization ID** with at least the Organization Project Creator role (defined when we created the MongoDB Atlas Provider API Keys in Step 2).

To get this information, simply click on **Settings** on the lefthand menu bar in the Atlas UI and click the copy icon next to Organization ID. You can now paste this information as the atlas\_org\_id in your **terraform.tfvars** file.

Next in the **main.tf** file, we will use the resource **mongodbatlas\_project** from the Terraform MongoDB Atlas Provider to create our Project. To do this, simply input:

```
# Create a Project
resource "mongodbatlas_project" "atlas-project" {
  org_id = var.atlas_org_id
  name = var.atlas_project_name
}
```

## Step 9: Create MongoDB Atlas user/password

To authenticate a client to MongoDB, like the MongoDB Shell or your application code using a MongoDB Driver (officially supported in Python, Node.js, Go, Java, C#, C++, Rust, and several others), you must add a corresponding Database User to your MongoDB Atlas Project. See the documentation for more information on available user roles so you can customize the user’s RBAC (Role Based Access Control) as per your team’s needs.

For now, simply input the following code as part of the next few lines in the **main.tf** file to create a Database User with a random 16-character password. This will use the resource **mongodbatlas_database_user** from the Terraform MongoDB Atlas Provider. The database user_password is a sensitive secret, so to access it, you will need to input the “**terraform output -json user_password**” command in your terminal window after our deployment is complete to reveal.

```
# Create a Database User
resource "mongodbatlas_database_user" "db-user" {
  username = "user-1"
  password = random_password.db-user-password.result
  project_id = mongodbatlas_project.atlas-project.id
  auth_database_name = "admin"
  roles {
    role_name     = "readWrite"
    database_name = "${var.atlas_project_name}-db"
  }
}

# Create a Database Password
resource "random_password" "db-user-password" {
  length = 16
  special = true
  override_special = "_%@"
}
```

## Step 10: Create IP access list

Next, we will create the IP Access List by inputting the following into your **main.tf** file. Be sure to lookup the IP address (or CIDR range) of the machine where you’ll be connecting to your MongoDB Atlas cluster from and paste it into the **terraform.tfvars** file (as shown in code block in Step 7). This will use the resource **mongodbatlas_project_ip_access_list** from the Terraform MongoDB Atlas Provider.

```
# Create Database IP Access List 
resource "mongodbatlas_project_ip_access_list" "ip" {
  project_id = mongodbatlas_project.atlas-project.id
  ip_address = var.ip_address
}
```

## Step 11: Create MongoDB Atlas cluster

We will now use the **mongodbatlas_advanced_cluster** resource to create a MongoDB Atlas Cluster. With this resource, you can not only create a deployment, but you can manage it over its lifecycle, scaling compute and storage independently, enabling cloud backups, and creating analytics nodes.

In this example, we group three database servers together to create a replica set with a primary server and two secondary replicas duplicating the primary's data. This architecture is primarily designed with high availability in mind and can automatically handle failover if one of the servers goes down — and recover automatically when it comes back online. We call all these nodes *electable* because an election is held between them to work out which one is primary.

We will also set the optional *backup_enabled* flag to true. This provides increased data resiliency by enabling localized backup storage using the native snapshot functionality of the cluster's cloud service provider (see documentation).

Lastly, we create one *analytics* node. Analytics nodes are read-only nodes that can exclusively be used to execute database queries on. That means that this analytics workload is isolated to this node only so operational performance isn't impacted. This makes analytic nodes ideal to run longer and more computationally intensive analytics queries on without impacting your replica set performance (see documentation).

```
# Create an Atlas Advanced Cluster 
resource "mongodbatlas_advanced_cluster" "atlas-cluster" {
  project_id = mongodbatlas_project.atlas-project.id
  name = "${var.atlas_project_name}-${var.environment}-cluster"
  cluster_type = "REPLICASET"
  backup_enabled = true
  mongo_db_major_version = var.mongodb_version
  replication_specs {
    region_configs {
      electable_specs {
        instance_size = var.cluster_instance_size_name
        node_count    = 3
      }
      analytics_specs {
        instance_size = var.cluster_instance_size_name
        node_count    = 1
      }
      priority      = 7
      provider_name = var.cloud_provider
      region_name   = var.atlas_region
    }
  }
}
```

## Step 12: Create Terraform outputs

You can output information from your Terraform configuration to the terminal window of the machine executing Terraform commands. This can be especially useful for values you won’t know until the resources are created, like the random password for the database user or the connection string to your Atlas cluster deployment. The code below in the **main.tf** file will output these values to the terminal display for you to use after Terraform completes.

```
# Outputs to Display
output "atlas_cluster_connection_string" { value = mongodbatlas_advanced_cluster.atlas-cluster.connection_strings.0.standard_srv }
output "ip_access_list"    { value = mongodbatlas_project_ip_access_list.ip.ip_address }
output "project_name"      { value = mongodbatlas_project.atlas-project.name }
output "username"          { value = mongodbatlas_database_user.db-user.username } 
output "user_password"     { 
  sensitive = true
  value = mongodbatlas_database_user.db-user.password 
  }
```

## Step 13: Set up a private endpoint to your MongoDB Atlas cluster

Increasingly, we see our customers want their data to traverse only private networks. One of the best ways to connect to Atlas over a private network from AWS is to use AWS PrivateLink, which establishes a one-way connection that preserves your perceived network trust boundary while eliminating additional security controls associated with other options like VPC peering (Azure Private Link and GCP Private Service Connect are supported, as well). Learn more about AWS Private Link with MongoDB Atlas.

To get started, we will need to first **Install the AWS CLI**. If you have not already done so, also see AWS Account Creation and AWS Access Key Creation for more details.

Next, let’s go to the terminal and create AWS Environment Variables with the below commands (similar as we did in Step 6 with our MongoDB Atlas credentials). Use the same region as above, except we will use the AWS naming convention instead, i.e., “us-west-2”.

```
export AWS_ACCESS_KEY_ID=""
export AWS_SECRET_ACCESS_KEY=""
export AWS_DEFAULT_REGION=""
```

Then, we add the AWS provider to the **provider.tf** file. This will enable us to now deploy AWS resources from the **Terraform AWS Provider** in addition to MongoDB Atlas resources from the **Terraform MongoDB Atlas Provider** directly from the same Terraform config files.

```
# Define the MongoDB Atlas and AWS Providers
terraform {
  required_providers {
    mongodbatlas = {
      source = "mongodb/mongodbatlas"
    }
    aws = {
      source = "hashicorp/aws"
    }
  }
  required_version = ">= 0.13"
}
```

We now add a new entry in our **variables.tf** and **terraform.tfvars** files for the desired AWS region. As mentioned earlier, we will be using “us-west-2” which is the AWS region in Oregon, USA.

**variables.tf**

```
# AWS Region
variable "aws_region" {
  type = string
  description = "AWS Region"
}
```

**terraform.tfvars**

```
aws_region = "us-west-2"
```

Next we create two more files for each of the new types of resources to be deployed: **aws-vpc.tf** to create a full network configuration on the AWS side and **atlas-pl.tf** to create both the Amazon VPC Endpoint and the MongoDB Atlas Endpoint of the PrivateLink. In your environment, you may already have an AWS network created. If so, then you’ll want to include the correct values in the **atlas-pl.tf** file and won’t need **aws-vpc.tf** file. To get started quickly, we will simply git clone them from our repo.

After that we will use a Terraform Data Source and wait until the PrivateLink creation is completed so we can get the new connection string for the PrivateLink connection. In the **main.tf**, simply add the below:

```
data "mongodbatlas_advanced_cluster" "atlas-cluser" {
  project_id = mongodbatlas_project.atlas-project.id
  name       = mongodbatlas_advanced_cluster.atlas-cluster.name
  depends_on = mongodbatlas_privatelink_endpoint_service.atlaseplink]
}
```

Lastly, staying in the **main.tf** file, we add the below additional output code snippet in order to display the [Private Endpoint-Aware Connection String to the terminal:

```
output "privatelink_connection_string" {
  value = lookup(mongodbatlas_advanced_cluster.atlas-cluster.connection_strings0].aws_private_link_srv, aws_vpc_endpoint.ptfe_service.id)
}
```

## Step 14: Initializing Terraform

We are now all set to start creating our first MongoDB Atlas deployment!

Open the terminal console and type the following command: **terraform init** to initialize Terraform. This will download and install both the Terraform AWS and MongoDB Atlas Providers (if you have not done so already).

![terraform init command, Terraform has been successfully initialized!

## Step 15: Review Terraform deployment

Next, we will run the **terraform plan** command. This will output what Terraform plans to do, such as creation, changes, or destruction of resources. If the output is not what you expect, then it’s likely an issue in your Terraform configuration files.

## Step 16: Apply the Terraform configuration

Next, use the **terraform apply** command to deploy the infrastructure. If all looks good, input **yes** to approve terraform build.

**Success!**

Note new AWS and MongoDB Atlas resources can take \~15 minutes to provision and the provider will continue to give you a status update until it is complete. You can also check on progress through the Atlas UI and AWS Management Console.

The connection string shown in the output can be used to access (including performing CRUD operations) on your MongoDB database via the MongoDB Shell, MongoDB Compass GUI, and Data Explorer in the UI (as shown below). Learn more about how to interact with data in MongoDB Atlas with the MongoDB Query Language (MQL). As a pro tip, I regularly leverage the MongoDB Cheat Sheet to quickly reference key commands.

Lastly, as a reminder, the database user_password is a sensitive secret, so to access it, you will need to input the “**terraform output -json user_password**” command in your terminal window to reveal.

## Step 17: Terraform destroy

Feel free to explore more complex environments (including code examples for deploying MongoDB Atlas Clusters from other cloud vendors) which you can find in our public repo examples. When ready to delete all infrastructure created, you can leverage the **terraform destroy command**.

Here the resources we created earlier will all now be terminated. If all looks good, input **yes**:

After a few minutes, we are back to an empty slate on both our MongoDB Atlas and AWS environments. It goes without saying, but please be mindful when using the terraform destroy command in any kind of production environment.

The HashiCorp Terraform MongoDB Atlas Provider is an open source project licensed under the Mozilla Public License 2.0 and we welcome community contributions. To learn more, see our contributing guidelines. As always, feel free to contact us with any issues.

Happy Terraforming with MongoDB Atlas on AWS!