Skip to content

[SSL: TLSV13_ALERT_CERTIFICATE_REQUIRED] exception when using self-signed certificates #2066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ZenulAbidin opened this issue Mar 27, 2022 · 6 comments

Comments

@ZenulAbidin
Copy link

ZenulAbidin commented Mar 27, 2022

Version: redis-py: 4.2.0, Redis: 6.2.6
Platform: Python 3.8.3 on Ubuntu 20.04

Description:
I have deployed Redis to my Kubernetes cluster using Helm and Bitnami's repository, with an autogenerated certificate. Specifically: helm install redis-test bitnami/redis --set image.debug=true --set tls.enabled=true --set tls.autoGenerated=true --set architecture=standalone

The redis server itself is in standalone mode and works fine and has a password and certificate, that's not the problem.

The problem is in the redis-py client which cannot connect to my Redis server using the self-signed certificate.

Here is a minimum reproducible example:

import redis
r = redis.StrictRedis(
    host='redactedentry.io', # <redacted>
    port=1234, # <redacted>
    password='<redacted>',
    ssl_cert_reqs=u'none',
    ssl=True)
r.info()

The ssl_cert_reqs is there to avoid [the SSL_CERTIFICE_VERIFY_FAILED] error in #1080.

Instead, I get another stack trace after executing r.info():

Traceback (most recent call last):
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 821, in read_response
    response = self._parser.read_response(disable_decoding=disable_decoding)
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 320, in read_response
    raw = self._buffer.readline()
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 251, in readline
    self._read_from_socket()
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 194, in _read_from_socket
    data = self._sock.recv(socket_read_size)
  File "/home/zenulabidin/anaconda3/lib/python3.8/ssl.py", line 1226, in recv
    return self.read(buflen)
  File "/home/zenulabidin/anaconda3/lib/python3.8/ssl.py", line 1101, in read
    return self._sslobj.read(len)
ssl.SSLError: [SSL: TLSV13_ALERT_CERTIFICATE_REQUIRED] tlsv13 alert certificate required (_ssl.c:2607)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/commands/core.py", line 900, in info
    return self.execute_command("INFO", **kwargs)
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/client.py", line 1192, in execute_command
    conn = self.connection or pool.get_connection(command_name, **options)
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 1386, in get_connection
    connection.connect()
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 626, in connect
    self.on_connect()
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 716, in on_connect
    auth_response = self.read_response()
  File "/home/zenulabidin/.local/lib/python3.8/site-packages/redis/connection.py", line 827, in read_response
    raise ConnectionError(f"Error while reading from {hosterr}" f" : {e.args}")
redis.exceptions.ConnectionError: Error while reading from redactedentry.io:1234 : (1, '[SSL: TLSV13_ALERT_CERTIFICATE_REQUIRED] tlsv13 alert certificate required (_ssl.c:2607)')

Here are the server logs as this exception is thrown:

08:00:12.991 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 27 Mar 2022 08:00:12.991 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 27 Mar 2022 08:00:12.991 # Configuration loaded
1:M 27 Mar 2022 08:00:12.991 * monotonic clock: POSIX clock_gettime
1:M 27 Mar 2022 08:00:12.992 * Running mode=standalone, port=6379.
1:M 27 Mar 2022 08:00:12.992 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 27 Mar 2022 08:00:12.992 # Server initialized
1:M 27 Mar 2022 08:00:12.992 * Ready to accept connections
1:M 27 Mar 2022 08:04:12.657 # Error accepting a client connection: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
# The last line repeats itself every time I attempt to make a Redis call

Barring extracting the certificate from the Kubernetes container (difficult but doable) to place inside the client, how can I bypass this exception?

@ZenulAbidin
Copy link
Author

ZenulAbidin commented Mar 27, 2022

A follow-up to my certificate-extraction "solution":

r = redis.StrictRedis(
    ...
    ssl_cert_reqs=u'none',
    ssl_ca_certs='./redis.crt', # This is the CA cert.
    ssl=True)

It looks like even that did not work - same exception as above. So I'm at a loss of ideas.

@chayim
Copy link
Contributor

chayim commented Mar 30, 2022

Hi @ZenulAbidin thanks for the issue report! Can I point you to the following, and see if they're right for you?

  1. Here's a unit test that handles self-signed certificates.
  2. Here is our example in the docs for doing this.

The latter is also available in the repository as a jupyter notebook in the examples folder

@ZenulAbidin
Copy link
Author

@chayim Hmm, I didn't see the ssl_certificate and ssl_keyfile parameters at first. I'll try passing them and see if things change.

I'll admit that I just read the README which didn't document those two. Maybe the example in the docs can be copied into the SSL section of the README as well.

@chayim
Copy link
Contributor

chayim commented Mar 30, 2022

Thanks for the feedback! I think we should generally revamp the readme, and link to our examples, docs and everything else Ina cleaner way.
In my mind, the readme should help to get people started with the library and point to resources that help them get going, keeping it small.
What do you think?

@ZenulAbidin
Copy link
Author

That's basically what I was thinking too. I can recommend two additional suggestions regarding the README on top of that.

  • The README is very long with many sections and I suspect most people aren't going to read through the whole thing. So it's better to list the most important package features as well as how to install, contribute etc. only.

The rest of the content can be broken down into additional files and placed in a folder called something like docs.

  • This depends on how old py-redis 2.X is, but in the same spirit as the above, those details should be moved into a file called Compatibility or something like that.

Probably if it's still recent then it would be inappropriate to move it out, but it should at least be close to the bottom of the README. It's currently at the beginning of the README which obscure smore basic documentation.

Being a big user of Redis and redis-py myself, I can make PRs for restructuring the README if you want.


Anyways, I managed to get this working by filling in the ssl_certfile, ssl_keyfile, and ssl_ca_certs with filenames whose content are PEM certs/keys I extracted from the Redis container's tls.crt, tls.key, and ca.crt respectively (Bitnami generates all three files in the same folder /opt/bitnami/redis/certs). My final initialization looked something like this:

import redis

# The following three variables point to file paths.
# I just put my certs and keys in the working dir and
# named them as below.
ssl_certfile="client.crt"
ssl_keyfile="client.key"
ssl_ca_certs="ca.crt"

# Can also use `Redis` in 3.x, they are identical
r = redis.StrictRedis(
    host='redactedentry.io', # <redacted>
    port=1234, # <redacted>
    password='<redacted>',
    ssl=True,
    ssl_certfile=ssl_certfile,
    ssl_keyfile=ssl_keyfile,
    ssl_cert_reqs="required",
    ssl_ca_certs=ssl_ca_certs)

# I can now ping it and run info() as usual.
r.ping()
# >>> True

Thanks for your help.

@chayim
Copy link
Contributor

chayim commented May 29, 2022

I'm so sorry, this is long since resolved, and I didn't link back here. The direct result of your ask is our SSL Connection Examples page , where we explicitly highlight this one.

Closing as a result.

@chayim chayim closed this as completed May 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants