Secured MongoDB container

Maxime Faye
4 min readMay 2, 2018

--

This is a problematic I was recently confronted to and after spending some time on the web (massively on stackoverflow.com) and digging into the MongoDb’s github I finnaly figured that they had everything ready. So without further ado, let’s have a look on how it should be done.

For this article I’ll suppose that you know at least a bit of docker-compose, as this is not the purpose of this article.

Creating the root user

What are we going to do ? First we’re going to create a root user for the instance, then we’re going to create a new user for our application database. The root user creation is quite straight forward :

The basic docker-compose.yml file to have a secured MongoDB container

This will just create a dbAdmin with the provided credentials. We let the MongoDB entrypoint.sh handle the creation of this user and we don’t have to test if the instance is running or if we passed the “ — auth” flag when starting the instance. Not our problem and this the way it should be.

Yay ! We now have a root user for our MongoDB instance, but it’d be a bit dirty (even dangerous) if we used this user for all the needs of our application. So now we’re going to look into how we can create a specific user for our application.

Note : The entrypoint.sh won’t try to create another root, so if you change the password or the user name after creating the db, you’ll be in a world of pain… (See this comment : https://github.com/docker-library/mongo/issues/174#issuecomment-297538188)

Db specific user

For this one there is a bit more to do. First you need to know that within the MongoDB Dockerfile they referring to a /docker-entrypoint-initdb.d/ volume. When you look into the entrypoint.sh from their github you’ll see that they’re in fact going through this directory and executing each .sh or .js file they find in it. So first we need to write the script that will create our new user for our application db :

A simple bash script to create a new user.

This will call the mongo client, connect to the db using the credentials we provided before, create the db if it doesn’t exists and finally create the user with the role “dbOwner”. You need to save this script in a place that’s accessible to docker-compose.
This is nice and all, but we still need to make it available to the MongoDb container. To do this, we’re going to mount the directory where we saved the bash script into the “/docker-entrypoint-initdb.d/” volume, let’s modify the “docker-compose.yml” file accordingly :

updated docker-compose.yml file with mounted bash directory

So now when we’re going to fire the “docker-compose up” command, the “/docker-entrypoint.initdb.d/” directory will be scan and it will execute our little bash script and therefor create our user.
At the end when docker-compose is done starting your container, you can only connect to it using your root access or the application access which is restricted to its db.

Awesome, but :

Every password is in plain text everywhere ?

Well you may need to share your docker-compose.yml file and you may not want others to see the users/passwords you provided. So let’s use another feature of our docker-compose friend : the .env file, from the documentation :

The “.env” file
You can set default values for any environment variables referenced in the Compose file, or used to configure Compose, in an environment file named .env

Ok, so the plan is this : we’re going to create a .env file, set the appropriate variables in it. Next we’re going to replace our hard-coded values with the respective variables. In the end you’ll need to add the .env file to your .gitignore to be sure that it won’t be shared by accident. And because you’re a very nice person, you’ll create a .env.dist file containing the variables that need to be set so that the person retrieving your code later on will be able to set its own values.

The “.env” file

The .env file that MUST not be shared

Nothing to say here, except that there is no special treatment of quotes inside this file. So if you do something like USERNAME=”IAmTheLaw” the USERNAME env var will contain “IAmTheLaw” and not IAmTheLaw

Okay now we have our values ready to be used, still need to use them, first stop, the docker-compose.yml file :

Root user name and password are now provided by the .env file

Now for the bash script, here is the trick : We’re going to use the docker-compose environment feature to send our variables to the bash script. So let’s edit our bash script accordingly :

The bash script is now expecting to find its values within the env vars

Our script will now look into the env vars to find its values. But we still need to pass them. We edit the docker-compose.yml file one last time and we should be done :

We’re done

You now have a secured MongoDB container.
The connexion parameters are stored in a file that isn’t shared.
You did create a .env.dist file that’s committed in your repository so that your fellow developers can use your docker-compose file.

You can return to your normal activity.

--

--