Creating User Access Control in MongoDB
User-defined roles were introduced to MongoDB in version 2.6. See how to take advantage of this feature and introduce user access control into a MongoDB instance.
Join the DZone community and get the full member experience.
Join For FreeMongoDB provides user access on role-based controls. It provides many built-in roles to be assigned to users: most notably the read
and readwrite
roles. Sometimes, however, they are not as granular as we would like.
I recently had a chance to explore user-defined roles in MongoDB, which were introduced in version 2.6. In this blog post, I will go over the MongoDB user-defined roles and define some custom roles that you might find useful.
Create Roles
Creating a user-defined role in MongoDB is simple. You can use the createRole
command to create a new role. The generic create role syntax is as follows.
{
createRole: "<role name>",
privileges: [{
resource: { <resource> },
actions: [ "<action>",] },
],
roles: [
{ role: "<role>", db: "<database>" } | "<role>",],
writeConcern: <write concern document>
}
Before running the createRole
command, make sure that you switch to the database that you want to create the role in. Note that the roles will be defined only in the database where the role has been created. If you want to create a role that grants access to more than one database, then that needs to be created on the admin database.
Let's go over the major components of the createRole
syntax.
Privileges
Permissions can be added to a user-defined role by adding a privilege. A privilege contains action and resource fields, which are discussed below.
Actions
Actions are a set of operations that are grouped together. For example, the insert
action can both insert and create. Actions are as granular as MongoDB’s role-based access control gets. The privileges parameter can be used to add roles to Mongo actions. A privilege constitutes the actions along with the resource on which the action applies. The following adds actions find
, insert
, and update on database mydb
.
privileges:
[
{resource: {db: "mydb", collection: "" },
actions: [ “find”,”insert”,”update” ] }
]
Resource
The resource document would specify the scope at which the actions would apply. The scope can be set at various granularities as follows.
Collection: The resource can be set to
resource: {db: "<db-name>", collection: "<collection name>" }
to grant the specified actions to just that particular collection.Database: The resource can be set to a particular database by leaving the collection parameter empty.
Resource string resource{db: "<db-name>", collection: "<collection name>" }
sets the scope to the entire database.Single collection across databases: The resource can be set to a particular collection using
resource: {db: ", collection: "<collection name>" }
to grant permissions to the collection on all databases. This permission can only be added onto a role created on the admin database.Multiple collections across databases: The resource can be set to all collections except the system collections across all databases by leaving both the
db
andcollection
parameters empty —resource: {db: "", collection: "" }
. This resource, like the one above, can only be granted on a role created on to the admin database.Cluster-wide resource: A cluster-wide resource can be specified by using
resource: { cluster : true }
. This cluster-wide resource can be used to specify the state of the system such as shutdown, replSetReconfig rather than to grant permissions on any particular document.All resources: It’s not recommended to use this scope for other than extraordinary circumstances.
{anyResource: true }
can be used to set scope set to all resources.
Roles
Inbuilt roles can be added to a custom role, as well. When an inbuilt role is added by using the roles parameter roles :[]
, it adds the permissions of the inbuilt role to the custom role.
An example of the roles parameter is roles: [{ role: "read", db: " "}]
.
Here, the custom role would inherit all the permissions of role read over the database defined. Let’s say a role is inherited onto a database db1
. The custom role can either be created on the database db1 or on the admin database.
Write Concern
The write concern defines the level of acknowledgment requested from MongoDB. It can be used to control write acknowledgments from the database. A write concern is not required when creating a role. A write concern can include fields w
, j
, and wtimeout
.
W
can be used to state the number of instances the write has been propagated to.J
: Field j can be set to determine whether the write is written to the journal.Wtimeout
is used to set the time by which the write has to achieve write concern. The write concern might still be achieved after the error is thrown. If awtimeout
has not been set and the write concern cannot be achieved, the write will be blocked indefinitely.
Assigning Roles
Custom roles are database-specific. A role can only be assigned to a user in the same database.
Let’s say we created a role myrole
on database db1
. We can create a user on the database using the following commands.
Use db1
db.createUser({"user" : "<user>",pwd: "<password>","roles" : [{"role" : "myrole", "db" : "db1"}]})
For further information on user management, refer to uthis post on user management in MongoDB.
Custom Roles
Let’s go over some custom roles that might be useful.
User With Read, Insert, and Update Permissions on a Single DB
The inbuilt roles read
and readWrite
might sometimes feel like too many permissions or too little permissions. Let’s see how we can create a custom role granting just read, insert and write permissions.
We already know we need all read
permissions, so we can add the inbuilt role “read
” to our custom role. We would also need permissions to create and update documents. These can be added by adding privilege actions insert and update. If we want to give the user the ability to create indexes and create collections, we can add the privilege action createIndex
and createCollection
.
For the scope, let's assume I have a database named db1
on which I the above permissions. The create command would look something like this:
Use db1.
db.createRole(
{
createRole: "<role-name>",
privileges: [
{ resource: { db: "db1", collection: "" },
actions: [ "insert","update","createIndex", "createCollection" ] }
],
roles: [{ role: "read", db: "db1"}]
})
The above command would create a role with <role-name>
in database db1
. A user granted permission by the above role will not have the “remove
” privilege action. Also, note that the methods db.collection.findAndModify()
, db.collection.mapReduce()
, and db.collection.aggregate()
cannot be run in full as they require the remove privilege.
User With Only Read, Insert, and Update Permissions on All DBs
We can create a role on the admin database similar to the one above to grant read
, create
, and update
privileges on all DBs. This role should be created on the admin DB and the subsequent user should also be created on the admin DB.
For this role, instead of using the standard read
role, we can inherit permissions from the readAnyDatabase
role. The role create would look something like this:
Use admin.
db.createRole(
{
createRole: "<role-name>",
privileges: [
{ resource: { db: "", collection: "" },
actions: [ "insert","update","createIndex", "createCollection" ] }
],
roles: [{ role: "readAnyDatabase", db: "admin"}]
})
Writer Roles With Write Concern
You could have a use case where write concern needs to be enforced. For this purpose, the write concern command can be added to a role. Adding writeConcern
to a role would enforce it on all the users granted the role on the DB. Let's define a role with a write concern that enforces majority writes.
Use admin.
db.createRole(
{
createRole: "<role-name>",
privileges: [ ],
roles: [{ role: "readWriteAnyDatabase", db: "admin"}],
writeConcern: { w: “majority”, j: false, wtimeout: 300 }
})
That's it for this post!
Published at DZone with permission of , DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
What Is Test Pyramid: Getting Started With Test Automation Pyramid
-
Building A Log Analytics Solution 10 Times More Cost-Effective Than Elasticsearch
-
Why You Should Consider Using React Router V6: An Overview of Changes
-
Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices
Comments