Recently,
I decided to move the MongoDB backend to an Amazon EC2 instance. Among other
things, I needed to set up authentication and this post is about what I
learned. While working through this, I didn't find any examples for syntax of
the end to end scenario and in fact had to resort to some brute force trial and
error - hopefully this post will remedy some of that.
I
won't go into too many details about the mechanics of setting up EC2 instances
and installing Mongo here though.
Scenario
My
app has 6 databases (relatively small) and the NodeJS server runs on a
different EC2 instance and accesses the databases over the network. I use
MongooseJS to access the MongoDB server.
This
translates into the following requirements (among others)
1.
Enable authentication for the MongoDB instance.
2.
Create user accounts to read-write and administer the databases. I could have
chosen to create user accounts per database (relatively easy to setup) but that
can be a chore to maintain. Instead I opted to use a single set of user
accounts that have access to all the databases (so that password updates etc.
are required only once per account)
Steps
The
steps below assume a vanilla install of Mongodb that can be accessed without
auth over the loopback interface(127.0.0.1). Lines prefixed by # are comments
and should be no-ops in a shell if you copy paste but I haven't tested every
shell.
- Create an admin user
mongo # fire up the mongo client on the
system with MongoDB installed
use admin #switch
to the admin database
db.addUser( { user: "adminuser", pwd:
"mypassword", roles: [ "userAdminAnyDatabase",
"clusterAdmin", "readWriteAnyDatabase" ,
"dbAdminAnyDatabase" ] } )
Note: The roles give you all access to any
database. This is a simplification, and you should scope the roles for each
user before you enter production. Read more about roles
here
- Create database users
Continuing from the previous step, add a database
user who can access any database on the system.
db.addUser( { user: "dbuser", pwd:
"mypassword", roles: [ "readWriteAnyDatabase" ,
"dbAdminAnyDatabase" ] } )
- Enable auth and network
access
On the Ubuntu 12.04 install that I used this
meant enabling the following lines (i.e. delete the leading '#') in /etc/mongodb.conf.
port = 27017
auth=true
- Setup connection in your app(Node/mongoose)
var myDB =
mongoose.createConnection("mongodb://dbuser:mypassword@myipaddress:27017/myfirstdb"
,{auth:{authdb:"admin"}});
The
createConnection string should look familiar for the most part. The section
{auth:{authdb:"admin"}} is a set of options that tells the driver to
authenticate the user (dbuser) against
the admin database instead of myfirstdb.
You can find more on CreateConnection
here
And you are off to the races.
Finer access granularity
In the example above
a single user dbuser was given read
write access to all databases in that MongoDB instance. In the example below
we'll create a database (mydb) and
provide access to the user (mydbuser)
defined in the admin database. mydbuser won't have any other access or admin rights
to other databases unlike the previous example.
- Create the
database user
mongo 127.0.0.1:27017/admin -u "adminuser"
-p "mypassword" # logs
you in
use admin
db.addUser( { user: "mydbuser", pwd:
"mypassword", roles: [ ] } )
Note: You can replace the 127.0.0.1 ip with a
public IP and login from a remote system too.
- Create the database and assign the user readWrite and
dbAdmin roles
Continuing
from the previous step
use mydb
db.addUser( { user: "mydbuser", userSource:
"admin" , roles: [ "readWrite" , "dbAdmin"] } )
And you now have a
user mydbuser with only access rights to
the database mydb. Similarly you might
divvy out access other databases or other users or both.
One last tip. If you
need to login from the mongo shell to access a certain database (while
authenticating against admin) use this
mongo myipaddr:27017/mydb -u "mydbuser" -p
"mypassword" --authenticationDatabase admin