x.509 Authentication not enabled in MongoDB - mongodb

I am trying to enable x.509 authentication in MongoDB.
I was able to compile with ssl support and was able to connect to the db using ca signed client certificate.
However it looks like all certificates signed by the same CA can connect to the database regardless of the username set in $external database.
Is this expected behaviour?
I thought mongodb would refuse connection from certificates that are not registered in $external database.
In my config file, I have following defined.
net:
ssl:
mode: requireSSL
PEMKeyFile: blah
PEMKeyPassword: blah
CAFile: blah
security:
authorization: enabled

This is as expected.
Anyone that has a certificate signed by the root CA you started mongo with will be able to connect to the database. However, when you auth and take an action (say, query a collection) the supplied cert will be checked against the $external database to see if the client has permissions to take that action.
db.getSiblingDB("$external").auth({ mechanism: "MONGODB-X509", user: "CN=MyCommonName,OU=MyOrgUnit,O=MyOrg,ST=Washington,C=US"})

Related

MongoDB Server accepting server certificate as client certificate

I seem to be a bit confused regarding the x509 certificate authentication in MongoDB.
TLDR:
I Created server- and client-certificates (signed by the same CA, but different CN and OU), created a user in the MongoDB using the subject name as username and successfully connected using the c# client + client certificates.
With the MongoDB Compass I was able to connect to and read from the server, using the server certificates as client certificates.
Why was I able to do authenticate using the wrong certificate? Is it not possible to control permissions on a per-certificate-basis?
Extended:
I Created a Self-Signed Root-CA using OpenSSL, which signed another certificate which is my Signing-CA.
Using this Signing-CA I created two more Certificates:
Server certificate (CN=Server1,OU=Servers,O=project,ST=SH,C=DE)
Client certificate (CN=Client1,OU=Clients,O=project,ST=SH,C=DE)
Having those certificates in place I started the MongoDB instance without authentication, initiated the replicaSet and created a user for the certificate using this command:
db.getSiblingDB("$external").runCommand({createUser: "CN=Client1,OU=Clients,O=project,ST=SH,C=DE",roles: [{role: "readWrite", db: "admin"}, {role: "userAdminAnyDatabase", db: "admin"}, {role: "clusterAdmin", db: "admin"}, {role: "root", db: "admin"}]});.
I restarded the server, this time using some more parameters to start with enabled authentication:
--replSet *replicaSetName* --port *port* --dbpath *path* --logpath *path* --tlsMode requireTLS --clusterAuthMode x509 --tlsCAFile *path* --tlsCertificateKeyFile *path* --tlsClusterFile *path* --auth
I was able to connect without an issue using the C# client, the MongoDB Compass worked aswell.
But when I tested other certificates to verify the security, I noticed that it was absolutely possible to use the server certificate and key file to connect to the server using the MongoDB compass.
I Could not only connect, but browse and modify data aswell.
I was under the impression that every client certificate has to have an associated account in the $external database and thus only has the permissions/roles I assigned/granted to this specific user account.
Is this behavior supposed to be happening?
Is it possible to create one user account per client-certificate and grant different permisisons on different databases?
Thanks for your attention and answers, have a good day!
It depends on how you have configured your mongod process. Assuming you have a configuration file for your mongod (default path is /etc/mongod.conf) you would look to see if you have net.tls and security.clusterAuthMode settings..
Example Configuration file with these settings:
storage:
dbPath: /data/db
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27017
bindIp: 0.0.0.0
tls:
mode: requireTLS
certificateKeyFile: /etc/ssl/node1.pem
CAFile: /etc/ssl/ca.crt
clusterFile: /etc/ssl/node1.pem
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
timeZoneInfo: /usr/share/zoneinfo
security:
authorization: enabled
clusterAuthMode: x509
replication:
replSetName: replset
Other things
Recently MongoDB switched from SSL to TLS so depending on the version you are using you may find SSL instead of TLS.
Also, you might be using a replica set, or you might not be. If using a replica set you need to decide how a replica set member will authenticate to the other members. Should it use a keyfile, or should it use x509 as well as ordinary database users.
Also, you will need to create at least one named database user. The system will allow root access to the connected user if it is bound to localhost and no other users exist. This is called the localhost exception. Missing these steps is an incomplete and insecure installation.
Socket/TLS connection and authentication are separate steps in the high level connection establishment process.
The word "connection" is used by people to refer to multiple separate operations and processes and when troubleshooting any of these you need to be very clear about what it is you are looking at/asking about:
Socket connection from driver to server
Authentication by the driver (doesn't happen on monitoring connections which still go through the socket connection process)
Client object creation (not strictly a connection at all, though many people sloppily/erroneously use the word "connection" to refer to the action of creating a client object - creating a client object itself doesn't connect anything to anywhere)
Performing operations (even a server with authentication enabled permits one to create socket connections to it and execute operations like the ismaster command without authentication)
You probably are meaning to ask about #2 but you tested either #3 or #4, which as you should now see isn't necessarily giving you the expected results.
When TLS is enabled and "insecure TLS" isn't, the server will validate the client's TLS certificate (and the client will validate the server's) during the socket connection process. The certificate being validated must be signed by the CA that the validator is configured with. At this point there isn't anything preventing the client from supplying the server's certificate to the server, if you managed to give the client the private key that goes with the server's certificate (which normally shouldn't happen). The server warns about this situation in the logs. Note that no authentication has happened yet.
If you are using X.509 authentication (which must be configured on the client side and is separate from supplying certificates used for the socket connection, e.g. use the authMechanism URI option) then, after a successful socket connection and any associated certificate verification, the driver will perform the authentication. At this point you need to have the server user created that matches the distinguished name on the certificate.
MongoDB has guides for both setting up TLS connections and X.509 auth, read through them and follow them exactly as written and verify each step of the way.

MongoDB SSL connection with self signed certificate

In the recent light of events of the MongoDB hacks. we too were hit by the hackers.
We enabled the authorization and changed the default port of the server.
However we want to encrypt our communication channel with the server with the help of a self signed certificate.
so our configuration looks like below
tls:
mode: requireTLS
allowConnectionsWithoutCertificates: false
certificateKeyFile: /etc/ssl/server.pem
CAFile: /etc/ssl/ca.crt
what happens is when I try to connect the mongoshell with the client certificate the connection is constantly denied. But after commenting the CAFile config and using --tlsAllowInavlidCertificates the connection is created.
I created the certificate with the following link:
https://gist.github.com/kevinadi/96090f6f9973ff8c2d019bbe0d9a0f70
To connect to the server I'm using the following command:
mongo --host hostname --username user --password password --authenticationDatabase admin --port port --tls --tlsCertificateKeyFile client.pem --tlsCAFile ca.crt
I dont know what I'm doing wrong and is this the correct way to do it even?
The server log contains reasons why connections are rejected.

PostgreSQL SSL doesn't work in cmd and java

Please help with the following problem ...
OS - Windows.
I want to configure SSL on Postgresql 12.
Then my Java application will add entries to the database, delete, etc.
I created certificates: CA, server, client.
CA and server are located in the directory C:\Program Files\PostgreSQL\12\data
The client is located in C:\Users\User\AppData\postgresql
Then I added CA certificate to trusted in Windows.
Configs:
pg_hba:
hostnossl all all 0.0.0.0/0 reject
hostssl all all 0.0.0.0/0 cert clientcert=1
postgresql.conf:
ssl = on
ssl_ca_file = 'root.crt'
I can connect server throw pgAdmin with my certificates, but there are some errors in cmd (and java)
Thant's what I tried to do in cmd
psql.exe -U postgres -h 127.0.0.1
Result:
SSL: certificate verify failed
FATAL: pg_hba.conf rejects connection for host "127.0.0.1", user "postgres", database "prod", SSL off
Logs:
tlsv1 alert unknown ca
FATAL: pg_hba.conf rejects connection for host "127.0.0.1", user "postgres", database "prod", SSL off
Please, tell me what's can be wrong and how can I fix it...
Also I did not find information, how to transfer my certificates to the database from Java application. Maybe, anybody can help me with that problem))
Thanks!
use this in your connection string and it will work:
ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Then I added CA certificate to trusted in Windows.
psql does not integrate with the Windows certificate manager. The CA to be used by the client needs to go in %APPDATA%\postgresql\root.crt, or if elsewhere its location must be specified by a connection parameter (sslrootcert) or environment variable (PGSSLROOTCERT). These must be files, I don't think there is way to say "go get it from the cert manager".
I think jdbc is the same way, it does not integrate with the Windows cert manager either, for how to specify the locations see https://jdbc.postgresql.org/documentation/head/ssl-client.html
SSL: certificate verify failed FATAL: pg_hba.conf rejects connection for host "127.0.0.1", user "postgres", database "prod", SSL off
Maybe you already know this, but first it tried using SSL and failed to verify the cert (it does not make it clear which side failed, the client cert or the server cert), then it tried to fall back to no SSL and got rejected by the pg_hba. If you had set the client's sslmode to "require" or higher, it would not have tried to fall back to the no SSL, it would have stopped at the first error.

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

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 ?
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 Configuration for Clients
Configure mongod and mongos for TLS/SSL
Use x.509 Certificates to Authenticate Clients
Use x.509 Certificate for Membership Authentication
In general 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 Mongo documents just refer to "client" certificate/connection. Be aware, this means normal clients (e.g. mongosh) as well as internal Replica Set / Sharded Cluster member clients. In this answer I use terms "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
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 member 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
openssl s_server -cert server.pem -CAfile cluster-ca.crt
# 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

Parse + mongodb + SSL: "no SSL certificate provided by peer"

In the course of migrating off Parse's servers before it shuts down, I'm trying to set up a simple MongoDB instance on Digital Ocean. (I'm using that instead of mLab because my needs are very limited—-a few MB of storage, a few hundred requests per week--and for that mLab's costs are pretty high.)
I've got mongod running, and have made some progress with SSL thanks to this guide using Let's Encrypt, but now I'm stuck. Parse's migration tool says, "No reachable servers," and if I try to connect on the command line like this:
mongo --ssl -u editAdmin -p "<password-here>" --host mydb.myhost.com dbname
I get this error:
MongoDB shell version: 3.2.7
connecting to: mydb.myhost.com:27017/dbname
2016-07-24T10:31:38.814-0700 E QUERY [thread1] Error: network error while attempting to run command 'isMaster' on host 'mydb.myhost.com:27017' :
connect#src/mongo/shell/mongo.js:231:14
#(connect):1:6
exception: connect failed
The server log reports:
2016-07-24T13:32:44.357-0400 I NETWORK [initandlisten] connection accepted from 12.345.67.89:33351 #39 (1 connection now open)
2016-07-24T13:32:44.390-0400 E NETWORK [conn39] no SSL certificate provided by peer; connection rejected
2016-07-24T13:32:44.390-0400 I NETWORK [conn39] end connection 12.345.67.89:33351 (0 connections now open)
So that would suggest the client needs to provide a cert, but (a) I don't know how to provide one, and (b) Parse doesn't provide that as an option so there must be some way not to.
Thanks in advance for your help.
The key error message is this one:
no SSL certificate provided by peer; connection rejected
When you enable TLS/SSL on MongoDB, MongoDB clients can now authenticate that the MongoDB server is who it claims to be by comparing the MongoDB's TLS/SSL certificate (specified by the PEMKeyFile property in the mongod.conf file) against the public Certificate Authority certificate that you provide to the MongoDB client to indicate which Certificate Authority you trust.
But what I just described is sometimes called one-way TLS, whereas, by default, MongoDB enables two-way or mutual TLS authentication. The idea behind this is that maybe the MongoDB doesn't want to accept client requests from just anyone (the way a public website might), but wants to authenticate the clients as well.
In TLS Mutual Auth, the same Certificate Authority I mentioned above will issue client certificates and the MongoDB server will check the client's certificate to make sure it really was issued by the Certificate Authority in question and that it's valid (e.g. hasn't expired).
So this error is saying "Hey, I expect my clients to present a TLS certificate, but you're not presenting anything."
The way to fix it is described at Configure mongod and mongos for TLS/SSL:
If you want to bypass validation for clients that don’t present
certificates, include the allowConnectionsWithoutCertificates run-time
option with mongod and mongos. If the client does not present a
certificate, no validation occurs. These connections, though not
validated, are still encrypted using SSL.
Of course, you can specify this in the mongod.conf file as well: https://docs.mongodb.com/manual/reference/configuration-options/#net.ssl.allowConnectionsWithoutCertificates
My preferred solution looks like this:
net:
port: 27017
bindIp: 172.0.0.1 # Set this to whatever your private IP address is
ssl:
mode: "requireSSL"
PEMKeyFile: "/path/to/tls/private/key"
CAFile: "/path/to/ca/public/cert"
disabledProtocols: "TLS1_0,TLS1_1"
allowConnectionsWithoutCertificates: true # <-- The line to add to your config
You're command is using the SSL option (and I assume Parse is doing the same) so you are trying to connect using SSL. A client must provide a cert when using SSL. https://docs.mongodb.com/manual/tutorial/configure-ssl-clients/ this link explains how to do this and also specifically mentions your issue
Just follow this tutorial, everything is there, I know that for sure cause I was following that and now I got running parse-server without any previous knowledge... I would recommend you using the MongoDB connection without SSL certificate and allow only localhost queries to it - so only the parse-server that runs on the same machine will access this DB...