SSL Certification Verify Failed on Heroku Redis

Viewed 5478

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.

6 Answers

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.

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

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

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

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.

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')

Related