Usuarios y roles con el mínimo privilegio
25 minIntermedio

En esta guía aprenderás a crear un rol que lee y escribe en una colección sin poder borrar y a dárselo al usuario de una aplicación.
Una aplicación que solo crea y actualiza pedidos no necesita borrarlos ni leer otras colecciones. Con un rol a medida le das solo esas acciones sobre esa colección, así que si su contraseña se filtra, quien la use no puede hacer más de lo que podía hacer la aplicación.
Lo que vas a construir
Un rol ordersWriter con las acciones find, insert y update sobre la colección tienda.pedidos, y un usuario
tienda-pedidos que solo tiene ese rol.
Requisitos
- Docker y
mongosh, para arrancar TeselaDB con TLS y usuarios en tu máquina.
Prepara el entorno
docker run -d --name teseladb -p 27017:27017 viuzi/teseladb:latest \
start --dbpath /data --bind_ip 0.0.0.0
until docker logs teseladb 2>&1 | grep -q '^ready'; do sleep 1; done
ROOT_PASSWORD=$(docker exec teseladb cat /data/root-credentials.txt | sed -n 's/^password=//p')
docker cp teseladb:/data/pki/ca.pem ./ca.pem
export TESELADB_URI="mongodb://root:$ROOT_PASSWORD@127.0.0.1:27017/?tls=true&tlsCAFile=./ca.pem&authSource=admin"
mongosh "$TESELADB_URI" --quiet --eval 'db.runCommand({ ping: 1 }).ok'
mongosh "$TESELADB_URI"El contenedor arranca un nodo en modo seguro, con TLS y usuarios, y su primer arranque crea la autoridad de
certificación y el usuario root con una contraseña al azar. Las órdenes siguientes esperan a la línea ready del
nodo, sacan esa contraseña y la CA del contenedor y dejan en TESELADB_URI una cadena con TLS como root. Cuando
mongosh responde 1, la última línea abre una sesión de root para crear el rol y el usuario.
1. Crea el rol
Cada privilegio une un recurso, aquí una colección, con las acciones permitidas sobre él:
db.getSiblingDB("admin").createRole({
role: "ordersWriter",
privileges: [{ resource: { db: "tienda", collection: "pedidos" }, actions: ["find", "insert", "update"] }],
roles: [],
});2. Crea el usuario
El usuario solo tiene el rol ordersWriter. passwordPrompt() pide la contraseña sin que quede en el historial
de mongosh:
db.getSiblingDB("admin").createUser({ user: "tienda-pedidos", pwd: passwordPrompt(), roles: ["ordersWriter"] });Probarlo
En otra terminal, desde la misma carpeta donde quedó ca.pem, conéctate como tienda-pedidos para ver lo que puede hacer la aplicación con ese rol, porque root puede hacerlo todo y la
prueba no diría nada. mongosh te pide la
contraseña que le diste en el paso 2:
mongosh "mongodb://tienda-pedidos@127.0.0.1:27017/?tls=true&tlsCAFile=./ca.pem&authSource=admin"Conectado como tienda-pedidos, prueba una inserción y un borrado en tienda.pedidos, sabiendo que el rol lleva la
acción insert pero ninguna que borre documentos, así que solo puede funcionar la primera de las dos escrituras de
abajo:
const tienda = db.getSiblingDB("tienda");
tienda.pedidos.insertOne({ total: 30 });
tienda.pedidos.deleteOne({});La inserción funciona y el borrado falla con Unauthorized, el mismo error que recibes si intentas leer otra colección
de tienda.
Limpiar
Si era una prueba, borra el usuario y el rol conectado como root. Al final borra también el contenedor y la CA con
las dos últimas órdenes: el nodo guarda los datos dentro, sin volumen, así que con él desaparecen el rol y el usuario y queda
libre el puerto 27017:
db.getSiblingDB("admin").dropUser("tienda-pedidos");
db.getSiblingDB("admin").dropRole("ordersWriter");docker rm -f teseladb
rm ca.pemSiguientes pasos
- Usuarios y roles, con los roles predefinidos y los privilegios que lleva cada uno.
- Acciones de privilegio, con todas las acciones que puede llevar un rol.