Configurando la seguridad de mongodb para un entorno de producción

En este artículo os voy a a hablar de cómo realizar la configuracíon necesaria para aplicar seguridad para un entorno de producción de una base de datos mongoDB. En estos últimos años he visto, cómo la seguridad ha pasado a un segundo plano, una problemática que se debe en parte a la desprofesionalización del sector y la continua pelea por el "yo lo hago más barato". MongoDB es una de las bases de datos noSQL más usadas, en parte porque nos proveé de una enorme flexibilidad permitiéndonos de esta forma, mejorar nuestra productividad. Precisamente por su uso cotidiano no debemos nunca descuidar o prescindir de las pautas necesarias para configurarla de forma segura. Si la seguridad no se tiene en cuenta, pueden suceder ataques a esta base de datos, como ya han sucedido en su momento por una mala o nula configuración de seguridad por parte de los propietarios de las mismas. Los puntos sobre los que vamos a trabajar en la configuración de la seguridad de nuestra base de datos, serán los siguientes: 1. Arquitectura 2. IP Binding 3. Firewall 4. Usuarios y Roles 5. SSL

Arquitectura

En esta imagen podemos visualizar la arquitectura implementada:
Arquitectura básica para seguridad en mongoDB
Podemos observar cómo tanto la base de datos como el api que lo llaman disponen de su propio VPS , realizando la comunicación entre ellos a través de una red privada. Aislando cada componente, mejoramos tanto su escalabilidad como la eficiencia de los mismos, haciendo que funcionen de forma independiente .

IP Binding

Modificaremos nuestro archivo mongod.conf configurando la propiedad bindip a la ip privada de la instancia, de este modo sólo se podrá acceder a la base de datos desde nuestra red privada. Nuestro archivo de configuración quedaría de la siguiente forma
net:
  port: 27017
  bindIp: 10.131.82.47

Firewall

Añadiendo un par de simples reglas de firewall podremos restringuir cualquier entrada desde una dirección sospechosa. En este caso el ejemplo os lo dejo usando ufw, ya que mi configuración es sobre ubuntu:
ufw allow from {ip} to any port 27017
En el siguiente comando sustituimos {ip} por la ip privada desde donde se accederá a nuestra base de datos o por aquella donde tengamos desplegada la aplicación que conecta con mongoDB. De esta forma, solo se podrán conectar a nuestra base de datos desde la ip que le indiquemos, haciendo que nuestro firewall bloqueé el resto de peticiones a ese puerto.

Usuarios y roles

Una buena practica de seguridad consiste en crear usuarios con los permisos estrictamente necesarios en cada una de nuestras bases de datos. En nuestro caso, crearemos un usuario que pueda leer y modificar evitando cualquier otro privilegio innecesario.
db.createUser(
  {
    user: "{user}",
    pwd: "{pass}",
    roles: [ { role: "readWrite", db: "{mydb}" } ]
  }
)
Debemos sustituir {user} y {pass} por el usuario y contraseña que deseemos crear y {mydb} por la base de datos sobre la que se aplicará.
Si por ejemplo nuestra aplicación solo mostrase información, lo conviente sería aplicar el rol read. Con el rol read nos aseguramos que nunca se pueda escribir en base de datos desde nuestra aplicación.
Una vez configurado nuestro usuario y rol, habilitamos este mecanismo de autenticación en nuestro archivo mongod.conf
security:
  authorization: "enabled"

SSL

Por último, pero no menos importante por ello, configuraremos nuestra instancia de mongoDB para que soporte TLS/SSL haciendo que la información de nuestra base de datos viaje encriptada.

Generación de certificado

Gracias a la herramienta certbot podremos obtener un certificado letsencrypt válido. Para la generación de nuestro certificado de seguridad ejecutaremos el siguiente comando:
certbot certonly --standalone -d {domain}
Sustituyendo {domain} por el nombre de dominio que queramos atribuirle. Una vez obtenido nuestro certificado necesitamos fusionar la clave pública y la privada en un solo fichero, utilizando para ello la siguiente orden:
cat /etc/letsencrypt/live/{domain}/fullchain.pem /etc/letsencrypt/live//{domain}/privkey.pem > /etc/ssl/mongodb.pem

Configuración en MongoDB

Un vez que hemos generado un certificado válido con la anterior orden, le indicamos su ubicación en el archivo mongod.conf:
#ssl
net:
 ssl:
   mode: requireSSL
   PEMKeyFile: /etc/ssl/mongodb.pem
Reiniciamos mongodb y ¡todo listo!
service mongod restart

Creación de tarea automatizada de renovación

Posteriomente, tendremos que renovar ese certificado de forma períodica, para lo cual, creamos el siguiente script:
cat /etc/letsencrypt/live/{domain}/fullchain.pem /etc/letsencrypt/live/{domain}/privkey.pem > /etc/ssl/mongodb.pem
service mongod restart
Este script, que podremos llamar "renew.sh" fusionará nuestra clave pública y privada para generar el certificado válido para mongoDB y posteriormente reinicará nuestra base de datos para que este cambio se vea reflejado. le otorgamos permisos de ejecución:
chmod +x /root/renew.sh
y creamos la siguiente tarea con el comando crontab -e
* */12  * * * certbot renew --renew-hook /root/renew.sh 1> /root/certbot-cron.log 2> /root/certbot-cron-error.log
De esta forma conseguiremos renovar nuestro certificado de seguridad de manera automática. Y ya sabéis, si tenéis algún proyecto donde necesitéis una ayuda de un profesional Mandadme un correo :D