MongoDB utilitza el control d'accés basat en rols (RBAC) per controlar l'accés i els privilegis a les bases de dades
Introducció
El control d'accés, també conegut com a autorització és una tècnica de seguretat que consisteix a determinar qui pot accedir a quins recursos.
Autenticació
En molts sistemes de gestió de bases de dades, un usuari s'identifiquen només amb un nom d'usuari.
En canvi, a MongoDB un usuari no només s'identifica pels seu nom d'usuari, sinó també per la base de dades en què es van crea (que es com a base de dades d'autenticació d'aquest usuari).
Això vol dir que a MongoDB és possible tenir diversos usuaris amb el mateix nom d'usuari sempre que es creïn en bases de dades d'autenticació diferents. Per autenticar-te com a usuari, has de proporcionar no només un nom d'usuari i una contrasenya, sinó també el nom de la base de dades d'autenticació associada a aquest usuari.
Es podria suposar que els usuaris creats en una base de dades d'autenticació determinada tindrien privilegis d'accés disponibles només per a aquesta base de dades en particular, però aquest no és el cas. Cada usuari, independentment de la base de dades d'autenticació en què es va crear, pot tenir privilegis assignats a diferents bases de dades.
Autorització
En un control d'accés basat en rols, els usuaris no tenen permís per dur a terme accions directament sobre els recursos, com ara inserir un document nou a la base de dades o consultar una col·lecció concreta, sinó que les regles que permeten accions sobre recursos concrets s'assignen a rols.
Els rols es defineixen amb un conjunt d'un o més privilegis. Cada privilegi consisteix en una acció (com ara crear nous documents, recuperar dades d'un document o crear i suprimir usuaris) i el recurs sobre el qual es pot realitzar aquesta acció (com ara una base de dades anomenada reports
o una col·lecció anomenada orders
).
Els rols s'identifiquen amb la combinació del nom del rol i la base de dades, ja que cada rol, excepte els creats a la base de dades admin
, només pot incloure privilegis que s'apliquen a la seva pròpia base de dades. En concedir a un usuari rols definits en una base de dades diferent de la seva base de dades d'autenticació, es pot donar permís a un usuari per actuar en més d'una base de dades. Els rols es poden concedir quan creas un usuari o en qualsevol moment després. La revocació de la pertinença al rol també es pot fer a voluntat, de manera que és senzill desvincular la gestió d'usuaris de la gestió dels drets d'accés.
MongoDB proporciona un conjunt de rols integrats que descriuen privilegis que s'utilitzen habitualment en sistemes de bases de dades, com ara read
per concedir accés només de lectura, readWrite
per atorgar tant permisos de lectura com d'escriptura o dbOwner
per concedir privilegis administratius complets sobre una base de dades determinada. Per a escenaris més específics, també es poden crear rols definits per l'usuari amb conjunts personalitzats de privilegis.
El control d'accés basat en rols permet assignar als usuaris només el nivell mínim i precís de permisos d'accés que necessiten per treballar en les seves tasques respectives. Aquesta és una pràctica de seguretat important coneguda com a principi de privilegis mínims .
Entorn de treball
El control d'accés de MongoDB no està habilitat per defecte
Arrenca la base de dades i crea una sessió:
> start-process -NoNewWindow mongodb
> mongosh
Crea l'usuari administrador root
:
> use admin
switched to db admin
admin> db.createUser(
{
user: "root",
pwd: passwordPrompt(),
roles: [
{
role: "userAdminAnyDatabase",
db: "admin"
},
"readWriteAnyDatabase"
]
}
)
Enter password
********{ ok: 1 }
Para el servidor i surt del shell:
> db.adminCommand({ shutdown: 1 })
> exit
Torna a executar mongod
, però aquest cop amb el flag --auth
:
> start-process -NoNewWindow mongod --auth
Crea una nova sessió amb l'usuari root
:
> mongosh.exe -u root
Enter password: ********
...
test>
Pots veure que ara ja no t'avisa de que RBAC està deshabilitat.
Rols predefinits
Per explicar com funciona el control d'accés basat en rols (RBAC, per abreujar) a la pràctica utilitzarem d'exemple una empresa de vendes que utilitza dues bases de dades.
-
La primera base de dades (anomenada
sales
) emmagatzemarà dades sobre les comandes dels clients a la botiga de l'empresa amb dues col·leccions separades:customers
per a les dades personals dels seus clients iorders
per als detalls de la comanda. -
La segona base de dades (aquesta anomenada
reports
) emmagatzemarà informes agregats de vendes mensuals. Aquesta base de dades contindrà una única col·lecció anomenadareports
.
L'empresa només té dos empleats, la Laura i la Roser.
I aquests són els permisos que crearas a continuació:
Usuari | sales |
reports |
admin |
---|---|---|---|
root |
readWriteAnyDatabase , admin:userAdminAnyDatabase |
||
laura |
readWrite |
||
roser |
read |
readWrite |
Canvia a la base de dades sales
:
> use sales
switched to db sales
Inserta un client a la col.lecció customers
:
sales> db.customers.insertOne({name: "David"})
{
acknowledged: true,
insertedId: ObjectId('67882f9242d68a24b1cb0ce3')
}
Inserta una ordre a la col.lecció orders
:
sales> db.orders.insert({total: 100})
{
acknowledged: true,
insertedIds: { '0': ObjectId('67882fd442d68a24b1cb0ce4') }
}
Laura
A continuació crea l'usuari "Laura" que treballa al departament de vendes i necessita accés complet a les dues col·leccions de la base de dades sales
, però no necessita treballar amb la base de dades reports
.
sales> db.createUser( {
user: "laura",
pwd: passwordPrompt(),
roles: [ {role : "readWrite", db: "sales" }]
})
Enter password
********{ ok: 1 }
Pots confirmar que s'ha afegit la "Laura" a la llista d'usuaris de la base de dades sales
:
sales> show users
[
{
_id: 'sales.laura',
userId: UUID('f97f35ec-b6c9-4175-adef-7ddd1b3f47da'),
user: 'laura',
db: 'sales',
roles: [ { role: 'readWrite', db: 'sales' } ],
mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]
}
]
Canvia a la base de dades reports
:
sales> use reports
switched to db reports
Insereix un document a la col.lecció reports
:
> db.reports.insertOne({orders: 1})
{
acknowledged: true,
insertedId: ObjectId('678833800c36be4e5fcb0ce2')
}
Tanca la sessió i crea una nova sessió amb l'usuari laura
:
> mongosh -u laura sales
...
Executa l'order show dbs
per llistar les bases de dades disponibles:
sales> show dbs
sales 80.00 KiB
A diferència del vostre compte d'administrador, només apareixerà una base de dades per a la laura
, ja que només li has concedit accés a la base de dades sales
Ara comproveu si la laura
pot recuperar objectes de les dues col·leccions a la base de dades sales
:
sales> db.customers.find()
[ { _id: ObjectId('67882f9242d68a24b1cb0ce3'), name: 'David' } ]
sales> db.orders.find()
[ { _id: ObjectId('67882fd442d68a24b1cb0ce4'), total: 100 } ]
Per assegurar-te que els drets d'accés a la base de dades sales
s'han configurat correctament, pots comprovar si la laura
també pot inserir nous documents:
sales> db.customers.insertOne({name: "Maria"})
{
acknowledged: true,
insertedId: ObjectId('6789044acdca8d8d69cb0ce2')
}
Com has concedit a la laura
el rol readWrite
, està autoritzats a escriure nous documents en aquesta base de dades.
Finalment, verifica que la laura
no pot llegir ni escriure cap dada a la based de dades resports
, ja que no li vas concedir accés a través dels rols assignats.
sales> use reports
switched to db reports
reports> db.reports.find()
MongoServerError[Unauthorized]: not authorized on reports to execute command { find: "reports", filter: {}, lsid: { id: UUID("461bf330-c3d1-4344-a350-d89e646843eb") }, $db: "reports" }
El missatge d'error Unauthorized
indica que la laura
no té prou drets d'accés per interactuar amb les dades de la base de dades reports
.
Roser
Ara has de crear el compte per a la roser
, l'analista de vendes de l'empresa.
La roser
necessita accés d'escriptura a la base de dades reports
per crear informes, així co només accés de lectura a la base de dades sales
per recuperar les dades.
Canvia a la base de dades admin
i autentica't com root
:
sales> use admin
switched to db admin
admin> db.auth("root")
Enter password
********{ ok: 1 }
Crea l'usuari roser
en la base de dades reports
:
admin> use reports
switched to db reports
reports> db.createUser({
... user: "roser",
... pwd: passwordPrompt(),
... roles: [ { role: "readWrite", db: "reports"}, {role: "read", db: "sales"} ]
... })
Enter password
********{ ok: 1 }
Autentica't com l'usuari roser
:
reports> db.auth("roser")
Enter password
********{ ok: 1 }
Executa l'ordre show dbs
per llistar les bases de dades disponibles per a roser
:
reports> show dbs
reports 40.00 KiB
sales 112.00 KiB
Com que la roser
pot utilitzar les bases de dades sales
i reports
, aquestes dues bases de dades es mostraran a la sortida.
Comprova si la roser
pot recuperar objectes de la base de dades sales
:
reports> use sales
switched to db sales
sales> db.orders.find()
[ { _id: ObjectId('67882fd442d68a24b1cb0ce4'), total: 100 } ]
A continuació, pots provar d'inserir un document nou a la col·lecció orders
:
sales> db.orders.insertOne({total: 50})
MongoServerError[Unauthorized]: not authorized on sales to execute command { insert: "orders", documents: [ { total: 50, _id: ObjectId('67890a7d86d96a7e1dcb0ce2') } ], ordered: true, lsid: { id: UUID("f2005137-cf06-411a-8cae-5bd2e3d878c1") }, $db: "sales" }
Com que has assignat a roser
només un rol read
per a aquesta base de dades, l' ordre insertOne
fallarà amb un missatge d'error.
A continuació, confirma si la roser
pot llegir i escriure dades a la base de dades reports
:
sales> use reports
switched to db reports
reports> db.reports.find()
[ { _id: ObjectId('678833800c36be4e5fcb0ce2'), orders: 1 } ]
reports> db.reports.insertOne({orders:2})
{
acknowledged: true,
insertedId: ObjectId('67890b2086d96a7e1dcb0ce3')
}
Concessió i revocació de rols per a usuaris existents
A la pràctica, els administradors de bases de dades sovint necessiten revocar o concedir nous privilegis als usuaris que ja s'han creat al sistema.
A continuació, autentica't com l'usuari root
,
reports> use admin switched to db admin admin> db.auth("root") Enter password ********
Concedeix permís de només lectura a la `laura` de la base de dades `reports`:
```mongodb
admin> use sales
switched to db sales
sales> db.grantRolesToUser("laura", [{role: "read", db: "reports"}])
{ ok: 1 }
Verifica els rols de la laura
:
sales> show users
[
{
_id: 'sales.laura',
userId: UUID('f97f35ec-b6c9-4175-adef-7ddd1b3f47da'),
user: 'laura',
db: 'sales',
roles: [
{ role: 'readWrite', db: 'sales' },
{ role: 'read', db: 'reports' }
],
mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]
}
]
Autentica't amb l'usuari laura
i verifica que pot accedir a la base de dades reports
després del canvi:
sales> db.auth("laura")
Enter password
********{ ok: 1 }
sales> use reports
switched to db reports
reports> db.reports.find()
[
{ _id: ObjectId('678833800c36be4e5fcb0ce2'), orders: 1 },
{ _id: ObjectId('67890b2086d96a7e1dcb0ce3'), orders: 2 }
]
Si al cap d'un temps vols revocar la capacitat de l'usuari laura
per accedir als informes, amb l'usuari root
elimina el permís corresponent:
...
sales> db.revokeRolesFromUser("laura",[ {role:"read", db:"reports"} ])
{ ok: 1 }
Verifica que la laura
ja no pot llegir documents de la base de dades reports
:
...
reports> db.reports.find()
MongoServerError[Unauthorized]: not authorized on reports to execute command { find: "reports", filter: {}, lsid: { id: UUID("55abd9f8-d8b1-479c-a7b2-cae6a4163505") }, $db: "reports" }
Rols definits per l'usuari
Mitjançant el mètode createRole
, pots crear un rol segons les teves necessitats.
Afegeix uns quants productes a la base de dades sales
:
sales> db.products.insertMany( [{"name":"orange"}, {"name": "apple"}, {"name":"banana"}] )
...
Canvia a l'usuari root
i crea un rol customer
a la base de dades sales
que pugui buscar i llegir de la col.lecció products
:
sales> db.createRole({
... role: "customer",
... privileges: [{
... resource: { db: "sales", collection: "products"},
... actions: [ "find"]
... }],
... roles: []
... })
{ ok: 1 }
Quan afegeixes un rol, crees el rol en una base de dades específica: MongoDB utilitza la combinació de la base de dades i el nom del rol per definir de manera única un rol.
Més informació a : https://www.mongodb.com/docs/manual/core/security-user-defined-roles/
En aquest enllaç tens la llista d'accions: Privilege Actions
Si mires la informació dels rols de la base de dades sales
pots veure que la propietat isBuiltin
indica que el rol customer
està definit per l'usuari.
sales> db.getRoles()
{
roles: [
{
_id: 'sales.customer',
role: 'customer',
db: 'sales',
roles: [],
isBuiltin: false,
inheritedRoles: []
}
],
ok: 1
}
Aquest rol el faras servir per afegir clients que puguin consultar la llista de productes de la nostra empresa:
sales> db.customers.find()
[
{ _id: ObjectId('67882f9242d68a24b1cb0ce3'), name: 'David' },
{ _id: ObjectId('6789044acdca8d8d69cb0ce2'), name: 'Maria' }
]
Per exemple, afegeix la maria com usuari de la base de dades sales
:
sales> db.createUser( {
... user: "maria",
... pwd: passwordPrompt(),
... roles: [ {role: "customer", db: "sales"} ]
... })
Enter password
********{ ok: 1 }
sales>
A continuació modifica el document de la Maria per registrar que té un usuari a la base de dades:
sales> db.customers.updateOne( {name: "Maria"}, { $set: {username: "maria"}} )
...
Ara la Maria pots consultar la llista del nostre productes, però com pot crear una ordre de compra?
Crea un rol maria
amb que pugui realitzar accions find
i insert
a la col.lecció orders_maria
:
db.createRole({ ... role: "maria", ... privileges: [{ ... resource: {db: "sales", collection: "orders_maria"}, ... actions: [ "find", "insert" ] ... }], ... roles: ["customer"] ... })
Afegeix el rol `maria` a l'usuari `maria`:
sales> db.grantRolesToUser("maria", [{role: "maria", db: "sales"}])
{ ok: 1 }
Com que el rol `maria` hereta els privilegis de `customer` pots revocar el rol `customer` a l'usuari `maria`:
```mongodb
sales> db.revokeRolesFromUser("maria", [{ role:"customer", db: "sales"}])
{ ok: 1 }
Autentica't com l'usuari maria
:
sales> db.auth("maria")
Enter password
********{ ok: 1 }
Verifica que l'usuari maria
pot buscar productes i inserir ordres a la col.lecció orders_maria
:
sales> db.products.find()
[
{ _id: ObjectId('67893a9520c44545d1cb0ce2'), name: 'orange' },
{ _id: ObjectId('67893a9520c44545d1cb0ce3'), name: 'apple' },
{ _id: ObjectId('67893a9520c44545d1cb0ce4'), name: 'banana' }
]
sales> db.orders_maria.insertOne({product: "orange", quantity: 5, price: 1.23 })
{
acknowledged: true,
insertedId: ObjectId('678946b720c44545d1cb0ce5')
}
Verifica que l'usuari maria
no pots inserir documents a la co.lecció orders
:
sales> db.orders.insertOne({product: "orange", quantity: 5, price: 1.23 })
MongoServerError[Unauthorized]: not authorized on sales to execute command { insert: "orders", documents: [ { product: "orange", quantity: 5, price: 1.23, _id: ObjectId('6789477120c44545d1cb0ce6') } ], ordered: true, lsid: { id: UUID("51dc4213-8d64-4c2f-b5a2-8dd5a9d838a4") }, $db: "sales" }
Immutabilitat
Si et fixes, els permisos d'un usuari customer no permeten les accions update
o remove
en la seva col.lecció d'ordres.
Això és important perquè com podem seguir totes les ordres de tots els clients?
Hem de permetre que els usuaris amb el rol de customer insereixin ordres a la col.lecció ordres
, però res més.
TODO