Friday, 16 January 2015

MongoDB User Authentication - the basics

Overview


When you're just starting out with MongoDB e.g. playing with it on your home PC, you don't need to worry about setting up database users etc, because authentication is disabled by default.

But once you start thinking about building an application with MongoDB, you'll probably need to think about which users should be able to read/write to which databases/collections. For example, ordinary users should probably only be able to read/write certain collections in a given database, while your application admin would need to be able to do things like create collections and create indexes etc in the application database.

Coming from an RDBMS background, I found MongoDB's user set-up a bit confusing, so I put together this post on how to set up a couple of users for an application database, where some users can only read/write in a specific database/collection.  I hope this will help you to get started with MongoDB's approach to user permissions etc.

Remember that this is just a learning example, so don't rely on this for your production systems.

Make sure you refer to the MongoDB authentication guide for reliable and up-to-date advice on how to do this for real!

This example also relies on the localhost exception when enabling authentication and creating your first user, so make sure this is working on your server machine.  You don't want to lock yourself out of your own database!

What we will do here


This post will show you how you can do the following:

  • enable authentication on a local MongoDB server
  • create a user administrator (you need to do this as soon as you enable authentication)
  • create a DBA super-user who can do anything
  • create an application-specific database
  • create an admin user for the application database only
  • create a couple of collections inside the application database
  • create an application-specific user role with read/write permissions for specific collections only
  • create an application-specific user with that role
  • check that this user can only access the specified collections

That should be enough to get you started with MongoDB user authentication.

Databases


  • admin:  this is where you define privileges that apply to any database.
  • myappdb: an application-specific database where you want to define local user privileges.

Roles


  • root: can do anything.
  • userAdminAnyDatabase:  can manage users on any database.
  • dbOwner:  can manage the relevant DB (we use this in myappdb).
  • myAppUserRole:  has limited access to specific collections in in myappdb.

Users


  • siteUserAdmin:  this user can manage users across the MongoDB server.
  • superuser:  this user can do anything on any DB via the “root” role.
  • myappowner:  this user manages the “myappdb” database via the “dbOwner” role.
  • bob: this user has the “myAppUserRole” role within “myappdb“ only.


Enable authentication on MongoDB server


Modify configuration to enable authentication


This is based on a Ubuntu server (other platforms may have slightly different config files).

Stop MongoDB:

sudo service mongod stop 

Edit /etc/mongod.conf (in Ubuntu) and set auth=true.   

This is the simplest authentication method, but you can also set up SSH authentication via key­files, as described in the MongoDB documentation (see above). 

Re­start MongoDB:

sudo service mongod start 

Create default user administrator (must connect via localhost)


Connect to MongoDB shell on the DB server (localhost): 

mongo 

Switch to admin DB and create the site user administrator:

use admin 
db.createUser({ 
    user: "siteUserAdmin", 
    pwd: "secret", 
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] 
  }) 

Re­connect to MongoDB shell on (localhost) DB server with this user: 

mongo -­u siteUserAdmin ­-p secret ­­--authenticationDatabase admin

Create a super-user


Log into the MongoDB shell as the site user administrator (as above). 

Switch to admin DB and create a “root” user called “superuser”: 

use admin 
db.createUser( 
    { 
      user: "superuser", 
      pwd: "123456", 
      roles: [ "root" ] 
    } 

Set up authentication for your application


Create an application database


Connect to MongoDB shell as the super­user (authenticated via admin DB)

mongo -­u superuser -­p 123456 ­­--authenticationDatabase admin 

Create your application database:  

use myappdb 

Create a DB owner for the application database


Make sure you are logged in as super­user and working in myappdb (see above). 

Create the application owner called “myappowner” for this database: 

db.createUser( 
  { user: "myappowner",  
    pwd: "secret",  
    roles:["dbOwner"]}) 

Re­connect to MongoDB as the DB owner (authenticated via your application DB): 

mongo ­-u myappowner -­p secret --­­authenticationDatabase myappdb 

Create collections in application database


Log in as application owner (see above) and switch to myappdb: 

use myappdb 

Create a collection that we will later define as read­only for ordinary users: 

db.myappreadonly.insert({"Foo":"Bar"}) 

Check it worked: 

db.myappreadonly.find() 
{ "_id" : ObjectId("54b7a63850d47a6b57031616"), "Foo" : "Bar" } 

Now create a read­write collection: 

db.myappreadwrite.insert({"Baz":"Bax"}) 

Check it worked: 

db.myappreadwrite.find() 
{ "_id" : ObjectId("54b7a67b50d47a6b57031617"), "Baz" : "Bax" }

Create an application-specific user role


Make sure you are logged in as application owner (see above) and using myappdb. 
Now create a local user role on this DB, with appropriate access to the collections we 
created above:

db.createRole({  
 role: "myAppUserRole",  
  privileges: [  
   { resource: { db: "myappdb",collection:"myappreadonly"}, 
                 actions: ["find"]},  
   { resource: { db: "myappdb", collection: "myappreadwrite"},  
                 actions: ["find","update","insert"]} 
  ], roles:[]}) 

Create a specific user with this role:

db.createUser( 
  {user:"bob",  
   pwd: "secret",  
   roles:["myAppUserRole"]}) 



Check your application user has correct permissions


Re­connect as this user and switch to myappdb:

mongo -­u bob -­p secret --­­authenticationDatabase myappdb 
use myappdb 

See if you can read the collections correctly

db.myappreadonly.find() 

{ "_id" : ObjectId("54b7a63850d47a6b57031616"), "Foo" : "Bar" } 
db.myappreadwrite.find() 

{ "_id" : ObjectId("54b7a67b50d47a6b57031617"), "Baz" : "Bax" } 

You should be able to insert into the read­write collection:

db.myappreadwrite.insert({"bob":"allowed"}) 

WriteResult({ "nInserted" : 1 }) 

db.myappreadwrite.find() 

{ "_id" : ObjectId("54b7a67b50d47a6b57031617"), "Baz" : "Bax" } 
{ "_id" : ObjectId("54b7a98099923fa639b3c70f"), "bob" : 
"allowed" } 

You should not be able to insert into the read­only collection:

db.myappreadonly.insert({"bob":"not allowed"}) 

WriteResult({ 
" writeError " : { 
"code" : 13, 
"errmsg" : "not authorized on myappdb to execute 
command { insert: \"myappreadonly\",  
documents: [ { _id: ObjectId('54b7a97299923fa639b3c70e'),  
bob: \"not allowed\" } ], 
 ordered: true }" }}) 


Check the application user cannot do anything else


e.g. cannot show all collections in myappdb:

show collections 

2015­01­15T11:49:29.040+0000 error: { 
"$err" : "not authorized for query on  
               myappdb.system.namespaces", 
"code" : 13} at src/mongo/shell/query.js:131 

e.g. cannot create collections or insert data on another DB:

use test 

switched to db test 

db.bobcoll.insert({"bob":"bad"}) 

WriteResult({ 
"writeError" : { 
"code" : 13, 
"errmsg" : "not authorized on test to execute command 
{ insert: \"bobcoll\", documents: [ { _id: 
ObjectId('54b7aa6699923fa639b3c710'), bob: \"bad\" } ], 
ordered: true }" 
}) 


Conclusion


  • Using these techniques, it should be possible to set up a simple set of users/roles to manage basic access to your database and application.  
  • MongoDB provides many more roles, e.g. for managing access to clusters, but these are beyond the scope of this simple introduction. 
  • See the MongoDB manual for comprehensive advice on security. 


No comments:

Post a Comment