Create MongoDB Atlas Cluster With Terraform and AWS

Create MongoDB Atlas Cluster With Terraform and AWS

This project aims to set up an Atlas MongoDB cluster with an AWS network peering to access the resources from AWS EC2, utilizing Terraform as an Infrastructure as a Code(IAC).

Prerequisites Needed:

Basic understanding of Terraform concepts and Terraform CLI installed.
AWS VPC with subnets and route tables.
MongoDB Atlas account.
MongoDB Atlas Organization and a Project under your account with public and private keys with Organization Project Creator API key.

Table of Contents

MongoDB Atlas API key for terraform
MongoDB atlas terraform provider

Module for cluster resource

Cluster Resources
Users and Roles
Network peering with atlas

Plan and apply
Resources

MongoDB Atlas API key for terraform

Once you create an organization in Atlas, access to an organization or project can only be managed using the API key, so we need to create an API key.

API keys have two parts: a Public Key and a Private Key. These two parts serve the same function as a username and a personal API key when you make API requests to Atlas.

You must grant roles to API keys as you would for users to ensure the API keys can call API endpoints without errors. Here we will need an API key that will have Organization Project Creator permissions.
e.g.

All API keys belong to the organization. You can give an API key access to a project. Each API key belongs to only one organization, but you can grant an API key access to any number of projects in that organization.

Configuring the MongoDB atlas provider for Terraform

The Terraform MongoDB Atlas Provider is a plugin that allows you to manage MongoDB Atlas resources using Terraform.
Syntax:

provider.tf

terraform {
required_providers {
aws = {
source = “hashicorp/aws”
version = “~> 4.4”
}
mongodbatlas = {
source = “mongodb/mongodbatlas”
version = “~> 1.9”
}
}
}
provider “mongodbatlas” {
public_key = “<YOUR PUBLIC KEY HERE>”
private_key = “<YOUR PRIVATE KEY HERE>”
}

In our case, all the required variables like Organization ID, Public key, and Private key are created in the AWS Systems Manager Parameter Store and are being referred to respectively.

data “aws_ssm_parameter” “private_key” {
name = “/atlas/private-key”
with_decryption = true
}

data “aws_ssm_parameter” “public_key” {
name = “/atlas/public-key”
with_decryption = true
}

data “aws_ssm_parameter” “atlas_organization_id” {
name = “/atlas/org-id”
with_decryption = true
}

Module for cluster resources

Cluster resources

mongodbatlas_project provides a Project resource. This allows the project to be created.

mongodbatlas_network_container provides a Network Peering Container resource. The resource lets you create, edit, and delete network peering containers. You must delete network peering containers before creating clusters in your project. You can’t delete a network peering container if your project contains clusters. The resource requires your Project ID.

mongodbatlas_project_ip_access_list provides an IP Access List entry resource that grants access from IPs, CIDRs, or AWS Security Groups (if VPC Peering is enabled) to clusters within the Project.

resource “mongodbatlas_project” “this” {
name = var.atlas_project_name
org_id = var.atlas_organization_id
}

resource “mongodbatlas_network_container” “this” {
atlas_cidr_block = var.atlas_cidr_block
project_id = mongodbatlas_project.this.id
provider_name = “AWS”
region_name = local.region_name
}

resource “mongodbatlas_project_ip_access_list” “this” {
project_id = mongodbatlas_network_peering.this.project_id
cidr_block = var.vpc_cidr_block
comment = “Grant AWS ${var.vpc_cidr_block} environment access to Atlas resources”
}

resource “aws_route” “this” {
for_each = toset(var.private_route_table_ids)
route_table_id = each.value
destination_cidr_block = mongodbatlas_network_container.this.atlas_cidr_block
vpc_peering_connection_id = aws_vpc_peering_connection_accepter.this.vpc_peering_connection_id
}

Users and Roles

mongodbatlas_custom_db_role allows you to create custom roles in Atlas when the built-in roles don’t include your desired set of privileges. Atlas applies each database user’s custom roles together with:

Any built-in roles you assign when you add a database user or modify a database user.
Any specific privileges you assign when you add a database user or modify a database user. You can assign multiple custom roles to each database user.
E.g.

resource “mongodbatlas_custom_db_role” “roles” {
for_each = var.custom_roles
project_id = module.atlas_project.project_id
role_name = each.value.role_name

dynamic “actions” {
for_each = each.value.actions
content {
action = actions.value.action
resources {
collection_name = actions.value.resources.collection_name
database_name = actions.value.resources.database_name
}
}
}
}

mongodbatlas_database_user Creates database users to provide clients access to the database deployments in your project. A database user’s access is determined by the roles assigned to the user.

resource “mongodbatlas_database_user” “database_users” {
for_each = var.database_users
username = each.value.username
password = jsondecode(data.aws_secretsmanager_secret_version.creds.secret_string)[each.value.username]
auth_database_name = “admin”
project_id = module.atlas_project.project_id

dynamic “roles” {
for_each = each.value.roles
content {
database_name = roles.value.database_name
role_name = roles.value.role_name
}
}
depends_on = [mongodbatlas_custom_db_role.roles]
}

You can create and upload the username and password details as a key pair values in AWS secret manager using,

aws secretsmanager create-secret –name atlas-users –description “Mytest with multiples values” –secret-string file://secretmanagervalues.json

Where,

file://secretmanagervalues.json

Which will have below values e.g.
{“Juan”:”mykey1″,”Pedro”:”mykey2″,”Pipe”:”mykey3″}

Network peering with atlas

mongodbatlas_network_peering Network peering establishes a private connection between your Atlas VPC and your cloud provider’s VPC. The connection isolates traffic from public networks for added security.

resource “mongodbatlas_network_peering” “this” {
container_id = mongodbatlas_network_container.this.id
project_id = mongodbatlas_project.this.id
provider_name = “AWS”
accepter_region_name = data.aws_region.current.id
vpc_id = var.vpc_id
aws_account_id = data.aws_caller_identity.current.account_id
route_table_cidr_block = var.vpc_cidr_block
}

resource “aws_vpc_peering_connection_accepter” “this” {
vpc_peering_connection_id = mongodbatlas_network_peering.this.connection_id
auto_accept = true
tags = {
Name = var.peering_connection_name
}
}

E.g.

Plan and Apply your terraform code

Your tfvars file should look like this,

environment.tfvars

vpc_id = “<VPC-ID>”
vpc_cidr_block = “10.0.0.0/16”
peering_connection_name = “tf-mongo-atlas”
atlas_project_name = “<Cluster-Name>”

atlas_cidr_block = “<Atlas-CIDR>”

database_users = {
user1 = {
username = “Juan”,
password = “”,
auth_database_name = “admin”
roles = [
{ database_name = “admin”, role_name = “readWriteAnyDatabase” },
]
},
user2 = {
username = “Pedro”,
password = “”,
auth_database_name = “admin”
roles = [
{ database_name = “admin”, role_name = “readWriteAnyDatabase” },
{ database_name = “admin”, role_name = “oplogRead” },
]
},
user3 = {
username = “Pipe”,
password = “”,
auth_database_name = “admin”
roles = [
{ database_name = “admin”, role_name = “readWriteAnyDatabase” },
]
},
// Add more users as needed
}

custom_roles = {
oplogRead = {
role_name = “oplogRead”
actions = [
{
action = “FIND”
resources = {
collection_name = “”
database_name = “anyDatabase”
}
},
{
action = “CHANGE_STREAM”
resources = {
collection_name = “”
database_name = “anyDatabase”
}
},
]
}
# Add more roles if needed
}

Now all you need to do is to plan your terraform code using the terraform plan and verify the changes in the printed plan. You should be seeing one module to be added which will be the atlas cluster with the provided configuration.

After verifying the plan in the above step, run terraform apply to apply your changes. You will see the cluster getting created message on the terminal and your changes will start appearing in your mongoDB console as well. It usually takes about 10 to 15 mins for the cluster to be created.

You will see cluster created like this,

Resources

You can find the project demo code here,
https://github.com/sagary2j/atlas-mongodb-terraform/tree/initial-code

MongoDB atlas: https://registry.terraform.io/providers/mongodb/mongodbatlas/latest

Atlas organizations apiKeys create: https://www.mongodb.com/docs/atlas/cli/stable/command/atlas-organizations-apiKeys-create/#inherited-options

Leave a Reply

Your email address will not be published. Required fields are marked *