# MongoDB Atlas With Terraform: Database Users and Vault

In this tutorial, I will show how to create a user for the MongoDB database in Atlas using Terraform and how to store this credential securely in HashiCorp Vault. We saw in the previous article, MongoDB Atlas With Terraform - Cluster and Backup Policies, how to create a cluster with configured backup policies. Now, we will go ahead and create our first user. If you haven't seen the previous articles, I suggest you look to understand how to get started.

This article is for anyone who intends to use or already uses infrastructure as code (IaC) on the MongoDB Atlas platform or wants to learn more about it.

Everything we do here is contained in the provider/resource documentation: 

 - mongodbatlas_database_user
- vault_kv_secret_v2

> Note: We will not use a backend file. However, for productive implementations, it is extremely important and safer to store the state file in a remote location such as S3, GCS, Azurerm, etc.

## Creating a User
At this point, we will create our first user using Terraform in MongoDB Atlas and store the URI to connect to my cluster in HashiCorp Vault. For those unfamiliar, HashiCorp Vault is a secrets management tool that allows you to securely store, access, and manage sensitive credentials such as passwords, API keys, certificates, and more. It is designed to help organizations protect their data and infrastructure in complex, distributed IT environments. In it, we will store the connection URI of the user that will be created with the cluster we created in the last article.

Before we begin, make sure that all the prerequisites mentioned in the previous article are properly configured: Install Terraform, create an API key in MongoDB Atlas, and set up a project and a cluster in Atlas. These steps are essential to ensure the success of creating your database user.

### Configuring HashiCorp Vault to run on Docker
The first step is to run HashiCorp Vault so that we can test our module. It is possible to run Vault on Docker Local. If you don't have Docker installed, you can download it. After downloading Docker, we will download the image we want to run — in this case, from Vault. To do this, we will execute a command in the terminal `docker pull vault:1.13.3` or download using Docker Desktop.

## Creating the Terraform version file
The version file continues to have the same purpose, as mentioned in other articles, but we will add the version of the Vault provider as something new.

```
terraform {
    required_version = ">= 0.12"
    required_providers {
        mongodbatlas = {
            source = "mongodb/mongodbatlas"
            version = "1.14.0"
        }
        vault = {
            source = "hashicorp/vault"
            version = "4.0.0"
        }
    }
}
```
### Defining the database user and vault resource
After configuring the version file and establishing the Terraform and provider versions, the next step is to define the user resource in MongoDB Atlas. This is done by creating a .tf file — for example, main.tf — where we will create our module. As we are going to make a module that will be reusable, we will use variables and default values so that other calls can create users with different permissions, without having to write a new module.

```
# ------------------------------------------------------------------------------
# RANDOM PASSWORD
# ------------------------------------------------------------------------------
resource "random_password" "default" {
    length = var.password_length
    special = false
}

# ------------------------------------------------------------------------------
# DATABASE USER
# ------------------------------------------------------------------------------
resource "mongodbatlas_database_user" "default" {
    project_id = data.mongodbatlas_project.default.id
    username = var.username
    password = random_password.default.result
    auth_database_name = var.auth_database_name

    dynamic "roles" {
        for_each = var.roles
        content {
            role_name = try(roles.value"role_name"], null)
            database_name = try(roles.value["database_name"], null)
            collection_name = try(roles.value["collection_name"], null)
        }
    }

    dynamic "scopes" {
        for_each = var.scope
        content {
            name = scopes.value["name"]
            type = scopes.value["type"]
        }
    }

    dynamic "labels" {
        for_each = local.tags
        content {
            key = labels.key
            value = labels.value
        }
    }
}

resource "vault_kv_secret_v2" "default" {
    mount = var.vault_mount
    name = var.secret_name
    data_json = jsonencode(local.secret)
}
```

At the beginning of the file, we have the random_password resource that is used to generate a random password for our user. In the mongodbatlas_database_user resource, we will specify our user details. We are placing some values as variables as done in other articles, such as name and auth_database_name with a default value of admin. Below, we create three dynamic blocks: roles, scopes, and labels. For roles, it is a list of maps that can contain the name of the role (read, readWrite, or some other), the database_name, and the collection_name. These values can be optional if you create a user with atlasAdmin permission, as in this case, it does not. It is necessary to specify a database or collection, or if you wanted, to specify only the database and not a specific collection. We will do an example. For the scopes block, the type is a DATA_LAKE or a CLUSTER. In our case, we will specify a cluster, which is the name of our created cluster, the demo cluster. And the labels serve as tags for our user.

Finally, we define the vault_kv_secret_v2 resource that will create a secret in our Vault. It receives the mount where it will be created and the name of the secret. The data_json is the value of the secret; we are creating it in the locals.tf file that we will evaluate below. It is a JSON value — that is why we are encoding it.

In the variable.tf file, we create variables with default values:
```
variable "project_name" {
    description = "The name of the Atlas project"
    type = string
}

variable "cluster_name" {
    description = "The name of the Atlas cluster"
    type = string
}

variable "password_length" {
    description = "The length of the password"
    type = number
    default = 20
}

variable "username" {
    description = "The username of the database user"
    type = string
}

variable "auth_database_name" {
    description = "The name of the database in which the user is created"
    type = string
    default = "admin"
}

variable "roles" {
    description = < Note: Remember to export the environment variables with the public and private key.

```terraform
export MONGODB_ATLAS_PUBLIC_KEY="your_public_key"
export MONGODB_ATLAS_PRIVATE_KEY=your_private_key"
```

Now, we run init and then plan, as in previous articles.

We assess that our plan is exactly what we expect and run the apply to create it.

When running the `terraform apply` command, you will be prompted for approval with `yes` or `no`. Type `yes`.

Now, let's look in Atlas to see if the user was created successfully...

![User displayed in database access][6]

![Access permissions displayed][7]

Let's also look in the Vault to see if our secret was created.

![MongoDB secret URI][8]

It was created successfully! Now, let's test if the URI is working perfectly.

This is the format of the URI that is generated:
`mongosh "mongodb+srv://usr_myapp:@/admin?retryWrites=true&majority&readPreference=secondaryPreferred"`

![Mongosh login ][9]

We connect and will make an insertion to evaluate whether the permissions are adequate — initially, in db1 in collection1.

![Command to insert to db and acknowledged][10]

Success! Now, in db3, make sure it will not have permission in another database.

![Access denied to unauthroized collection][11]
Excellent — permission denied, as expected.

We have reached the end of this series of articles about MongoDB. I hope they were enlightening and useful for you!

To learn more about MongoDB and various tools, I invite you to visit the [Developer Center to read the other articles.

  [1]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt3adf134a1cc654f8/661cefe94c473591d2ee4ca7/image2.png
  [2]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt01b4534800d306c0/661cefe912f2752a7aeff578/image8.png
  [3]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltabb003cbf7efb6fa/661cefe936f462858244ec50/image1.png
  [4]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt2c34530c41490c28/661cefe90aca6b12ed3273b3/image7.png
  [5]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt867d41655e363848/661cefe931ff3a1d35a41344/image9.png
  [6]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltcdaf7406e85f79d5/661cefe936f462543444ec54/image3.png
  [7]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltbb0d0b37cd3e7e23/661cefe91c390d5d3c98ec3d/image10.png
  [8]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt0dc4c9ad575c4118/661cefe9ba18470cf69b8c14/image6.png
  [9]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltc6c61799f656701f/661cf85d4c4735186bee4ce7/image5.png
  [10]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltdd01eaae2a3d9d24/661cefe936f462254644ec58/image11.png
  [11]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt05fe248cb479b18a/661cf85d4c47359b89ee4ce5/image4.png