“A man stretching out his two hands with careless written on them in black and white” by Mitchel Lensink on Unsplash Have you come across a situation where Unless you can restore the data from a backup, you are in a terrible situation. ‘someone accidentally dropped an entire collection in production?’ I came across a few clients who faced this situation at one point in time. So, it is important that you take security measures to prevent such situation from happening in the first place. You can easily achieve it by making use of the user-defined roles. This is one of the many articles in multi-part series, , solely created for you to master by learning . In a few series of articles, I would like to give various tips to tighten the security on . In this article, I would discuss how an user-defined role can help prevent someone accidentally dropping a collection. Mastering MongoDB - One tip a day MongoDB ‘one tip a day’ MongoDB Mastering user-defined role What is a role MongoDB employs Role-Based Access Control (RBAC) to govern access to a MongoDB system. A grant users access to MongoDB resources. Outside of role assignments, the user has no access to the system. role Here are a few concepts that I want you to be aware of A user is granted one or more roles. A role grants privileges to perform sets of actions on a resource. A privilege consists of a resource and the actions permitted on them. A resource is a , collection or set of collections. database An action specifies the operation allowed on the resource. Why user-defined role MongoDB provides a number of built-in roles that administrators can use to control access to a MongoDB system. Every database includes the following roles Database User Roles read readWrite Database Administration Roles dbAdmin userAdmin dbOwner However, if these roles cannot describe the desired set of privileges, you can create a new user-defined role by using the method. While creating a role, you can specify the set of privileges you want to grant access. db.createRole() readWrite role has dropCollection action The database administrators typically make use of the built-in and roles to restrict the access to data. The below command shows the various set of actions a user with role can execute. ‘read’ ‘readWrite’ ‘getRole’ ‘readWrite’ db.getRole( , { : } ).privileges[ ].actions // command to get readWrite privileges "readWrite" showPrivileges true 0 // output of above command /* [ "changeStream", "collStats", "convertToCapped", "createCollection", "createIndex", "dbHash", "dbStats", "dropCollection", "dropIndex", "emptycapped", "find", "insert", "killCursors", "listCollections", "listIndexes", "planCacheRead", "remove", "renameCollectionSameDB", "update" ] */ The MongoDB getRole command to show all the granted actions for readWrite role Based on the context of the current article, the riskiest action among them is the action. If there is truly a need for (a human) user to have a read & write permission, it is recommended to have a user-defined role with all the actions but the action from role. By assigning this user-defined role to such users, the administrators prevent someone accidentally drop a collection. ‘dropCollection’ ‘dropCollection’ ‘readWrite’ Hands-On lab exercises This lab exercise helps you create a user-defined role and illustrate how can prevent someone accidentally drop a collection when compared to a user with role. readWriteMinusDropRole readWrite Setup environment First, you would need an environment to play around. I recommend using , a utility tool from , to setup a test environment on your local machine. If you already have an environment with authentication turned on, you may skip this step. mlaunch mtools mlaunch init --auth --replicaset --port 28000 # Don't have mtools? The easiest way to install mtools is via pip # pip install mtools # output # launching: "mongod" on port 28000 # launching: "mongod" on port 28001 # launching: "mongod" on port 28002 # replica set 'replset' initialized. # waiting for primary to add a user. # Username "user", password "password" A bash script to setup a MongoDB environment with authentication on your local machine Create app_user with readWrite role Log in to the test environment using the above credentials and create with role on the database. app_user readWrite social mongo admin --port 28000 -u user -p password --authenticationDatabase admin <<EOF db.createUser({user: , : , roles: [{role: , db: }]}) EOF 'app_user' pwd 'password' 'readWrite' 'social' # The output of above command # MongoDB shell version v3.6.2 # connecting to: mongodb://127.0.0.1:28000/ # MongoDB server version: 3.6.2 # Successfully added user: { # "user" : "app_user", # "roles" : [ # { # "role" : "readWrite", # "db" : "social" # } # ] # } # bye A bash script to create a user with readWrite role on the social database A user with readWrite role can drop collection Log in to the test environment using the credentials and create a sample document on the database. Since the has role which grants access to action, the command execution succeeds and the collection is dropped. app_user person social app_user readWrite dropCollection db.person.drop() mongo social --port -u app_user -p password --authenticationDatabase admin # output above command # MongoDB shell version v3 # connecting to: mongodb: # MongoDB server version: # replset:PRIMARY> # create a person collection db.person.insert({ : , : }) # output above command # WriteResult({ : }) db.getCollectionNames() # The output above command # [ ] # drop the collection db.person.drop() # The output above command # db.getCollectionNames() # The output above command # [ ] 28000 of .6 .2 //127.0.0.1:28000/social 3.6 .2 document in "fname" "Shyam" "lname" "Arjarapu" of "nInserted" 1 of "person" of true of Set of bash & JavaScript to show that user with readWrite role can drop a collection Create a user-defined role Log in to the test environment using the credentials and create the following on the database. user social a user-defined role, readWriteMinusDropRole a user with role human_user readWriteMinusDropRole Notice that there is no action from the set of actions being granted to . dropCollection readWriteMinusDropRole mongo social --port 28000 -u user -p password --authenticationDatabase admin <<EOF db.createRole({ role: , privileges: [ { resource: { db: , collection: }, actions: [ , , , , , , , , , , , , , , ]} ], roles: [] } ); use admin; db.createUser({user: , : , roles: [{role: , db: }]}) EOF "readWriteMinusDropRole" "social" "" "collStats" "dbHash" "dbStats" "find" "killCursors" "listIndexes" "listCollections" "convertToCapped" "createCollection" "createIndex" "dropIndex" "insert" "remove" "renameCollectionSameDB" "update" 'human_user' pwd 'password' 'readWriteMinusDropRole' 'social' # The output of above command # MongoDB shell version v3.6.2 # connecting to: mongodb://127.0.0.1:28000/social # MongoDB server version: 3.6.2 # { # "role" : "readWriteMinusDropRole", # "privileges" : [ # { # "resource" : { # "db" : "social", # "collection" : "" # }, # "actions" : [ # "collStats", # "dbHash", # "dbStats", # "find", # "killCursors", # "listIndexes", # "listCollections", # "convertToCapped", # "createCollection", # "createIndex", # "dropIndex", # "insert", # "remove", # "renameCollectionSameDB", # "update" # ] # } # ], # "roles" : [ ] # } # switched to db admin # Successfully added user: { # "user" : "human_user", # "roles" : [ # { # "role" : "readWriteMinusDropRole", # "db" : "social" # } # ] # } # bye A bash script with MongoDB commands to create a user-defined role and a user. User with readWriteMinusDropRole role cannot drop collection mongo social --port 28000 -u human_user -p password --authenticationDatabase admin db.person.insert({ : , : }) db.getCollectionNames() db.person.drop() db.getCollectionNames() # output of above command # MongoDB shell version v3.6.2 # connecting to: mongodb://127.0.0.1:28000/social # MongoDB server version: 3.6.2 # replset:PRIMARY> # create a document in person collection "fname" "Shyam" "lname" "Arjarapu" # output of above command # WriteResult({ "nInserted" : 1 }) # The output of above command # [ "person" ] # drop the collection # The output of above command # 2018-05-14T17:01:38.830-0500 E QUERY [thread1] Error: drop failed: { # "operationTime" : Timestamp(1526335298, 1), # "ok" : 0, # "errmsg" : "not authorized on social to execute command { drop: \"person\", $clusterTime: { clusterTime: Timestamp(1526335285, 1), signature: { hash: BinData(0, 7EE640BEC21303BD6514D6791A9F50D6DEB45CC5), keyId: 6555423603385434113 } }, $db: \"social\" }", # "code" : 13, # "codeName" : "Unauthorized", # "$clusterTime" : { # "clusterTime" : Timestamp(1526335298, 1), # "signature" : { # "hash" : BinData(0,"lh/gXN9yKwcrV4asUPFVV8kLAxA="), # "keyId" : NumberLong("6555423603385434113") # } # } # } : # _getErrorWithCode@src/mongo/shell/utils.js:25:13 # DBCollection.prototype.drop@src/mongo/shell/collection.js:695:1 # @(shell):1:1 # The output of above command # [ "person" ] A user with user-defined role, readWriteMinusDropRole, cannot drop a collection Summary While MongoDB provides various built-in roles that provide the different levels of access commonly needed in a database system, you would need user-defined roles to grant fine-grained actions to MongoDB resources. Don’t wait till you regret of not doing it earlier. Tighten your security measures using user-defined roles and prevent someone accidentally drop a collection. Here are a few measures taken by my clients to tighten the security. No access to the production environment for developers (more drastic) If access is required, give role to developers (much needed) ‘read’ Create a user-defined role with all actions but ‘readWrite’ ‘dropCollection’ If permissions is required for any users, assign above user-defined role (highly recommended) ‘read & write’ Create a separate with permissions for your application to interact with MongoDB app_user ‘readWrite’ With the MongoDB v3.6, you could further tighten the security by defining the range of IP addresses a user is allowed to authenticate from using . But that’s a topic for another day. Hopefully, you learned something new today on you scale the path to “ ”. authenticationRestrictions Mastering MongoDB - One tip a day