Control d'accés
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’identifica només amb un nom d’usuari.
En canvi, a MongoDB un usuari no només s’identifica pel seu nom d’usuari, sinó també per la base de dades on es crea (que és la seva base de dades d’autenticació).
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 només tindrien privilegis d’accés per a aquella base de dades en particular, però no és així. Cada usuari, independentment de la base de dades d’autenticació on s’ha creat, pot tenir privilegis assignats a bases de dades diferents.
Autorització
En un control d’accés basat en rols, els usuaris no tenen permís per fer 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 documents nous, recuperar dades d’un document o crear i suprimir usuaris) i el recurs sobre el qual es pot fer 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. Concedint a un usuari rols definits en una base de dades diferent de la seva base de dades d’autenticació, pots donar permís a un usuari per actuar en més d’una base de dades. Els rols es poden concedir quan crees un usuari o en qualsevol moment posterior. 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 d’ús habitual en sistemes de bases de dades, com ara read per concedir accés només de lectura, readWrite per atorgar permisos tant 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. 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
> mongoshCrea 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 }Atura el servidor i surt del shell:
> db.adminCommand({ shutdown: 1 })
> exitTorna a executar mongod, però aquest cop amb el flag --auth:
> start-process -NoNewWindow mongod --authCrea una nova sessió amb l’usuari root:
> mongosh.exe -u root
Enter password: ********
...
test>Pots veure que ara ja no t’avisa que el 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 com a exemple una empresa de vendes que fa servir 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:customersper a les dades personals dels seus clients iordersper als detalls de la comanda. -
La segona base de dades (anomenada
reports) emmagatzemarà informes agregats de vendes mensuals. Aquesta base de dades contindrà una única col·lecció anomenadareports.
L’empresa només té dues empleades, la Laura i la Roser.
I aquests són els permisos que crearàs 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 salesInsereix un client a la col·lecció customers:
sales> db.customers.insertOne({name: "David"})
{
acknowledged: true,
insertedId: ObjectId('67882f9242d68a24b1cb0ce3')
}Insereix una comanda a la col·lecció orders:
sales> db.orders.insert({total: 100})
{
acknowledged: true,
insertedIds: { '0': ObjectId('67882fd442d68a24b1cb0ce4') }
}Laura
A continuació crea la usuària “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 reportsInsereix 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’ordre show dbs per llistar les bases de dades disponibles:
sales> show dbs
sales 80.00 KiBA diferència del teu compte d’administrador, per a la laura només apareixerà una base de dades, ja que només li has concedit accés a la base de dades sales.
Ara comprova si la laura pot recuperar objectes de les dues col·leccions de 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 documents nous:
sales> db.customers.insertOne({name: "Maria"})
{
acknowledged: true,
insertedId: ObjectId('6789044acdca8d8d69cb0ce2')
}Com que has concedit a la laura el rol readWrite, està autoritzada a escriure documents nous en aquesta base de dades.
Finalment, verifica que la laura no pot llegir ni escriure cap dada a la base de dades reports, ja que no li has concedit 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í com accés només de lectura a la base de dades sales per recuperar les dades.
Canvia a la base de dades admin i autentica’t com a root:
sales> use admin
switched to db admin
admin> db.auth("root")
Enter password
********{ ok: 1 }Crea la usuària roser a 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 a usuària roser:
reports> db.auth("roser")
Enter password
********{ ok: 1 }Executa l’ordre show dbs per llistar les bases de dades disponibles per a la roser:
reports> show dbs
reports 40.00 KiB
sales 112.00 KiBCom 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 a la roser només li has assignat el 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 privilegis nous a usuaris que ja s’han creat al seu sistema.
A continuació, autentica’t com a usuari root,
reports> use admin
switched to db admin
admin> db.auth("root")
Enter password
********{ ok: 1 }Concedeix permís de només lectura a la laura a la base de dades reports:
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’usuària 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 la usuària laura d’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
Amb el mètode createRole, pots crear un rol segons les teves necessitats.
Afegeix alguns 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 cercar 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 un rol de manera única.
Més informació a: User-Defined Roles on Self-Managed Deployments
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 l’utilitzaràs 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 a usuària 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 pot consultar la llista dels nostres productes, però com pot crear una comanda de compra?
Crea un rol maria amb el qual pugui fer 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"]
... })
{ ok: 1 }Afegeix el rol maria a la usuària 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 la usuària maria:
sales> db.revokeRolesFromUser("maria", [{ role:"customer", db: "sales"}])
{ ok: 1 }Autentica’t com a usuària maria:
sales> db.auth("maria")
Enter password
********{ ok: 1 }Verifica que la usuària maria pot cercar productes i inserir comandes 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 la usuària maria no pot inserir documents a la col·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 t’hi fixes, els permisos d’un usuari customer no permeten les accions update o remove a la seva col·lecció de comandes.
Això és important perquè, com podem fer el seguiment de totes les comandes de tots els clients?
Hem de permetre que els usuaris amb el rol de customer insereixin comandes a la col·lecció ordres, però res més.
TODO