How Security in MongoDB works (using x.509 cert)

1.6k views Asked by At

I Read through many documents in the mongoDB doc, still unclear how authentication works for clients an member of replica set(using x.509).

Found a resource "http://pe-kay.blogspot.in/2016/02/securing-mongodb-using-x509-certificate.html" which was well documented, still not clear as how authentication happens.

Considering the below mongoConfig and commands for starting server and mongo client:-

mongoConfig.cfg

storage:
    dbPath: "../DB"
  security:
    clusterAuthMode: x509
  net:
    port: 27001
  ssl:
    mode: "requireSSL"
    PEMKeyFile: "../server/security/one.pem"
    clusterFile: "../server/security/one.pem"
    CAFile: "../server/security/rootCA.crt"

Commands in Prompt:-

cPrompt> mongod -v --config "../custom/mongoConf.cfg" --replSet "one"

cPrompt> mongo -ssl --sslPEMKeyFile "../client/security/oneHost.pem" --sslCAFile "../client/security/rootCA.crt" --host mylocalhost --port 27001

1) Is it a oneWay or a twoWay SSL/TLS ?

2) How authentication between members of replicaSet takes place (mongod - mongod while doing replication) and between server-client (mongod-mongo say mongoShell or application) ?

3) Which version of TLS is used ?

Can someone explain in detail ?

1

There are 1 answers

2
Wernfried Domscheit On

This is an old question, however I was facing the same issues and it took me a lot of time to get it working. Some items are rather essential but quite hidden in the documentation.

I try to give an overview without doing simple copy/paste from the MongoDB documentation.

In general a x.509 certificate in MongoDB provides these functions:

  • Generate keys to encrypt the connection
  • Ensure the connection is established from correct host (i.e. the declared hostname matches the actual hostname)
  • Authenticate a client (instead of using username + password or keyfile)

As starting point, one should have a look at these tutorials:

TLS/SSL settings are defined in this configuration file section:

net:
   tls:
      certificateKeyFile: server.pem
      CAFile: server-ca.crt
      clusterFile: member.pem
      clusterCAFile: cluster-ca.crt

They correspond to command line options

  • --tlsCertificateKeyFile server.pem
  • --tlsCAFile server-ca.crt
  • --tlsClusterFile member.pem
  • --tlsClusterCAFile cluster-ca.crt

All other TLS/SSL related parameters are well documented and usually they should not cause any confusion or misunderstanding.

Step 1

When a client tries to establish a TLS/SSL enabled connection, then the mongod/mongos server presents a server certificate. The client verifies this certificate with a CA.

  • A client can be a normal client (e.g. the Mongo shell mongosh) or an internal Replica Set / Sharded Cluster member

  • The server certificate is always the same, mongod/mongos does not distinct the client types

  • The server certificate is defined by parameter

    net.tls.certificateKeyFile or --tlsCertificateKeyFile

  • A normal client can verify the server certificate for example with these:

    • Option --tls --tlsCAFile server-ca.cer

    • Option --tls --tlsUseSystemCA

    • Connection string parameter tls=true&tlsCAFile=server-ca.cer

    • --tlsUseSystemCA exists only as option, you cannot define it in connection string. Would be like this:

      mongosh --tlsUseSystemCA "mongodb://localhost/?tls=true"

  • An internal Replica Set / Sharded Cluster member verifies the server certificate by parameter

    net.tls.CAFile or --tlsCAFile

  • If net.tls.CAFile or --tlsCAFile is not specified and you are not using x.509 authentication, the system-wide CA certificate store will be used. If you use x.509 authentication, then net.tls.CAFile or --tlsCAFile is required.

Step 2

The client presents a client certificate to the mongod/mongos server. The client certificate can be used to authenticate the user. In this case, you don't have to provide a password/keyfile.

  • For normal client, x.509 authentication is enabled by user creation, e.g. db.getSiblingDB("$external").runCommand({createUser: "CN=myName,OU=myOrgUnit,O=myOrg,..."})
  • For Replica Set / Sharded Cluster member, x.509 authentication is enabled by parameter security.clusterAuthMode: x509

A normal client (e.g. mongosh) provides client certificate for example by these parameters:

  • mongosh --tls --tlsCertificateKeyFile client.pem (no x.509 authentication)
  • mongosh --tls --authenticationDatabase $external --authenticationMechanism MONGODB-X509 --tlsCertificateKeyFile client.pem (with x.509 authentication)
  • mongosh "mongodb://username:secret@localhost/?tls=true&authSource=admin&tlsCertificateKeyFile=client.pem" (no x.509 authentication)
  • mongosh "mongodb://localhost/?tls=true&authSource=$exernal&tlsCertificateKeyFile=client.pem&authMechanism=MONGODB-X509" (with x.509 authentication)

An internal Replica Set / Sharded Cluster member provides member certificate by parameter net.tls.clusterFile or --tlsClusterFile

  • The monogd/mongos sever verifies the client/member certificate with Root-CA defined by parameter net.tls.clusterCAFile or --tlsClusterCAFile
  • The client can be a normal client (e.g. the Mongo shell mongosh) or an internal Replica Set / Sharded Cluster member
  • The Root-CA is always the same, mongos/mongod does not distinct between client certificate and member certificate
  • If net.tls.clusterCAFile or --tlsClusterCAFile is not defined, then net.tls.CAFile/--tlsCAFile is used for verification.

Pitfalls:

  • Some MongoDB documentations just use the term "certificate" without a clear statement whether it applies to client certificates or server certificates or both. And often MongoDB documentation just use the term "client certificate" without a clear statement whether it applies to normal user client certificates or internal membership client certificates in a Replica Set / Sharded Cluster deployment.

    In this answer I use terms "server certificate", "client certificate" and "member certificate" for better understanding.

  • Server certificates and Member certificates must have the same O, OU, and DC in their subject name.

    Starting in MongoDB version 7.0 you can change this behavior by setting net.tls.clusterAuthX509.attributes, however so far I did not test it.

  • Client certificates and Member certificates must have different O, OU, and DC in their subject name

  • Parameter pairs certificateKeyFile/CAFile and clusterFile/clusterCAFile are not used to separate connections from normal clients and connections from Replica Set / Sharded Cluster members. They are used to separate client and server certificates, i.e. incoming and outgoing connections. In my opinion, these names are totally miss-leading.

  • You can use a common Root-CA, defined by net.tls.CAFile

  • You can also use the same certificate for client, member and server. This common certificate can be even used for x.509 authentication of Replica Set / Sharded Cluster members. This certificate only provides encrypted connection and x.509 member authentication. Of course, you cannot use it for x.509 authentication of normal clients.

  • Option tlsAllowInvalidCertificates has no effect on x509 authentication. For x509 authentication the certificate must be valid. Invalid certificates are only used to encrypt the connection.

Test cases:

openssl verify -CAfile server-ca.crt server.pem
openssl verify -CAfile cluster-ca.crt member.pem
openssl verify -CAfile cluster-ca.crt client.pem

# Verify server certificate:
openssl s_server -cert server.pem
# open another terminal
openssl s_client -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q

# Verify server and client certificate:
openssl s_server -cert server.pem -CAfile cluster-ca.crt -Verify 0
# open another terminal
openssl s_client -cert member.pem -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q
openssl s_client -cert client.pem -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q

Visualization

enter image description here

Or if you use only one CA certificate common-ca.crt:

enter image description here