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

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...

Related

Cannot connect AppSmith to local PostgreSQL server

Problem
In general, there have been a ton of issues in connecting a remote service to a PostgreSQL database. The documentation for most services doesn't really have documentation for this since the task of connecting to a PostgreSQL database requires the Admin to modify both the postgresql.conf and pg_hba.conf files.
The current scenario is giving AppSmith remote access to the given server.
PostgreSQL needs to allow the following IP addresses at the pg_hba.conf: 18.223.74.85 and 3.131.104.27
Research SSL Connections and if one would be required in this case
Success Criteria:
Appsmith is able to connect to given database
Appsmith is able to read/write data to given database
Resolution Research
Allowing the above IP addresses to connect to the PostgreSQL database in the pg_hba.conf file and changing the postgresql.conf file to allow remote connections using listening_addresses = '*' did not resolve the issue. Appsmith is unable to connect to the database.
SSL Connection: SSL stands for Secure Sockets Layer and, in short, it's the standard technology for keeping an internet connection secure and safeguarding any sensitive data that is being sent between two systems, preventing criminals from reading and modifying any information transferred, including potential personal details.
SSL proved to be a dead-end for this issue with no resolution.
In order to create an SSL connection, the following steps must be followed (PostgreSQL SSL documentation: https://www.postgresql.org/docs/9.1/ssl-tcp.html):
OpenSSL needs to be installed on the host server (https://fedingo.com/how-to-install-openssl-in-ubuntu/). Determined that OpenSSL is already installed on the host server using openssl version -a.
Following the above steps from the postgresql documentation does not produce the desired result.
Following steps from https://www.cyberciti.biz/faq/postgresql-remote-access-or-connection/ does not work either.
Error in all cases on Appsmith: Failed to initialize pool: The connection attempt failed
Next-steps
Consult with the Stackoverflow community to see if anyone else is having a similar issue.
Similar issues have been found, but Appsmith documentation and the Stackoverflow community did not have the information needed to fulfill this issue. I will post the full case to the community.
I resolved this problem using ngrok to make a tcp tunnel on your localhost.
Donwload and conifg ngrok and create a new tunnel on terminal, just run ngrok tcp 5432 at terminal
After this, get the host/port and insert at Appsmith PostgreSQL Connection.
make sure your username/password is correct.
Image from host/port create on ngrok
Image to how config this host/port on Appsmith

could not initiate GSSAPI security context on Postgres 14 logical replication

I am following this post to enable ssl on Postgres 14 for logical replication. Then try to make connection on client:
CREATE SUBSCRIPTION my-sub
CONNECTION 'host=my-domain.com dbname=my-db user=my-username password=xxxxxx'
PUBLICATION my-pub;
It throws error:
2022-05-12 13:51:36.047 PDT [37340] ERROR: could not connect to the publisher: connection to server at "my_domain.com" (xxx.xxx.xxx.141), port 5432 failed: could not initiate GSSAPI security context: The operation or option is not available: Credential for asked mech-type mech not found in the credential handle
connection to server at "my_domain.com" (xxx.xxx.xxx.141), port 5432 failed: FATAL: connection requires a valid client certificate
connection to server at "my-domain.com" (xxx.xxx.xxx.141), port 5432 failed: FATAL: no pg_hba.conf entry for host "xxx.xxx.xxx.199", user "my-username", database "my-db", no encryption
On my-pub server, one line was added to pg_hba.conf:
hostssl all all 0.0.0.0/0 scram-sha-256 clientcert=verify-full
On sub client, the ca file is setup as below:
ssl_ca_file = '/usr/local/var/postgres/root.crt'. //<<==client cert copied from pub server.
Mostly people just use serve certs. Using client certs is unusual, I would say especially in the case of a logical replication subscriber. But if you do actually want the publisher to demand client certs, it is not configured incorrectly to that purpose (or at least, not that we can tell from the current data). The publisher is demanding a client cert, but the subscriber is not offering one. The configuration problem is on the subscriber.
Note that in this case the subscriber will be acting as the client to connect to the publisher, not acting in the role of a server. It uses the libpq client library to do that, and so the configuration of it is not based on the contents of postgresql.conf. In particular, ssl_ca_file is a server configuration option, not client configuration.
So the way to do this would be for the CONNECTION to look something like
'host=my-domain.com dbname=my-db user=my-username password=xxxxxx sslcert=/foobar/my-username.crt sslkey=/foobar/my-username.key'
But for this to work, the cert and key would need to be on the subscriber computer, readable to whomever owns the postgres process. Which already renders any security benefit dubious.

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.

How to connect to MongoDB Atlas using Robo 3T?

I'm trying to connect to MongoDB Atlas using Robo 3T.
I must be doing something wrong, cause when i'm trying to connect I get the following error message:
Failed to connect to cluster via SSL tunnel.
in details: Error: ssl connection failure: Authentication failed.
What iv'e tried so far:
Selected a "Direct connection" type.
I used my primary cluster as address (including the port number)
for Authentication I used "admin" Database, and put my username (my email) and the password of MongoDB Atlas.
I also white listed my IP address, and even set it as "allow access from anywhere", though it's not secure.
I checked "Use self-signed certificate"
Nothing I do seems to work.
Any idea what am I doing wrong?
thanks
At Atlas connections are SSL encrypted.
Go to SSL Tab in the connection settings window
Select Use SSL Protocol option
Now try connecting.
Exclude the port number in your cluster URI. :PORT. Exclude the port then use ssl and self certificate.

SSL error when connection pgAdmin3 to Heroku postgreSQL DB

When trying to connect to Heroku PostgresSQL DB using pgAdmin3 I'm getting the following error:
Error connecting to the server: SSL error: certificate verify failed
The connection is based on pg:credentials output and defined as below:
[Properties]:
Host: <host>
Port: 5432
Service: [blank]
Maintenance DB: <database>
Username: <user>
[SSL]:
SSL: require
Server Root Certificate File: [blank]
Server Certificate Revocation List: [blank]
Client Certificate File: [blank]
Client Key File: [blank]
SSL compression: on
[SSH Tunnel] and [Advanced] left default
so as per Heroku guidelines SSL is enabled (set to: [**require**]).
Any ideas how to provide/fix the certificate referred by the error message?
It's likely that pgAdmin is picking up a bundle of CA certificates that has been configured on your system, in which case require would try to verify the server certificate against that bundle.
Typically, this would be a root.crt file located in %APPDATA%\postgresql\ (C:\Users\YourUserName\AppData\Roaming\postgresql\) under Windows, or in ~/.postgresql/ under Linux.
If there is such a file, try to move it out of the way temporarily to check if it works better.
The problem with moving it out of the way is that you are then no longer verifying any remote PostgreSQL certificates against anything but it still works (with require, it would fail with verify-full).
You can solve this by putting the root.crt file in the right place and adding the server certificate to the list of trusted certificates.
It can be bit tricky to find a remote PostgreSQL certificate, but this simple Python application should let you do it (replace hostname and port as required):
import socket
import ssl
import struct
hostname = '...'
port = 5432
sock = socket.socket()
sock.connect((hostname, port))
# We first connect without encryption and tell the server
# we want to upgrade to SSL/TLS.
initiate_ssl_command = struct.Struct('!ii').pack(8, 80877103)
sock.sendall(initiate_ssl_command)
resp = sock.recv(1)
print "Response should be S: %s" % (resp,)
# We then initiate an SSL/TLS connection on this socket.
ssl_sock = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_NONE)
ssl_sock.do_handshake()
peer_cert = ssl_sock.getpeercert(True)
print ssl.DER_cert_to_PEM_cert(peer_cert)
ssl_sock.close()
(For details about what this code does, see the PostgreSQL protocol documentation, in particular the "SSL Session Encryption" section and the SSLRequest message, which is similar to what STARTTLS does in other protocols such as SMTP.)
Security warning: Here, you're just hoping that this particular connection has not been attacked and returns the genuine certificate the first time. It's what you'll use as a trust anchor for subsequent connections. (It's very similar to accepting an SSH server key for the first connection, it will flag changes to the certificate if it changes.)
It's also worth noting that the certificate Subject DN might not match that of the server you're connecting to, therefore you might not be able to use PostgreSQL's verify-full mode (which is the only really secure mode, since it also verifies the host name as well as the trust anchor).
Ideally, Heroku (or whoever provides this service) should give you that certificate by another secure means, and make sure that the Subject DN in that certificate matches the host name they give you. (I'm not sure if this is the case at the moment, perhaps it is available from the administration interface.)