Recently I had to setup a MongoDB instance on one of our servers to use in an internal application we're building during Hackfridays. I went with MongoDB because my experience with it is very superficial and Hackfriday projects are perfect to delve into unknown tech (and it also fitted the purpose of the application).
The server where the database would reside is used for multiple internal tools, so my idea was to run MongoDB on a Docker container to keep it isolated and easier to manage.
After figuring that out, my first thought was that I needed to use the firewall to block MongoDB's port (27017) since I only needed internal usage at the moment.
Installing and configuring Ubuntu's
ufw (Uncomplicated Firewall) is as simple as this:
$ apt install ufw $ ufw enable $ ufw allow "OpenSSH"
In the example, we're adding the OpenSSH profile to the allowed rules. This allows connections on port 22 with the TCP protocol (IPv4 and IPv6). Check enabled rules and general status info with
$ ufw status Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), deny (routed) New profiles: skip To Action From -- ------ ---- 22/tcp (OpenSSH) ALLOW IN Anywhere 22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
After making sure that
ufw was not accepting connections to port 27017, I went ahead with the basic setup to run the container with a mounted data volume.
$ mkdir -p /var/docker/mongo/data $ docker run --rm -d -p 27017:27017 --name mongodb \ -v /var/docker/mongo/data:/data/db \ mongo
However, in the middle of all this, someone mentioned that I probably needed to add further security measures as Docker would bypass the firewall. Wait, what?! Yes, Docker manipulates
iptables (which is the actual firewall beneath
ufw). You can read more about it here (https://docs.docker.com/network/iptables/).
A quick check allowed me to verify this. I was able to connect to MongoDB from my computer using a management tool (Robot 3T, in my case).
It is possible to prevent this behavior by setting the
iptables option to
false in the
DOCKER_OPTS environment variable. This didn't seem to be the best option to me because:
- it's not the default and advised behavior;
- we already had other containers running on this machine;
- Friday is definitely not a good day to break stuff.
The solution is quite simple: enable authentication in MongoDB. This should actually have been one of the first things to setup but hey, I'm a MongoDB noob!
By default, if you start a MongoDB instance, it won't have any authentication setup. This can be activated by making some changes to the config file. Since there is no configuration file, it needs to be created. You can find one by entering the container and taking
/etc/mongod.conf.orig or you can get it on MongoDB's GitHub repo: https://github.com/mongodb/mongo/blob/master/rpm/mongod.conf. By default, MongoDB will look for a configuration file in
You then add this block and restart the service:
security: authorization: "enabled"
The file should look like this:
# mongod.conf # ogirinal default file can be found here: https://github.com/mongodb/mongo/blob/master/rpm/mongod.conf # for documentation of all options, see: # http://docs.mongodb.org/manual/reference/configuration-options/ # where to write logging data. systemLog: destination: file logAppend: true path: /var/log/mongodb/mongod.log # network interfaces # net: # port: 27017 # bindIp: 127.0.0.1 # how the process runs processManagement: timeZoneInfo: /usr/share/zoneinfo security: authorization: "enabled"
Notice also the
network interfaces. By keeping it commented, MongoDB will accept connections from any IP address. You can uncomment as is to accept only local connections, or you can add additional addresses.
Now, the problem with our configuration file is that it is not persisted and you would need to restart the MongoDB service inside the container. This is a bit nonsense.
The final solution is to keep the configuration file in your computer, mount another volume and tell MongoDB that it should read a configuration file.
I've created a
cnf directory next to my
data directory in
/var/docker/mongo/. Side note: I now run all my local databases in Docker, and mount whatever volumes I need in
/var/docker, such as
Create the directory where I would mount the config volume:
mkdir -p /var/docker/mongo/cnf
Run mongo on Docker:
docker run --rm -d -p 27017:27017 --name mongodb \ -v /var/docker/mongo/data:/data/db \ -v /var/docker/mongo/cnf:/etc/mongo \ -e MONGO_INITDB_ROOT_USERNAME=mongoadmin \ -e MONGO_INITDB_ROOT_PASSWORD=someStrongPassword \ mongo --config /etc/mongo/mongod.conf
Here's an article about how I manage local databases with Docker: