Database access using Role-Based Access Control - Amazon DocumentDB

Database access using Role-Based Access Control

You can restrict access to the actions that users can perform on databases using role-based access control (RBAC) in Amazon DocumentDB (with MongoDB compatibility). RBAC works by granting one or more roles to a user. These roles determine the operations that a user can perform on database resources. Amazon DocumentDB currently supports both built-in roles that are scoped at the database level, such as read, readWrite, readAnyDatabase, clusterAdmin, and user-defined roles that can be scoped to specific actions and granular resources such as collections based on your requirements.

Common use cases for RBAC include enforcing least privileges by creating users with read-only access to the databases or collections in a cluster, and multi-tenant application designs that enable a single user to access a given database or collection in a cluster.

Note

All new users created before March 26, 2020 have been granted the dbAdminAnyDatabase, readWriteAnyDatabase, and clusterAdmin roles. It is recommended that you reevaluate all existing users and modify the roles as necessary to enforce least privileges for your clusters.

RBAC concepts

The following are important terms and concepts related to role-based access control. For more information on Amazon DocumentDB users, see Managing Amazon DocumentDB users.

  • User — An individual entity that can authenticate to the database and perform operations.

  • Password — A secret that is used to authenticate the user.

  • Role — Authorizes a user to perform actions on one or more databases.

  • Admin Database — The database in which users are stored and authorized against.

  • Database (db) — The namespace within clusters that contains collections for storing documents.

The following command creates a user named sample-user.

db.createUser({user: "sample-user", pwd: "abc123", roles: [{role: "read", db: "sample-database"}]})

In this example:

  • user: "sample-user" — Indicates the user name.

  • pwd: "abc123" — Indicates the user password.

  • role: "read", "db: "sample-database" — Indicates that the user sample-user will have read permissions in sample-database.

Code example showing a createUser command indicating user name, password, and permissions.

The following example shows the output after you get the user sample-user with db.getUser(sample-user). In this example, the user sample-user resides in the admin database but has the read role for the database sample-database.

Code output example showing the result of the createUser command defining the new user ID, the admin database the new user is assigned to, and role permissions applied to the user.

When creating users, if you omit the db field when specifying the role, Amazon DocumentDB will implicitly attribute the role to the database in which the connection is being issued against. For example, if your connection is issued against the database sample-database and you run the following command, the user sample-user will be created in the admin database and will have readWrite permissions to the database sample-database.

db.createUser({user: "sample-user", pwd: "abc123", roles: ["readWrite"]})

Output from this operation looks something like the following.

{ "user":"sample-user", "roles":[ { "db":"sample-database", "role":"readWrite" } ] }

Creating users with roles that are scoped across all databases (for example, readAnyDatabase) require that you either be in the context of the admin database when creating the user, or you explicitly state the database for the role when creating the user. To issue commands against the admin database, you can use the command use admin. For more information, see Common commands.

Getting started with RBAC built-in roles

To help you get started with role-based access control, this section walks you through an example scenario of enforcing least privilege by creating roles for three users with different job functions.

  • user1 is a new manager that needs to be able to view and access all databases in a cluster.

  • user2 is a new employee that needs access to only one database, sample-database-1, in that same cluster.

  • user3 is an existing employee that needs to view and access a different database, sample-database-2 that they didn't have access to before, in the same cluster.

At a point later, both user1 and user2 leave the company and so their access must be revoked.

To create users and grant roles, the user that you authenticate to the cluster with must have an associated role that can perform actions for createUser and grantRole. For example, the roles admin and userAdminAnyDatabase can both grant such abilities, for example. For actions per role, see Database access using Role-Based Access Control.

Note

In Amazon DocumentDB, all user and role operations (for example, create, get, drop, grant, revoke, etc.) are implicitly performed in the admin database whether or not you are issuing commands against the admin database.

First, to understand what the current users and roles are in the cluster, you can run the show users command, as in the following example. You will see two users, serviceadmin and the primary user for the cluster. These two users always exist and cannot be deleted. For more information, see Managing Amazon DocumentDB users.

show users

For user1, create a role with read and write access to all databases in the entire cluster with the following command.

db.createUser({user: "user1", pwd: "abc123", roles: [{role: "readWriteAnyDatabase", db: "admin"}]})

Output from this operation looks something like the following.

{ "user":"user1", "roles":[ { "role":"readWriteAnyDatabase", "db":"admin" } ] }

For user2, create a role with read-only access to the database sample-database-1 with the following command.

db.createUser({user: "user2", pwd: "abc123", roles: [{role: "read", db: "sample-database-1"}]})

Output from this operation looks something like the following.

{ "user":"user2", "roles":[ { "role":"read", "db":"sample-database-1" } ] }

To simulate the scenario that user3 is an existing user, first create the user user3, and then assign a new role to user3.

db.createUser({user: "user3", pwd: "abc123", roles: [{role: "readWrite", db: "sample-database-1"}]})

Output from this operation looks something like the following.

{ "user":"user3", "roles":[ { "role":"readWrite", "db":"sample-database-1" } ] }

Now that the user user3 has been created, assign user3 the role read to sample-database-2.

db.grantRolesToUser("user3", [{role: "read", db: "sample-database-2"}])

Lastly, both user1 and user2 leave the company and need their access to the cluster revoked. You can do this by dropping the users, as follows.

db.dropUser("user1") db.dropUser("user2")

To ensure that all users have the appropriate roles, you can list all users with the following command.

show users

Output from this operation looks something like the following.

{ "_id":"serviceadmin", "user":"serviceadmin", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"master-user", "user":"master-user", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"user3", "user":"user3", "db":"admin", "roles":[ { "db":"sample-database-2", "role":"read" }, { "db":"sample-database-1", "role":"readWrite" } ] }

Getting started with RBAC user-defined roles

To help you get started with user-defined roles, this section walks you through an example scenario of enforcing least privilege by creating roles for three users with different job functions.

In this example, the following applies:

  • user1 is a new manager that needs to be able to view and access all databases in a cluster.

  • user2 is a new employee that needs only the ‘find’ action to only one database, sample-database-1, in that same cluster.

  • user3 is an existing employee that needs to view and access a specific collection, col2 in a different database, sample-database-2 that they didn't have access to before, in the same cluster.

  • For user1, create a role with read and write access to all databases in the entire cluster with the following command.

db.createUser( { user: "user1", pwd: "abc123", roles: [{role: "readWriteAnyDatabase", db: "admin"}] } )

Output from this operation looks something like the following.

{ "user":"user1", "roles":[ { "role":"readWriteAnyDatabase", "db":"admin" } ] }

For user2, create a role with ‘find’ privileges to all collections in the database sample-database-1 with the following command. Note that this role would ensure that any associated users can only run find queries.

db.createRole( { role: "findRole", privileges: [ { resource: {db: "sample-database-1", collection: ""}, actions: ["find"] }], roles: [] } )

Output from this operation looks something like the following.

{ "role":"findRole", "privileges":[ { "resource":{ "db":"sample-database-1", "collection":"" }, "actions":[ "find" ] } ], "roles":[ ] }

Next, create the user (user2) and attach the recently created role findRole to the user.

db.createUser( { user: "user2", pwd: "abc123", roles: [] }) db.grantRolesToUser("user2",["findRole"])

To simulate the scenario that user3 is an existing user, first create the user user3, and then create a new role called collectionRole which we will in the next step assing to user3.

Now you can assign a new role to user3. This new role will allow user3 to be able to insert, update, delete and find access to one specific collection col2 in sample-database-2.

db.createUser( { user: "user3", pwd: "abc123", roles: [] }) db.createRole( { role: "collectionRole", privileges: [ { resource: {db: "sample-database-2", collection: "col2"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )

Output from this operation looks something like the following.

{ "role":"collectionRole", "privileges":[ { "resource":{ "db":"sample-database-2", "collection":"col2" }, "actions":[ "find", "update", "insert", "remove" ] } ], "roles":[ ] }

Now that the user user3 has been created, you can grant user3 the role collectionFind.

db.grantRolesToUser("user3",["collectionRole"])

Lastly, both user1 and user2 leave the company and need their access to the cluster revoked. You can do this by dropping the users, as follows.

db.dropUser("user1") db.dropUser("user2")

To ensure that all users have the appropriate roles, you can list all users with the following command.

show users

Output from this operation looks something like the following.

{ "_id":"serviceadmin", "user":"serviceadmin", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"master-user", "user":"master-user", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"user3", "user":"user3", "db":"admin", "roles":[ { "db":"admin", "role":"collectionRole" } ] }

Connecting to Amazon DocumentDB as a User

When connecting to an Amazon DocumentDB cluster, you connect in the context of a particular database. By default, if you don't specify a database in your connection string, you are automatically connected to the cluster in the context of the test database. All collection level commands like insert and find are issued against collections in the test database.

To see the database you are in the context of or — in other words — issuing commands against, use the db command in the mongo shell, as follows.

Query:

db

Output:

test

Although the default connection might be in the context of the test database, that does not necessarily mean that the user associated with the connection is authorized to perform actions on the test database. In the preceding example scenario, if you authenticate as the user user3, which has the readWrite role for the sample-database-1 database, the default context of your connection is the test database. However, if you try to insert a document into a collection on the test database, you will receive an Authorization failure error message. This is because that user is not authorized to perform that command on that database, as shown below.

Query:

db

Output:

test

Query:

db.col.insert({x:1})

Output:

WriteCommandError({ "ok" : 0, "code" : 13, "errmsg" : "Authorization failure" })

If you change the context of your connection to the sample-database-1 database, you can write to the collection for which the user has the authorization to do so.

Query:

use sample-database-1

Output:

switched to db sample-database-1

Query:

db.col.insert({x:1})

Output:

WriteResult({ "nInserted" : 1})

When you authenticate to a cluster with a particular user, you can also specify the database in the connection string. Doing so removes the necessity to perform the use command after the user has been authenticated to the admin database.

The following connection string authenticates the user against the admin database, but the context of the connection will be against the sample-database-1 database.

mongo "mongodb://user3:abc123@sample-cluster.node.us-east-1.docdb.amazonaws.com:27017/sample-database-2"

Common commands

This section provides examples of common commands using role-based access control in Amazon DocumentDB. You must be in the context of the admin database to create and modify users and roles. You can use the use admin command to switch to the admin database.

Note

Modifications to the users and roles will implicitly occur in the admin database. Creating users with roles that are scoped across all databases (for example, readAnyDatabase) requires that you are either in the context of the admin database (that is, use admin) when creating the user, or you explicitly state the database for the role when creating the user (as shown in Example 2 in this section).

Example 1: Create a user with read role for the database foo.

db.createUser({user: "readInFooBar", pwd: "abc123", roles: [{role: "read", db: "foo"}]})

Output from this operation looks something like the following.

{ "user":"readInFooBar", "roles":[ { "role":"read", "db":"foo" } ] }

Example 2: Create a user with read access on all databases.

db.createUser({user: "readAllDBs", pwd: "abc123", roles: [{role: "readAnyDatabase", db: "admin"}]})

Output from this operation looks something like the following.

{ "user":"readAllDBs", "roles":[ { "role":"readAnyDatabase", "db":"admin" } ] }

Example 3: Grant read role to an existing user on a new database.

db.grantRolesToUser("readInFooBar", [{role: "read", db: "bar"}])

Example 4: Update a user's role.

db.updateUser("readInFooBar", {roles: [{role: "read", db: "foo"}, {role: "read", db: "baz"}]})

Example 5: Revoke access to a database for a user.

db.revokeRolesFromUser("readInFooBar", [{role: "read", db: "baz"}])

Example 6: Describe a built-in role.

db.getRole("read", {showPrivileges:true})

Output from this operation looks something like the following.

{ "role":"read", "db":"sample-database-1", "isBuiltin":true, "roles":[ ], "inheritedRoles":[ ], "privileges":[ { "resource":{ "db":"sample-database-1", "collection":"" }, "actions":[ "changeStream", "collStats", "dbStats", "find", "killCursors", "listCollections", "listIndexes" ] } ], "inheritedPrivileges":[ { "resource":{ "db":"sample-database-1", "collection":"" }, "actions":[ "changeStream", "collStats", "dbStats", "find", "killCursors", "listCollections", "listIndexes" ] } }

Example 7: Drop a user from the cluster.

db.dropUser("readInFooBar")

Output from this operation looks something like the following.

true

Example 8: Create a role with read and write access to a specific collection

db.createRole( { role: "collectionRole", privileges: [ { resource: {db: "sample-database-2", collection: "col2"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )

Output from this operation looks something like the following.

{ "role":"collectionRole", "privileges":[ { "resource":{ "db":"sample-database-2", "collection":"col2" }, "actions":[ "find", "update", "insert", "remove" ] } ], "roles":[ ] }

Example 9: Create a user and assign a user defined role

db.createUser( { user: "user3", pwd: "abc123", roles: [] }) db.grantRolesToUser("user3",["collectionRole"])

Example 10: Grant additional privileges to a user defined role

db.grantPrivilegesToRole( "collectionRole", [ { resource: { db: "sample-database-1", collection: "col1" }, actions: ["find", "update", "insert", "remove"] } ] )

Example 11: Remove privileges from a user defined role

db.revokePrivilegesFromRole( "collectionRole", [ { resource: { db: "sample-database-1", collection: "col2" }, actions: ["find", "update", "insert", "remove"] } ] )

Example 12: Update an existing user defined role

db.updateRole( "collectionRole", { privileges: [ { resource: {db: "sample-database-3", collection: "sample-collection-3"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )

Functional differences

In Amazon DocumentDB, user and role definitions are stored in the admin database and users are authenticated against the admin database. This functionality differs from the MongoDB Community Edition, but is consistent with MongoDB Atlas.

Amazon DocumentDB also supports change streams, which provide a time-ordered sequence of change events that occur within your cluster’s collections. The listChangeStreams action is applied at the cluster level (that is, across all databases), and the modifyChangeStreams action can be applied at the database level and cluster level.

Limits

The following table contains the limits for Role-Based Access Control in Amazon DocumentDB.

Description Limit
Number of users per cluster 1000
Number of roles associated with a user 1000
Number of user-defined roles 100
Number of resources associated with a privilege 100

Database access using Role-Based Access Control

With role-based access control, you can create a user and grant it one or more roles to determine what operations that user can perform in a database or cluster.

The following is a list of built-in roles that are currently supported in Amazon DocumentDB.

Note

In Amazon DocumentDB 4.0 and 5.0, the ListCollection and ListDatabase commands can optionally use the authorizedCollections and authorizedDatabases parameters to list the collections and databases that the user has permission to access with requiring the listCollections and listDatabase roles, respectively. Also, users now have the ability to kill their own cursors without requiring the KillCursor role.

Database user
Role name Description Actions
read Grants a user read access to the specified database.

changeStreams

collStats

dbStats

find

killCursors

listIndexes

listCollections

readWrite Grants the user read and write access to the specified database.

All actions from read permissions.

createCollection

dropCollection

createIndex

dropIndex

insert

killCursors

listIndexes

listCollections

remove

update

Cluster user
Role name Description Actions
readAnyDatabase Grants a user read access to all databases in the cluster.

All actions from read permissions.

listChangeStreams

listDatabases

readWriteAnyDatabase Grants a user read and write access to all databases in the cluster.

All actions from readWrite permissions.

listChangeStreams

listDatabases

userAdminAnyDatabase Grants a user the ability to assign and modify the roles or privileges any user has to the specified database.

changeCustomData

changePassword

createUser

dropRole

dropUser

grantRole

listDatabases

revokeRole

viewRole

viewUser

dbAdminAnyDatabase Grants a user the ability to perform database administration roles on any specified database.

All actions from dbAdmin permissions.

dropCollection

listDatabases

listChangeStreams

modifyChangeStreams

Superuser
Role name Description Actions
root Grants a user access to the resources and operations of all the following roles combined: readWriteAnyDatabase, dbAdminAnyDatabase, userAdminAnyDatabase, clusterAdmin, restore, and backup.

All actions from readWriteAnyDatabase, dbAdminAnyDatabase, userAdminAnyDatabase, clusterAdmin, restore, and backup.

Database administrator
Role name Description Actions
dbAdmin Grants a user the ability to perform administrative tasks on the specified database.

bypassDocumentValidation

collMod

collStats

createCollection

createIndex

dropCollection

dropDatabase

dropIndex

dbStats

find

killCursors

listIndexes

listCollections

modifyChangeStreams

dbOwner Grants a user the ability to perform any administrative tasks on the specified database by combining the roles dbAdmin and readWrite.

All actions from dbAdmin and readWrite.

Cluster administrator
role Name Description Actions
clusterAdmin Grants a user the greatest cluster management access by combining the clusterManager, clusterMonitor, and hostManager roles.

All actions from clusterManager, clusterMonitor, and hostManager.

listChangeStreams

dropDatabase

modifyChangeStreams

clusterManager Grants a user the ability to take management and monitoring actions on the specified cluster.

listChangeStreams

listSessions

modifyChangeStreams

replSetGetConfig

clusterMonitor Grants a user the ability to have read-only access to monitoring tools.

collStats

dbStats

find

getParameter

hostInfo

indexStats

killCursors

listChangeStreams

listCollections

listDatabases

listIndexes

listSessions

replSetGetConfig

serverStatus

top

hostManager Grants a user the ability to monitor and manage servers.

auditConfigure

killCursors

killAnyCursor

killAnySession

killop

Backup administrator
Role name Description Actions
backup Grants a user the access needed to back up data.

getParameter

insert

find

listChangeStreams

listCollections

listDatabases

listIndexes

update

restore Grants a user the access needed to restore data.

bypassDocumentValidation

changeCustomData

changePassword

collMod

createCollection

createIndex

createUser

dropCollection

dropRole

dropUser

getParameter

grantRole

find

insert

listCollections

modifyChangeStreams

revokeRole

remove

viewRole

viewUser

update