Fix This Page
Navigation

Enforce Keyfile Access Control in a Replica Set without Downtime

Overview

To secure against unauthorized access, enforce authentication in sharded cluster deployments. Authentication in MongoDB consists of internal authentication among the replica set members, and user access control for clients connecting to the replica set.

If your deployment does not enforce authentication, MongoDB 3.4 provides the --transitionToAuth option for performing a no-downtime upgrade to enforcing authentication.

New in version 3.4: MongoDB 3.2 and earlier do not support a no-downtime upgrade to enforce authentication. See Enforce Keyfile Access Control in a Replica Set for enforcing authentication in an existing MongoDB 3.2 replica set.

This tutorial uses the keyfile internal authentication mechanism for internal security, and SCRAM-SHA-1-based role-based access controls for client connections.

Cloud Manager and Ops Manager

If you are using Cloud Manager or Ops Manager to manage your deployment, see: Configure Access Control for MongoDB Deployments in the Cloud Manager manual or in the Ops Manager manual to enforce authentication.

Architecture

This tutorial assumes that your replica set can elect a new primary after stepping down the existing primary replica set member. This requires:

Transition State

A mongod running with --transitionToAuth accepts both authenticated and non-authenticated connections. Clients connected to the mongod during this transition state can perform read, write, and administrative operations on any database.

Client Access

At the end of the following procedure, the replica set rejects any client attempting to make a non-authenticated connection. The procedure creates users for client applications to use when connecting to the replica set.

See Configure Role-Based Access Control for user creation and management best practices.

Enforce Keyfile Access Control on Existing Replica Set

1

Create the user administrator.

The userAdminAnyDatabase role grants access to user creation on any database in the deployment.

You must connect to the primary to create users.

The following example creates the user fred with the userAdminAnyDatabase role on the admin database.

Important

Passwords should be random, long, and complex to ensure system security and to prevent or delay malicious access.

admin = db.getSiblingDB("admin")
admin.createUser(
  {
    user: "fred",
    pwd: "changeme1",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)

At the completion of this procedure, any client that administers users in the replica set must authenticate as this user, or a user with similar permissions.

See Database User Roles for a full list of built-in roles and related to database administration operations.

2

Create the cluster administrator.

The clusterAdmin role grants access to replication operations, such as configuring the replica set.

You must connect to the primary to create users.

The following example creates the user ravi with the clusterAdmin role on the admin database.

Important

Passwords should be random, long, and complex to ensure system security and to prevent or delay malicious access.

db.getSiblingDB("admin").createUser(
  {
    "user" : "ravi",
    "pwd" : "changeme2",
    roles: [ { "role" : "clusterAdmin", "db" : "admin" } ]
  }
)

At the completion of this procedure, any client that administrates or maintains the replica set must authenticate as this user, or a user with similar permissions.

See Cluster Administration Roles for a full list of built-in roles related to replica set operations.

3

Create users for client applications.

Create users to allow client application to connect and interact with the replica set. At the completion of this tutorial, clients must authenticate as a configured user to connect to the replica set.

See Database User Roles for basic built-in roles to use in creating read-only and read-write users.

The following creates a user with read and write permissions on the foo database.

Important

Passwords should be random, long, and complex to ensure system security and to prevent or delay malicious access.

Create a user with the readWrite role in the foo database.

db.getSiblingDB("foo").createUser(
  {
    "user" : "joe",
    "pwd" : "changeme2",
    roles: [ { "role" : "readWrite", "db" : "foo" } ]
  }
)

Clients authenticating as this user can perform read and write operations against the foo database. See Authenticate a User for more on creating an authenticated connection to the replica set.

See the Add Users tutorial for more information on adding users. Consider security best practices when adding new users.

4

Update Client Applications

At this point in the procedure, the replica set does not enforce authentication. However, client applications can still specify auth credentials and connect to the replica set.

Update client applications to authenticate to the replica set using a configured user. Authenticated connections require a username, password, and the authentication database. See Authenticate a User.

For example, the following connects to a replica set named mongoRepl and authenticates as the user joe.

mongo  -u joe -password changeme2 -authenticationDatabase foo --host mongoRepl/mongo1.example.net:27017, mongo2.example.net:27017, mongo3.example.net:27017

If your application uses a MongoDB driver, see the associated driver documentation for instructions on creating an authenticated connection.

At the completion of this tutorial, the replica set rejects non-authenticated client connections. Performing this step now ensures clients can connect to the replica set before and after the transition.

5

Create a keyfile.

The contents of the keyfile serves as the shared password for the members of the replica set. The content of the keyfile must be the same for all members of the replica set.

You can generate a keyfile using any method you choose. The contents of the keyfile must be between 6 and 1024 characters long.

Note

On UNIX systems, the keyfile must not have group or world permissions. On Windows systems, keyfile permissions are not checked.

The following operation uses openssl to generate a complex pseudo-random 1024 character string to use for a keyfile. It then uses chmod to change file permissions to provide read permissions for the file owner only:

openssl rand -base64 756 > <path-to-keyfile>
chmod 400 <path-to-keyfile>

See Keyfiles for additional details and requirements for using keyfiles.

6

Copy the keyfile to each replica set member.

Copy the keyfile to each server hosting the replica set members. Use a consistent location for each server.

Important

Do not use shared network locations or storage mediums such as USB drives for storing the keyfile.

Ensure that the user running the mongod instances can access the keyfile.

7

Restart each secondary or arbiter member of the replica set with transitionToAuth.

Restart each secondary or arbiter member in the replica set, specifying the --transitionToAuth option and an internal authentication mechanism such as --keyfile. You must do this one at a time to ensure a majority of members in the replica set remain online.

Shut down the secondary or arbiter members.

From a mongo shell connected to the secondary or arbiter, issue the db.shutdownServer() against the admin database.

admin = db.getSiblingDB("admin")
admin.shutdownServer()

Restart the secondary or arbiter members with transitionToAuth

Restart the mongod, this time specifying the --transitionToAuth option and an internal authentication mechanism such as --keyfile.

Starting the mongod with --transitionToAuth places the instance in a transition state where it can accept and create both authenticated and non-authenticated connections.

Specify the following settings in your configuration file.

security:
  keyFile: <path-to-keyfile>
  transitionToAuth: true
replication:
  replSetName: <replicaSetName>

Specify the --config option with the path to the configuration file when starting the mongod.

mongod --config <path-to-config-file>

For more information on the configuration file, see configuration options.

You can also use the equivalent mongod options when starting your mongod. See the mongod reference page for a complete list of options.

Include additional settings as appropriate to your deployment.

At the end of this step, all secondaries and arbiters should be up and running with --transitionToAuth.

8

Step down the primary member of the replica set and restart it with --transitionToAuth.

Restart the primary member in the replica set, specifying the --transitionToAuth option and an internal authentication mechanism such as --keyfile.

Step down the primary replica set member

Connect to the primary using a mongo shell and step down the primary using the rs.stepDown() method.

rs.stepDown()

Shut down the old primary

Once the primary steps down and the replica set elects a new primary, shut down the old primary mongod.

From a mongo shell connected to the old primary, issue the db.shutdownServer() on the admin database.

admin = db.getSiblingDB("admin")
admin.shutdownServer()

Restart the old primary with transitionToAuth

Restart the mongod, this time specifying the --transitionToAuth option and an internal authentication mechanism such as --keyfile.

Starting the mongod with --transitionToAuth places the instance in a transition state where it can accept and create both authenticated and non-authenticated connections.

Specify the following settings in your configuration file.

security:
  keyFile: <path-to-keyfile>
  transitionToAuth: true
replication:
  replSetName: <replicaSetName>

Start the mongod using the configuration file.

mongod --config <path-to-config-file>

For more information on the configuration file, see configuration options.

You can also use the equivalent mongod options when starting your mongod. See the mongod reference page for a complete list of options.

Include additional settings as appropriate to your deployment.

At the end of this step, all members of the replica set should be up and running with --transitionToAuth and --keyfile.

9

Restart secondaries and arbiters without --transitionToAuth

Restart each secondary or arbiter member in the replica set, removing the --transitionToAuth option on restart. You must do this one at a time to ensure a majority of members in the replica set remain online.

If the majority of replica set members are offline at the same time, the replica set may go into read-only mode.

Shut down the secondary or arbiter members

Connect to a mongo shell to the secondary or arbiter, and issue the db.shutdownServer() on the database.

admin = db.getSiblingDB("admin")
admin.shutdownServer()

Restart the secondary or arbiter members without transitionToAuth

Restart the mongod, this time without the --transitionToAuth option and with internal authentication mechanism such as --keyfile.

Starting the mongod with --transitionToAuth places the instance in a transition state where it can accept and create both authenticated and non-authenticated connections.

Specify the following settings in your configuration file.

security:
  keyFile: <path-to-keyfile>
replication:
  replSetName: <replicaSetName>

Start the mongod using the configuration file:

mongod --config <path-to-config-file>

For more information on the configuration file, see configuration options.

You can also use the equivalent mongod options when starting your mongod. See the mongod reference page for a complete list of options.

Include additional settings as appropriate to your deployment.

At the end of this step, all secondaries and arbiters should be up and running with internal authentication configured, but without --transitionToAuth. Clients can only connect to these mongod instances by using the configured client authentication mechanism.

10

Step down and restart the primary replica set member without --transitionToAuth.

Step down the primary member in the replica set, then restart it without the --transitionToAuth option.

Important

At the end of this step, clients not connecting with auth cannot connect to the replica set. Update clients to connect with authentication before completing this step to avoid loss of connectivity.

Step down the primary replica set member

Connect to the primary using a mongo shell and step down the primary using the rs.stepDown() method.

rs.stepDown()

Shut down the old primary

Once the primary steps down and the replica set elects a new primary, shut down the old primary mongod.

From a mongo shell connected to the old primary, issue the db.shutdownServer() on the admin database.

admin = db.getSiblingDB("admin")
admin.shutdownServer()

Restart the old primary without transitionToAuth

Restart the mongod, this time without the --transitionToAuth option and with internal authentication mechanism such as --keyfile.

Starting the mongod with --transitionToAuth places the instance in a transition state where it can accept and create both authenticated and non-authenticated connections.

Specify the following settings in your configuration file.

security:
  keyFile: <path-to-keyfile>
replication:
  replSetName: <replicaSetName>

Start the mongod using the configuration file:

mongod --config <path-to-config-file>

For more information on the configuration file, see configuration options.

You can also use the equivalent mongod options when starting your mongod. See the mongod reference page for a complete list of options.

Include additional settings as appropriate to your deployment.

At the end of this step, all members of the replica set should be up and running with authentication enforced. Clients can only connect to these mongod instances by using the configured client authentication mechanism.

x.509 Internal Authentication

For details on using x.509 for internal authentication, see Use x.509 Certificate for Membership Authentication.

To upgrade from keyfile internal authentication to x.509 internal authentication, see Upgrade from Keyfile Authentication to x.509 Authentication.