ServerSelectionTimeoutError when connecting to aws with pymongo - python

I am attempting to connect to MongoDB hosted on an AWS instance with a key file. I am able to ssh into the instance and connect to the database with no issues. When I try to connect to the database from a remote location with pymongo I receive this error:
ServerSelectionTimeoutError: SSL handshake failed: EOF occurred in violation of protocol
Port 27017 is open and the source is set to 0.0.0.0/0.
from pymongo import MongoClient
client = MongoClient('mongodb://ec2-123-45-678-910.compute-1.amazonaws.com',
27017,
ssl=True,
ssl_keyfile='/path_to/mykey.pem')
db = client.test
coll = db.foo
coll.insert_many(records)
ServerSelectionTimeoutError: SSL handshake failed: EOF occurred in violation of protocol (_ssl.c:645)
This question is nearly identical to mine, however the error is different and the solution posted there does not apply to my issue.
The address and key here have been changed, I have been going in circles on this for hours with no luck, any help would be appreciated.

This issue can cause because of following issue:
version of pymongo (suggest to use 3.3.0, which worked for me)
It can be a DNS issue, etc, in fact you could check for a DNS issue using:
telnet xx.xx.xx.xx port
can be a firewall issue
Can be an issue with ssl key. Try the following to test:
import os
import pymongo
import ssl
URL="url:port/db?ssl=true"
client = pymongo.MongoClient(URL, ssl_cert_reqs=ssl.CERT_NONE)
db = client.get_default_database()
print db
print db.collection_names()

I had the same problem (SSL handshake) with Pymongo module to connect to DocumentDB Azure (Data Base).
The error :
ServerSelectionTimeoutError: SSL handshake failed: EOF occurred in violation of protocol (_ssl.c:590)
I was using pymongo==3.4.0
To resolve this :
Change the version of pymongo by installing the 3.3.0 version
pip install pymongo==3.3.0
Try:
import pymongo
pymongo.__version__

For me, the problem was that my Python setup only supported TLS 1.0 – not TLS 1.1 or above.
You can check it like this:
Python 3
> from urllib.request import urlopen
> urlopen('https://www.howsmyssl.com/a/check').read()
Python 2
> from urllib2 import urlopen
> urlopen('https://www.howsmyssl.com/a/check').read()
Check the output for the key tls_version. If it says TLS 1.0 and not TLS 1.1 or TLS 1.2 that could be the problem.
If you're using a virtualenv, be sure to run the command inside.
Solution: Install Python with a newer version of OpenSSL
In order support TLS 1.1 or above, you may need to install a newer version of OpenSSL, and install Python again afterwards. This should give you a Python that supports TLS 1.1.
The process depends on your operating system – here's a guide for OS X.
virtualenv users
For me, the Python outside of my virtualenv had TLS 1.2 support, so just I removed my old virtualenv, and created a new one with the same packages and then it worked. Easy peasy!
See also:
The warning about TLS 1.0 in the Python 3 section in the PyMongo documenation. Although it's under the Python 3 section it also applies to Python 2

I had the same issue and talked for 30 minutes with the Mongo Atlas support which deployed over AWS. I run the next terminal command:
/Applications/Python\ 3.6/Install\ Certificates.command

I had the same issue. Please check if you are connected via VPN. when I disconnected it resolved my problem.

Related

Pymongo unable to read Certificate Authority file

I am trying to setup TLS encrypted connections to MongoDB database using PyMongo. I have 2 python binaries installation at 2 different locations. But, both have version: 3.6.8. For both of them I have installed PyMongo version: 4.1.1. Have completed the process for generating CA keys and server private keys. I then added the ca.pem to '/etc/pki/ca-trust/source/anchors/' and ran 'sudo update-ca-trust' to add the certificate authority in the operating system certificate store. Then, updated the mongod.conf file and restarted the mongod instance. I am able to connect to the mongo shell using this command
mongo --tls --host='server-host-name'
But, the main issue is I am able to connect to the database using one python package, but the other gives this error:
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)
error=AutoReconnect('SSL handshake failed:....)]
The output of the below command is:
openssl version -d
OPENSSLDIR: "/etc/pki/tls"
One workaround to make the other python binary also work was to explicitly export the path in the environment variable
export SSL_CERT_FILE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
But, I want the other python binary to also look for the CAs in the appropriate directory automatically.
All these tests are performed locally and not through some remote connections (which would require the certificate paths to be specified explicitly). I wanted to know the internal working of pymongo.MongoClient specifically for TLS connections in detail. Basically, I wanted some understanding how does it fetch the CAFiles from the operating system certificate store.
Also, how do I increase the logging for pymongo, any workaround for this? Can someone help me debug this? I can add additional information if required. Thank you.

Python celery connect through ssl

I have been trying to connect to a RabbitMQ (it was created from AWS Messaging Service if it matters) instance via celery 5.0.5. The connection link starts as follows amqps://user:password#..../. I receive the following error when running my python script:
consumer: Cannot connect to amqps://sessionstackadmin:**#b-0482d011-0cca-40bd-968e-c19d6c85e2a9.mq.eu-central-1.amazonaws.com:5671//: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
I am running the script from a docker container with python 3.6.12. The docker container has access to the endpoint (at least it can telnet to it). I have the feeling that the python process does not respect the distro certificate chain and it just fails verifying the certificate.
I solved it! Celery is using Kombu, which is using py-amqp and it happens that the latest version 5.0.3 from Jan 19 is broken.
My GH ticket https://github.com/celery/py-amqp/issues/349
Solution: add amqp==5.0.2 as a hard dependency in your project requirements.
Fix at: git+git://github.com/celery/py-amqp.git#0b8a832d32179d33152d886acd6f081f25ea4bf2
I am leaving the workaround that "fixes" this. For some reason the kombu library when trying to handle ssl connections does not respect the default CA certs coming with your distribution. This is basically handled by https://docs.python.org/3/library/ssl.html#ssl.create_default_context which the library does not use. Sadly it does not allow to pass in a custom SSLContext but only a set of options that will be later passed down to the context. One such options is broker_use_ssl. By settings it to {'ca_certs': '/etc/ssl/certs/ca-certificates.crt'} it will respect the CA certs from the distribution (keep in mind that I am using an ubuntu/debian based image and the CA certs configuration file resides there, if you are using another distro check out the proper location for your CA certs).

Python requests: Passing multiple client certificates to session.cert

I'm writting a Flask app that connects to external soap service that uses TLS v1.2.
I'm using Python 2.7 and requests library in version 2.18.1.
I've contacted server owner and he told me that I need to include multiple client certificates in TLS connection. It's a chain of 3 certificates which I have in separate .pem files. (root + indermediate + my client certificate).
Server won't let me in if I would have just the last one.
I've tested this with SoapUI and Wireshark and it's true. I receive a response only when I provide the whole chain of 3 certificates.
I get an error from the server when passing just my client certificate.
From requests documentation you can read that as client certificate you can pass just one cert using:
session = requests.session()
session.cert = ('/path/client_cert.pem', '/path/private_key.pem')
response = session.post(SERVICE_URL, data=XML_CONTENT, headers=HEADERS)
I get an error even if my "client_cert.pem" file is a bundle of 3 certificates (just like you do it in session.verify with CA certs). I can see on Wireshark that only the first one is used in TLS connection.
Is there any way to include multiple certificates TLS connection in Python's requests library?
Maybe I should use different library or override some of it's code?
I've got it!
I had some legacy library versions installed.
It seems that this issue was fixed by requests library developers in version 1.23. I also had to update urllib3.
My current requirements.txt is:
requests==2.22.0
urllib3==1.25.2 # compatible with requests 2.22
For following spec everything works perfecly. I've checked TLS connection on Wireshark. All certificates from "client_cert.pem" chain are passed.
If you'll have problems like this in the future remember to check if your requests and urllib3 library versions are compatible.
Thank you guys!

Windows Authentication Frequently Failing with pymssql

I am having a problem where Windows Authentication has almost completed stopped working for pymssql 2.1.3. It was working last week, but now when I try and use my AD login, it fails almost every time with the error (20009, b'DB-Lib error message 20002, severity 9:\nAdaptive Server connection failed (878240-SQLdb4:1433)\n'), though it does manage to succeed about 1 in every 100 attempts. I have Sql Server Management Studios installed on the server where my Python code is running from, and Windows Authentication appears to be working fine. I checked the sql log for failed logins and I couldn't see any attempts.
Here is my code:
import pymssql
conn = pymssql.connection(server='myserver',database='database1')
Any ideas to make it connect consistently?
*Edit: It appears to work more consistently if it is the first time I have tried logging in after a few minutes.
So I just had to switch to pyodbc which has better support for Windows authentication. Keep in mind that the latest release of pyodbc (4.0.21) does not support Python 3.6, so you need to use 3.5. Apparently there is a wheel for python 3.6, but I haven't tested it and it appears pip is unable to natively install it on Windows. I also had to change a few things such as the connection string and how stored procedures are called (pyodbc does not have the callproc function). Here is my connection string now:
import pyodbc
conn = pyodbc.connect(server='server',database='database',Trusted_Connection='yes', driver = '{ODBC Driver 13 for SQL Server}')

urllib.request SSL Connection Python 3

I'm trying to parse the data from this url:
https://www.chemeo.com/search?q=show%3Ahfus+tf%3A275%3B283
But I think this is failing because the website uses SSL TLS 1.3. How can I enable my Python script, below, to connect using SSL in urllib.request?
I've tried using an SSL context but this doesn't seem to work.
This is the Python 3.6 code I have:
import urllib.request
import ssl
from bs4 import BeautifulSoup
scontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
chemeo_search_url = "https://www.chemeo.com/search?q=show%3Ahfus+tf%3A275%3B283"
print(chemeo_search_url)
with urllib.request.urlopen(chemeo_search_url, context=scontext) as f:
print(f.read(200))
Try:
ssl.PROTOCOL_TLS
From the docs on "PROTOCOL_SSLv23":
Deprecated since version 2.7.13: Use PROTOCOL_TLS instead.
note:
Be sure to have the CA certificate bundles installed, like on a minimal build of alpine linux, busybox, the certs have to be installed. Also sometimes if python wasn't compiled with SSL support, it might be necessary to to do so. Also depending on which version of OpenSSL has been compiled will determine which features for SSL will be usable.
Also note chemeo site doesn't use TLSv1.3 ... it is still experimental and not all that secure at the time of this writing, they currently support tls 1.0, 1.1, 1.2 using "letsencrypt" as their cert provider.

Categories