SSL Certification Verify Failed on Heroku Redis
Asked Answered
L

8

11

I'm deploying a flask app on Heroku using a Redis premium plan. I get the following error: 'SSL Certification Verify Failed'. Attempted fixes:

  • Downgrading to Redis 5
  • Passing ssl_cert_reqs=None to the Redis constructor in redis-py

A solution to this problem could be:

  1. Explain how to disable TLS certification on heroku redis premium plans
  2. Explain how to make TLS certification work on heroku redis premium plans

From Heroku's docs, this may be a hint: 'you must enable TLS in your Redis client’s configuration in order to connect to a Redis 6 database'. I don't understand what this means.

Limp answered 27/11, 2020 at 18:59 Comment(0)
G
9

I solved my problem by adding ?ssl_cert_reqs=CERT_NONE to the end of REDIS_URL in my Heroku config.

Glume answered 6/12, 2021 at 11:44 Comment(4)
this is the wayGrimaldi
This worked for me when I set it specifically to ?ssl_cert_reqs=none (CERT_NONE raised an "invalid flag" error)Dour
This won't stay if you are using Heroku Data for Redis or another addon since the environment variable is managed by Heroku.Hardbitten
@Hardbitten Is correct. The workaround I applied for this was to leave the Heroku environment variables untouched and append ?ssl_cert_reqs=none to the Redis URL in the Flask config.py file instead.Liederman
H
6

The docs are actually incorrect, you have to set SSL to verify_none because TLS happens automatically.

From Heroku support:

"Our data infrastructure uses self-signed certificates so certificates can be cycled regularly... you need to set the verify_mode configuration variable to OpenSSL::SSL::VERIFY_NONE"

I solved this by setting the ssl_params to verify_none:

ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }

For me it was where I config redis (in a sidekiq initializer):

# config/initializers/sidekiq.rb
Sidekiq.configure_client do |config|
  config.redis = { url: ENV['REDIS_URL'], size: 1, network_timeout: 5, 
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
end

Sidekiq.configure_server do |config|
  config.redis = { url: ENV['REDIS_URL'], size: 7, network_timeout: 5, 
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
end
Horal answered 5/1, 2021 at 14:30 Comment(5)
Can you please explain what a sidekiq initializer is and how it relates to a flask app?Limp
Sidekiq is a background processing gem, since it connects with redis I set the SSL config there to fix the same error you got. You can probably do the same (verify_none SSL) wherever you're configuring redis.Lilongwe
@Joe'sIdeas can you provide a link for the Heroku support quote, please? I couldn't find it anywhere :/ (I have a related issue: #65835075)Disseisin
@Disseisin there isn't a link, that was from a conversation with support, looks like the verify none worked for you though, nice 👍Lilongwe
@Joe'sIdeas yep! Thank you :)Disseisin
L
5

You can disable TLS certification on Heroku by downgrading to Redis 5 and passing ssl_cert_reqs=None to the Redis constructor.

$ heroku addons:create heroku-redis:premium-0 --version 5
from redis import ConnectionPool, Redis
import os
connection_pool = ConnectionPool.from_url(os.environ.get('REDIS_URL'))
app.redis = Redis(connection_pool=connection_pool, ssl_cert_reqs=None)

My mistake was not doing both at the same time.

An ideal solution would explain how to configure TLS certification for Redis 6.

Limp answered 27/11, 2020 at 22:37 Comment(0)
V
2

If using the django-rq wrapper and trying to deal with this, be sure to not use the URL parameter with SSL_CERTS_REQS. There is an outstanding issue that describes this all, but basically you need to specify each connection param instead of using the URL.

Verdieverdigris answered 5/9, 2021 at 1:46 Comment(1)
Thanks, I was facing the same issue in django-rq and your solution helped!Pivot
S
2

On Heroku (assuming Heroku Redis addon), the redis TLS route already has the ssl_cert_reqs param sorted out. A common oversight that can cause errors in cases like this on heroku is: using REDIS_URL over REDIS_TLS_URL.

Solution:

redis_url = os.environ.get('REDIS_TLS_URL')

Soniferous answered 19/5, 2022 at 19:53 Comment(1)
This works for "Mini Heroku Data for Redis" only, not the "Premium" one.Felix
G
2

I ran into difficulty on this but finally got it resolved...

A lot of documentation and posts on this topic are unclear. I've requested Heroku update their documentation on https://devcenter.heroku.com/articles/connecting-heroku-redis#connecting-in-python to include a specific change to the Procfile.

It's sort of mentioned above but refers to "Heroku config" instead of the Procfile specifically.

In your Procfile add ?ssl_cert_reqs=none to $REDIS_URL.

e.g.:

web: gunicorn webapp:app
worker: rq worker -u $REDIS_URL?ssl_cert_reqs=none queue

Don't update REDIS_URL directly as Heroku cycle this from time to time.

I also updated the Redis setup as per the original documentation:

url = urlparse(os.environ.get("REDIS_URL"))
r = redis.Redis(host=url.hostname, port=url.port, password=url.password, ssl=True, ssl_cert_reqs=None)

But it was the change to the Procfile that finally got Redis v6.2.11 with TLS working correctly for me.

Guerrilla answered 14/3, 2023 at 18:3 Comment(0)
U
1

This solution works with redis 6 and python on Heroku

import os, redis

redis_url = os.getenv('REDIS_URL')
redis_store = redis.from_url(redis_url, ssl_cert_reqs=None)

In my local development environment I do not use redis with the rediss scheme, so I use a function like this to allow work in both cases:

def get_redis_store():
    '''
    Get a connection pool to redis based on the url configured
    on env variable REDIS_URL

    Returns
    -------
    redis.ConnectionPool
    '''
    redis_url = os.getenv('REDIS_URL')
    if redis_url.startswith('rediss://'):
        redis_store = redis.from_url(
            redis_url, ssl_cert_reqs=None)
    else:
        redis_store = redis.from_url(redis_url)
    return redis_store
Uninterrupted answered 25/8, 2021 at 20:27 Comment(1)
Hey @GonzaloOdiard, Thanks a lot man! You just saved a lot of my time. I have been wondering why is it not working, it was connecting with RedisInsight with TLS true, but wasn't getting integrated with python. I tried installing OpenSSL Certificates as well.Oler
F
0

Solution works for nodejs16 and redis client 4.6.x

redisClient = redis.createClient({
            url: process.env.REDIS_URL,
            socket: {
                tls: true,
                rejectUnauthorized: false
            })
Fictionalize answered 13/3, 2023 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.