Configure Transport Layer Security (TLS) (original) (raw)

In this guide, you can learn how to use the TLSprotocol to secure your connection to a MongoDB deployment.

When you enable TLS for a connection, PyMongo performs the following actions:

To learn how to configure your MongoDB deployment for TLS, see theTLS configuration guide in the MongoDB Server manual.

Important

A full description of TLS/SSL, PKI (Public Key Infrastructure) certificates, and Certificate Authorities (CAs) is beyond the scope of this document. This page assumes prior knowledge of TLS/SSL and access to valid certificates.

To enable TLS for the connection to your MongoDB instance, set the tls connection option to True. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>", tls=True)


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>?tls=true")


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>", tls=True)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>?tls=true")

Tip

If your connection string includes the +srv modification, which specifies the SRV connection format, TLS is enabled on your connection by default.

To learn more about the SRV connection format, seeSRV Connection Formatin the MongoDB Server documentation.

During the TLS handshake, the MongoDB deployment presents a certificate key file to your application to establish its identity. Usually, a deployment's certificate has been signed by a well-known CA, and your application relies on this CA to validate the certificate.

During testing, however, you might want to act as your own CA. In this case, you must instruct PyMongo to use your CA certificates instead of ones signed by another CA.

To do so, use the tlsCAFile connection option to specify the path to a .pem file containing the root certificate chain. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsCAFile="/path/to/ca.pem")


uri = "mongodb://<db_username>:<db_password>@<hostname>:<port>/?tls=true&tlsCAFile=/path/to/ca.pem"

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsCAFile="/path/to/ca.pem")


uri = "mongodb://<db_username>:<db_password@<hostname>:<port>/?tls=true&tlsCAFile=/path/to/ca.pem"

client = pymongo.AsyncMongoClient(uri)

When an X.509 certificate is no longer trustworthy—for example, if its private key has been compromised—the CA revokes the certificate. PyMongo includes two ways to check whether a server's certificate has been revoked.

To use the Online Certificate Status Protocol (OCSP) to validate a server certificate, you must install PyMongo with the ocsp option, as shown in the following example:


python -m pip install pymongo[ocsp]

The certificate-validation process varies depending on the version of MongoDB Server you're connecting to:

To stop PyMongo from contacting the OCSP endpoint, set thetlsDisableOCSPEndpointCheck connection option to True. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsDisableOCSPEndpointCheck=True)


uri = "mongodb://example.com/?tls=true&tlsDisableOCSPEndpointCheck=true"

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsDisableOCSPEndpointCheck=True)


uri = "mongodb://example.com/?tls=true&tlsDisableOCSPEndpointCheck=true"

client = pymongo.AsyncMongoClient(uri)

Note

Even if the tlsDisableOCSPEndpointCheck option is set to True, PyMongo still verifies any OCSP response stapled to a server's certificate.

Instead of using OCSP, you can instruct PyMongo to check the server's certificate against a Certificate Revocation List (CRL) published by the CA. To do so, use the tlsCRLFile connection option to specify the path to a .pemor .der file from the CA. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsCRLFile="/path/to/crl.pem")


uri = "mongodb://example.com/?tls=true&tlsCRLFile=/path/to/crl.pem"

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsCRLFile="/path/to/crl.pem")


uri = "mongodb://example.com/?tls=true&tlsCRLFile=/path/to/crl.pem"

client = pymongo.AsyncMongoClient(uri)

Note

You can't use both a CRL and OCSP in the same TLS handshake.

Some MongoDB deployments require every connecting application to present a client certificate that proves its identity. To specify the client certificate for PyMongo to present, set the tlsCertificateKeyFile option to the file path of the .pem file that contains your certificate and private key. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsCertificateKeyFile='/path/to/client.pem')


uri = ("mongodb://<db_username>:<db_password>@<hostname:<port>/?"

       "tls=true"

       "&tlsCertificateKeyFile=path/to/client.pem")

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsCertificateKeyFile='/path/to/client.pem')


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsCertificateKeyFile=path/to/client.pem")

client = pymongo.AsyncMongoClient(uri)

Important

Your client certificate and private key must be in the same .pem file. If they are stored in different files, you must concatenate them. The following example shows how to concatenate a key file and a certificate file into a third file calledcombined.pem on a Unix system:


$ cat key.pem cert.pem > combined.pem

If the private key in your certificate file is encrypted, you must provide a password. To do so, use the tlsCertificateKeyFilePassword connection option to specify the password or passphrase for the encrypted private key. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>",

                       tls=True,

                       tlsCertificateKeyFile='/path/to/client.pem',

                       tlsCertificateKeyFilePassword=<passphrase>)


uri = ("mongodb://<db_username>:<db_password>@<hostname:<port>/?"

       "tls=true"

       "&tlsCertificateKeyFile=path/to/client.pem"

       "&tlsCertificateKeyFilePassword=<passphrase>")

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                              tls=True,

                              tlsCertificateKeyFile='/path/to/client.pem',

                              tlsCertificateKeyFilePassword=<passphrase>)


uri = ("mongodb://<db_username>:<db_password"

       "@<hostname>:<port>/?"

       "tls=true"

       "&tlsCertificateKeyFile=path/to/client.pem"

       "&tlsCertificateKeyFilePassword=<passphrase>")

client = pymongo.AsyncMongoClient(uri)

When TLS is enabled, PyMongo automatically verifies the certificate that the server presents. When testing your code, you can disable this verification. This is known as insecure TLS.

When insecure TLS is enabled, PyMongo requires only that the server present an X.509 certificate. The driver accepts a certificate even if any of the following are true:

Note

Even when insecure TLS is enabled, communication between the client and server is encrypted with TLS.

To enable insecure TLS, set the tlsInsecure connection option to True. You can do this in two ways: by passing an argument to theMongoClient constructor or through a parameter in your connection string.


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>",

                             tls=True,

                             tlsInsecure=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsInsecure=true")

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsInsecure=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsInsecure=true")

client = pymongo.AsyncMongoClient(uri)

To disable only certificate validation, set the tlsAllowInvalidCertificates option toTrue, and set the tlsInsecure option to False or omit it:


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsAllowInvalidCertificates=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsAllowInvalidCertificates=true")

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsAllowInvalidCertificates=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsAllowInvalidCertificates=true")

client = pymongo.AsyncMongoClient(uri)

To disable only hostname verification, set the tlsAllowInvalidHostnames option toTrue, and set the tlsInsecure option to False or omit it:


client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                             tls=True,

                             tlsAllowInvalidHostnames=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsAllowInvalidHostnames=true")

client = pymongo.MongoClient(uri)


client = pymongo.AsyncMongoClient("mongodb://<db_username>:<db_password>@<hostname>:<port>",

                                  tls=True,

                                  tlsAllowInvalidHostnames=True)


uri = ("mongodb://<db_username>:<db_password>@<hostname>:<port>/?"

       "tls=true"

       "&tlsAllowInvalidHostnames=true")

client = pymongo.AsyncMongoClient(uri)

Warning

Don't Use in Production

Always set the tlsInsecure, tlsAllowInvalidCertificates, andtlsAllowInvalidHostnames options to False in production.

Setting any of these options to True in a production environment makes your application insecure and potentially vulnerable to expired certificates and to foreign processes posing as valid client instances.

An error message similar to the following means that OpenSSL couldn't verify the server's certificate:


[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

This often happens because OpenSSL can't access the system's root certificates, or because the certificates are out of date.

If you use Linux, ensure that you have the latest root certificate updates installed from your Linux vendor.

If you use macOS, and if you're running Python v3.7 or later that you downloaded from python.org, run the following command to install root certificates:


open "/Applications/Python <YOUR PYTHON VERSION>/Install Certificates.command"

Tip

If you use portable-pypy, you might need to set an environment variable to tell OpenSSL where to find root certificates. The following code example shows how to install thecertifi module from PyPi and export the SSL_CERT_FILE environment variable:


$ pypy -m pip install certifi

$ export SSL_CERT_FILE=$(pypy -c "import certifi; print(certifi.where())")

Tip

An error message similar to the following means that the OpenSSL version used by Python doesn't support a new enough TLS protocol to connect to the server:


[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version

Industry best practices recommend, and some regulations require, that older TLS protocols be disabled in some MongoDB deployments. Some deployments might disable TLS 1.0, while others might disable TLS 1.0 and TLS 1.1.

No application changes are required for PyMongo to use the newest TLS versions, but some operating system versions might not provide an OpenSSL version new enough to support them.

If you use macOS v10.12 (High Sierra) or earlier, install Python from python.org, homebrew, macports, or a similar source.

If you use Linux or another non-macOS Unix, use the following command to check your OpenSSL version:

If the preceding command shows a version number less than 1.0.1, support for TLS 1.1 or newer isn't available. Upgrade to a newer version or contact your OS vendor for a solution.

To check the TLS version of your Python interpreter, install the requests module and execute the following code:


python -c "import requests; print(requests.get('https://www.howsmyssl.com/a/check', verify=False).json()['tls_version'])"

You should see TLS 1.1 or later.

An error message similar to the following means that certificate revocation checking failed:


[('SSL routines', 'tls_process_initial_server_flight', 'invalid status response')]

For more details, see the OCSP section of this guide.

When using Python v3.10 or later with MongoDB versions earlier than v4.0, you might see errors similar to the following messages:


SSL handshake failed: localhost:27017: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)

SSL handshake failed: localhost:27017: EOF occurred in violation of protocol (_ssl.c:997)

The MongoDB Server logs might also show the following error:


2021-06-30T21:22:44.917+0100 E NETWORK  [conn16] SSL: error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher

Changes made to the ssl module in Python v3.10 might cause incompatibilities with MongoDB versions earlier than v4.0. To resolve this issue, try one or more of the following steps:

When using OpenSSL v3 or later, you might see an error similar to the following message:


[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled

These types of errors occur because of outdated or buggy SSL proxies that mistakenly enforce legacy TLS renegotiation.

To resolve this issue, perform the following steps:

Run the following command to ensure that you have OpenSSL vv3.0.4 or later installed:

Create a configuration file that includes theUnsafeLegacyServerConnect option. The following example shows how to set the UnsafeLegacyServerConnect option:


openssl_conf = openssl_init

[openssl_init]

ssl_conf = ssl_sect

[ssl_sect]

system_default = system_default_sect

[system_default_sect]

Options = UnsafeLegacyServerConnect

Run Python while setting the OPENSSL_CONF environment variable to use the OpenSSL configuration file you just created:


OPENSSL_CONF=/path/to/the/config/file/above.cnf python ...

Important

Because setting the UnsafeLegacyServerConnect option hassecurity implications, use this workaround as a last resort to address unsafe legacy renegotiation disabled errors.

To learn more about configuring TLS for PyMongo, see the following API documentation: