mongodb / mongo-php-library

The Official MongoDB PHP library
https://mongodb.com/docs/php-library/current/
Apache License 2.0
1.6k stars 262 forks source link

Connecting to Atlas shards with TLS ERROR - No suitable servers found (serverSelectionTryOnce set): [TLS handshake failed ....'] #1359

Closed lpredova closed 3 months ago

lpredova commented 3 months ago

Bug Report

I'm running php:8.3.7-fpm-alpine3.19 on AWS linux2 machine.

After the upgrade from 7.4 and lib version 1.4.2 to 1.19.1 I am unable to connect to Atlas cluster with ssl turned on without having to set:

tlsAllowInvalidCertificates
tlsAllowInvalidHostnames

to true. When any of those flags is true the connection is successful and everything works, so network access settins on mongo are not the issue.

The error message i get when connecting to Atlas is one tls handshake error per every shard:

No suitable servers found (serverSelectionTryOnce set): [TLS handshake failed: Failed certificate verification calling hello on 'xxx.mongodb.net:27017'] [TLS handshake failed: Failed certificate verification calling hello on 'xxx.mongodb.net:27017'] [TLS handshake failed: Failed certificate verification calling hello on 'xxx.mongodb.net:27017']

And it used to work on 7.4 and 1.4.2 with having these properties set to true:

$driverOptions = [
                'allow_invalid_hostname' => !$verifyPeer,
                'weak_cert_validation' => !$verifyPeer,
            ];

My current connection strings with uri and ssl configs are (they havent changed) are:

"mongodb+srv://xxx.xxx.mongodb.net/my-db-name"
^ array:5 [▼
  "connectTimeoutMS" => 0
  "readPreference" => "primary"
  "ssl" => true
  "username" => "my-very-secret-user"
  "password" => "my-very-secret-pass"
   "tlsAllowInvalidHostnames" => true
]
^ array:8 [▼
  "default_cert_file" => "/etc/ssl/cert.pem"
  "default_cert_file_env" => "SSL_CERT_FILE"
  "default_cert_dir" => "/etc/ssl/certs"
  "default_cert_dir_env" => "SSL_CERT_DIR"
  "default_private_dir" => "/etc/ssl/private"
  "default_default_cert_area" => "/etc/ssl"
  "ini_cafile" => ""
  "ini_capath" => ""
]

When running this command from my docker alpine

openssl s_client -showcerts -connect xxx.xxx.mongodb.net:27017 < /dev/null

it outputs

SSL handshake has read 3977 bytes and written 481 bytes
Verification: OK

is is able to successfully connect to the atlas.

Environment

I'm running php:8.3.7-fpm-alpine3.19 on AWS linux2 machine. I'm trying to connect to mongo atlas - sharded cluster I believe via TLS connection

php -i | grep -E 'mongodb|libmongoc|libbson'

 /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini,
mongodb
libbson bundled version => 1.27.2
libmongoc bundled version => 1.27.2
libmongoc SSL => enabled
libmongoc SSL library => OpenSSL
libmongoc crypto => enabled
libmongoc crypto library => libcrypto
libmongoc crypto system profile => disabled
libmongoc SASL => disabled
libmongoc SRV => enabled
libmongoc compression => enabled
libmongoc compression snappy => disabled
libmongoc compression zlib => enabled
libmongoc compression zstd => enabled
libmongocrypt bundled version => 1.10.0
libmongocrypt crypto => enabled
libmongocrypt crypto library => libcrypto
mongodb.debug => no value => no value

composer show mongodb/mongodb outputs -> 1.19.1

Expected and Actual Behavior

The expected behaviour is that PHP connects to the Atlas with tls turned on without having to specify any additional flags that might compromise security of the system. The actual behaviour is that I currently have to enable insecure certs to get connection to work.

Minimal example

use MongoDB\Client;
use MongoDB\Driver\ServerApi;

$uri = 'mongodb+srv://username:password@xxx.xxx.mongodb.net/?retryWrites=true&w=majority&appName=MyAppName';

// Set the version of the Stable API on the client
$apiVersion = new ServerApi(ServerApi::V1);

// Create a new client and connect to the server
$client = new Client($uri, [], ['serverApi' => $apiVersion]);

try {
    // Send a ping to confirm a successful connection
    $client->selectDatabase('admin')->command(['ping' => 1]);
    echo "Pinged your deployment. You successfully connected to MongoDB!\n";
} catch (Exception $e) {
    printf("Error: %s\n", $e->getMessage());
}

Debug Log

Exceptions\Mongo\MongoException
No suitable servers found (`serverSelectionTryOnce` set): [TLS handshake failed: Failed certificate verification calling hello on 'xxx.xxx.mongodb.net:27017'] [TLS handshake failed: Failed certificate verification calling hello on 'xxx.xxx.mongodb.net:27017'] [TLS handshake failed: Failed certificate verification calling hello on 'xxx.xxx.mongodb.net:27017']

Does anyone know what could cause this behaviour or what should I check in order to fix this?

Update v1

After going thought issues on the library and the driver I added tlsCertificateKeyFile (not really sure what is the difference from tlsCAFile property )and now I get similar but much less descriptive error: Failed certificate verification -> connection

No suitable servers found (`serverSelectionTryOnce` set): [connection error calling hello on 'xxx.yyy.mongodb.net:27017'] [connection error calling hello on 'xxx.yyy.mongodb.net:27017'] [connection error calling hello on 'xxx.yyy.mongodb.net:27017']
bisht2050 commented 3 months ago

Solved in MongoDB Forums

The issue was in the libressl that my docker build was using, I replaced it with the openSSL and all of the sudden it started working like a charm.