Getting SSLCertVerificationError, but CURL is working - python

I'm trying to replicate a CURL command using aiohttp in Python.
curl -k -X POST https://XXXXXXXXXXXXXXX.com \
--cert file.cer:pass \
--key file.key \
-u "XXXXXXXXXXX:XXXXXXXXXXX" \
-d "username=XXXXXXXXXXX" \
-d "password=XXXXXXXXXXX" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic XXXXXXXXXXX"
That works fine.
Reading the docs here, https://docs.aiohttp.org/en/stable/client_advanced.html#ssl-control-for-tcp-sockets, I create a SSL Context like so, using Python's ssl module:
import ssl
ssl_context = ssl.create_default_context()
ssl_context.load_cert_chain(
certfile=CERT_PATH,
keyfile=KEY_PATH,
password=KEY_PASS
)
Then, with aiohttp when executing a request:
async with session.post(url,json=body,ssl=ssl_context) as r:
...
And I get this:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)
Any ideas why?

Update:
Solved this by following the answer here: How can I create a Python SSL Client/Server pair where only the server authenticates the client
Basically replaced ssl.create_default_context() with ssl.SSLContext()
Only thing is that now I get a warning:
DeprecationWarning: ssl.SSLContext() without protocol argument is deprecated.
DeprecationWarning: ssl.PROTOCOL_TLS is deprecated
But that is a problem for another day. I'm open to hear more suggestions, tho.

Related

How to solve SSL - certificate verify failed exception while pact verification, service provider against broker (https broker) using pact-python lib

Facing below error while communicating with https pact broker url, using pact-python lib for contract verification test against broker.
Conn close because of connect error SSL_connect returned=1 errno=0 state=error: certificate verify failed.
I have already installed required certificates on container (Docker environment) where the code is running.
Below is the sample code:
broker_opts():
return {
"broker_url": "https://ebpact01.devlab2k.testnet.rim.net:443",
"publish_verification_results": True
}
def test_user_service_provider_against_broker(server, broker_opts):
verifier = Verifier(provider="user#provider", provider_base_url=PROVIDER_URL)
success, logs = verifier.verify_with_broker(
**broker_opts,
verbose=True,
provider_states_setup_url=f"{PROVIDER_URL}/_pact/provider_states",
enable_pending=False,
)
assert success == 0
Sample Docker file :
FROM python:3.7-slim-buster
COPY ./ .
RUN pwd
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN apt-get update \
&& apt-get install openssl \
&& apt-get install ca-certificates
#Add certificate required to access broker
ADD 'http://certificate-url/Root-CA-1.crt' $capath/broker-root-ca1.crt
RUN update-ca-certificates
RUN export SSL_CERT_DIR=/etc/ssl/certs
RUN export SSL_CERT_FILE=/etc/ssl/certs/broker-root-ca1.crt
#invokes pytest.main method
CMD ["python3", "./test/invoke_pact_test.py"]
Sample Docker compose file :
pactverify:
build:
context: ../../
dockerfile: deploy/docker/dockerfile-pact
image: app-pact:$CI_COMMIT_SHORT_SHA
environment:
- PACT_BROKER=$PACT_BROKER
Stack trace :
Error making request - OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=error: certificate verify failed , attempt 1 of 3
Error making request - OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=error: certificate verify failed , attempt 2 of 3
Error making request - OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=error: certificate verify failed , attempt 3 of 3
/usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/net/http.rb:923:in connect': SSL_connect returned=1 errno=0 state=error: certificate verify failed (OpenSSL::SSL::SSLError) from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/net/http.rb:923:in block in connect'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/timeout.rb:74:in timeout' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/net/http.rb:923:in connect'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/net/http.rb:863:in do_start' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/ruby/lib/ruby/2.2.0/net/http.rb:852:in start'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/hal/http_client.rb:62:in block in perform_request' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/retry.rb:23:in until_true'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/hal/http_client.rb:50:in perform_request' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/hal/http_client.rb:25:in get'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/hal/link.rb:49:in get' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb:57:in index'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb:42:in call' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/pact_broker/fetch_pact_uris_for_verification.rb:38:in call'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-1.62.0/lib/pact/pact_broker.rb:18:in fetch_pact_uris_for_verification' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/aggregate_pact_configs.rb:46:in pacts_for_verification'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/aggregate_pact_configs.rb:39:in pacts_urls_from_broker' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/aggregate_pact_configs.rb:26:in call'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/aggregate_pact_configs.rb:10:in call' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/app.rb:211:in all_pact_urls'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/app.rb:225:in warn_empty_pact_set' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/app.rb:40:in call'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/app.rb:35:in call' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/cli/verify.rb:49:in verify'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/thor-1.2.1/lib/thor/command.rb:27:in run' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in invoke_command'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/thor-1.2.1/lib/thor.rb:392:in dispatch' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/thor-1.2.1/lib/thor/base.rb:485:in start'
from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/vendor/ruby/2.2.0/gems/pact-provider-verifier-1.36.1/lib/pact/provider_verifier/cli/custom_thor.rb:17:in start' from /usr/local/lib/python3.7/site-packages/pact/bin/pact/lib/app/pact-provider-verifier.rb:33:in '
opening connection to broker.url:443 ...
opened
starting SSL for broker.url:443 ...
SSL established
Conn close because of connect error SSL_connect returned=1 errno=0 state=error: certificate verify failed
opening connection to broker.url:443 ...
opened
starting SSL for broker.url:443 ...
SSL established
Conn close because of connect error SSL_connect returned=1 errno=0 state=error: certificate verify failed
opening connection to broker.url:443 ...
opened
starting SSL for broker.url:443 ...
SSL established
Conn close because of connect error SSL_connect returned=1 errno=0 state=error: certificate verify failed
Is your self signed certificate?
I would advise reading the below
https://docs.pact.io/pact_broker/advanced_topics/using-tls#connecting-to-a-pact-broker-running-over-tls
and raising an issue on the repo, as well as a repo as a sample.
We hang out over at https://slack.pact.io
Does it work if you disable ssl on the verifier?

can connect to URL with curl but not with requests (i.e. requests ignoring my CA bundle?)

I am able to connect to a certain URL with cURL, after I installed the corresponding SSL certificates:
$ export MY_URL=https://www.infosubvenciones.es/bdnstrans/GE/es/convocatoria/616783
$ curl -vvvv $MY_URL # Fails
$ sudo openssl x509 -inform pem -outform pem -in /tmp/custom-cert.pem -out /usr/local/share/ca-certificates/custom-cert.crt
$ sudo update-ca-certificates
$ curl -vvvv $MY_URL # OK
However, requests (or httpx, or any other library I use) refuses to do so:
In [1]: import os
...: import requests
...: requests.get(os.environ["MY_URL"])
---------------------------------------------------------------------------
SSLCertVerificationError Traceback (most recent call last)
...
SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)
My understanding is that requests uses certifi and as such these custom certificates are not available here:
In [1]: import certifi
In [2]: certifi.where()
Out[2]: '/tmp/test_ca/.venv/lib/python3.10/site-packages/certifi/cacert.pem'
I have already tried a number of things, like trying to use the system CA bundle:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt same error
requests.get(..., verify="/etc/ssl/certs/ca-certificates.crt") same error
switched to httpx + a custom SSL context as explained in the docs, same error
attempted truststore as discussed in this httpx issue, same error
How can I make Python (requests, httpx, raw ssl, anything) use the same certificates that cURL is successfully using?
The only thing that worked so far, inspired by this hackish SO answer, is to do verify=False. But I don't want to do that.
In [9]: requests.get(
...: my_url,
...: verify=False,
...: )
/tmp/test_ca/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1043: InsecureRequestWarning: Unverified HTTPS request is being made to host 'xxx'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
i tried your stuff on my system (Manjaro Linux, python 3.10) i can make a connection. I downloaded the complete certificate chain from the website (with my browser). After that i can use it with:
r = requests.get(url=URL, verify=<path to pem file>)
and with
export REQUESTS_CA_BUNDLE=<path to pem>
r = requests.get(url=URL)
I tried the export within pyCharm.
So the python stuff is working and you may have a problem in your certificates. Without this stuff i get the ssl error (of course), because python does not use the system certs as you mentioned correct. In my pem-file i have 3 certificates. Maybe you have only 1 and the others are in the global store, so that curl does not need the complete chain, instead of python. You should try to download the complete chain with your browser and try again.

FastAPI (Python) Why I get "Unsupported upgrade request." with POST request?

I have similar apps on Flask and FastAPI.
When I do this curl requests with Flask, that is all right:
Without TLS:
curl -X POST -H "Content-Type: application/json" -d '{"method": "account.auth"}' http://X.X.X.X:5050/
{"error":0,"result":{"token":"XXX"}}
With TLS:
curl -X POST -H "Content-Type: application/json" -d '{"method": "account.auth"}' https://example.com:8443/api/
{"error":0,"result":{"token":"XXX"}}
!!! But with FastAPI I get another result:
Without TLS:
curl -X POST -H "Content-Type: application/json" -d '{"method": "account.auth"}' http://X.X.X.X:5050/
{"error":0,"result":{"token":"XXX"}}
With TLS:
curl -X POST -H "Content-Type: application/json" -d '{"method": "account.auth"}' https://example.com:8443/api/
Unsupported upgrade request.
How to fix problem with "Unsupported upgrade request."? And what is it? Flask are working with it normally.
This same issue usually seems to arise from incomplete uvicorn installations, but is usually related to websockets.
A solution for this issue might be to reinstall uvicorn with the recommended (by FastAPI) extras:
python3 -m pip uninstall uvicorn
python3 -m pip install uvicorn[standard]
I had this problem using java to access the api. The solution was to set HTTP Request to 1.1
var httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://127.0.0.1:8000/jobs"))
.version(HttpClient.Version.HTTP_1_1)
.GET()
.build();

Vault returns CERTIFICATE_VERIFY_ERROR when authenticating with tls

I am newbie to vault and currently trying to enable client tls authentication (all on the only CentOS 7 node) via self-signed certificates.
Of course, first of all i ran: vault auth-enable cert
Then, I created a policy.hcl file with such contents:
path "secret/policy/test/foo" {policy="read"}
Then I did the following:
$ vault policy-write test policy.hcl
$ vault write "secret/policy/test/foo" vaule=s3cr3t policy=test
Generate client certificate:
$ openssl genrsa -out client.key 2048
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -in client.csr -signkey client.key -out client.crt
And the final action:
$ vault write auth/cert/certs/test display_name=test policies=test certificate=#/home/vagrant/ssl/client.crt
And it all execute without any errors or warnings. Then, i wrote a simple script which must read just a one value after authentication with TLS:
import os
import hvac
client = hvac.Client(url='https://127.0.0.1:8200', cert=('client.crt', 'client.key'))
print(client.read('secret/policy/test/foo'))
But when I run it I get the following error:
requests.exceptions.SSLError: HTTPSConnectionPool(host='127.0.0.1', port=8200): Max retries exceeded with url: /v1/secret/policy/test/foo (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),))
Server log says:
http: TLS handshake error from 127.0.0.1:33744: remote error: tls: unknown certificate authority
Any help is highly appreciated
EDIT:
to clarify what the actual problem is, I'd like to mention that when i authenticate to the Vault using CLI:
$ vault auth -method=cert -client-cert=client.crt -client-key=client.key
# returns:
The token below is already saved in the session. You do not
need to "vault auth" again with the token.
token: 8afdb5bd-b6f1-e33e-a391-ced99fa18b5f
token_duration: 2764800
token_policies: [default test]
... it seems to be working just fine cuz the policy I've created is being attached and I can read the data from secret/policy/test/foo, but Python+HVAC approach does not work.

Curl command in Requests Python

I am trying write a python equivalent script for the cURLcommand below using Requests library. I am not able to find relevant flags to disable SSL verification and set no proxy.
curl -v -k -T debug.zip https://url-to-no-ssl-server/index.aspx --noproxy url-to-no-ssl-server -X POST -H "filename: debug.zip"
How do I convert this command to python-requests?
This SO Answer shows how to disable proxies:
session = requests.Session()
session.trust_env = False
The documentation for requests has disabling SSL verification:
Requests can also ignore verifying the SSL certificate if you set verify to False:
requests.get('https://kennethreitz.com', verify=False)
<Response [200]>
By default, verify is set to True. Option verify only applies to host certs.

Categories