Heroku Redisをアップグレードするとコネクションエラーになる件

Heroku RedisをHobby devプランからPremium0にアップグレードすると、コネクションエラーになる事象があったのでメモです。

再現手順

  • Heroku RedisのHobby DevプランからPremium0にアップグレードする
  • Redisを使った処理を走らせてみる(Sidekiqなど)

Heroku Redis - Add-ons - Heroku Elements

エラーログ

in `connect_nonblock': SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain) (OpenSSL::SSL::SSLError)

原因

HobbyプランではTLSと非暗号化接続両方をサポートしているが、プロダクションプラン(Premiumなど)ではTLS接続が必要。プレミアムプランではRedis6に接続するために、クライアント側でTLSを有効化する必要がある。

Herokuは内部的にはルーターのレイヤーでSSLターミネーションをして、HTTPでアプリケーションにリクエストを転送する。

インバウンドリクエストは、SSL ターミネーションを提供するロードバランサーによって受信されます。リクエストは、ここから一連のルータに直接渡されます。 ルーターは、アプリケーションの Web ​dyno​ の場所を判断し、これらの dyno のいずれかに HTTP リクエストを転送する役割を担います。

対処

SidekiqでRedisを使用しているので下記の設定を追加する。

# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
end

Sidekiq.configure_client do |config|
  config.redis = { ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
end

ここでconfig.redis=のハッシュ設定値は、Sidekiqの処理の中でRedis.newするときのパラメータとして渡る。redis-rbのコードを読むと、ssl_paramsOpenSSL::SSL::SSLContext.newのオブジェクトのパラメータとしてセットされている。

def self.connect(host, port, timeout, ssl_params)
  # Note: this is using Redis::Connection::TCPSocket
  tcp_sock = TCPSocket.connect(host, port, timeout)

  ctx = OpenSSL::SSL::SSLContext.new

  # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
  ctx.set_params(ssl_params || {})
  # ...
end

https://github.com/redis/redis-rb/blob/506f9228cc106d1364040a73fb2366cf99e94207/lib/redis/connection/ruby.rb#L227

OpenSSL::SSL::SSLContext#verify_mode=のドキュメントがここ。 OpenSSL::SSL::SSLContext#verify_mode= (Ruby 3.0.0 リファレンスマニュアル)

OpenSSL::SSL::VERIFY_NONEの設定はサーバーモードでは証明書を要求せず、クライアントモードでは証明書を検証するが失敗してもハンドシェイクを継続するとのこと。

OpenSSL::SSL::VERIFY_NONE (Ruby 3.0.0 リファレンスマニュアル)

まとめるとRedis6、HerokuであればPremiumプラン以上ではTLS接続が必須であるが、Heroku内部ではSSL認証をルーターというレイヤでやるので、Redisとの接続のところでTLS接続されていない。

なのでRedis側の設定を変えることで対応をしている。という認識。

関連記事