如何在 Sidekiq 上为 Redis 6 启用 TLS?

ogi*_*inc 12 ruby ssl ruby-on-rails heroku redis

问题

在我的 Ruby on Rails 应用程序上,我不断收到以下有关Heroku Redis Premium 0 附加组件的错误:

OpenSSL::SSL::SSLError:SSL_connect 返回=1 errno=0 state=error:证书验证失败(证书链中的自签名证书)

Heroku Redis文档提到我需要在 Redis 客户端的配置中启用 TLS 才能连接到 Redis 6 数据库。为了实现这一点,我已经阅读了redis-rb上的 SSL/TLS 支持文档。我的理解是;我需要分配ca_file,certkeyRedis.new#ssl_params. 问题是如何为 Redis 或通过 Heroku 上的 Sidekiq 设置这些?

更新

更新 3:Heroku 支持提供了解决问题的答案。

更新 2:创建 Heroku 支持票和等待响应。

更新 1:询问Sidekiq 的 Github 问题,并被建议去写 Heroku 支持。当我得到答案时,会更新这个问题。


相关信息

我已经验证了当附加组件是以下任一情况时,该应用程序确实可以工作:

  • Redis 6 的业余爱好开发
  • Redis 5 的溢价 0

版本:

  • 红宝石 – 3.0.0p0
  • Ruby on Rails – 6.1.1
  • Redis – 6.0
  • redis-rb – 4.2.5
  • Sidekiq – 6.2.1
  • Heroku 堆栈 – 20

一些帮助我缩小问题范围的链接:

ogi*_*inc 16

解决方案

使用OpenSSL::SSL::VERIFY_NONE您的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
Run Code Online (Sandbox Code Playgroud)

Redis

Redis.new(url: 'url', driver: :ruby, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
Run Code Online (Sandbox Code Playgroud)

原因

Redis 6 需要 TLS 才能连接。但是,Heroku 支持解释说,他们管理从路由器级别到涉及自签名证书的应用程序级别的请求。事实证明,Heroku 在路由器级别终止 SSL,请求从那里通过 HTTP 转发到应用程序,而一切都在 Heroku 的防火墙和安全措施之后。


来源

  • 另请确保您的“redis”版本至少高于“4.0.2”。根据 Heroku 的说法,以下任何版本都会忽略 `OpenSSL::SSL::VERIFY_NONE`。这是我们使用旧版本的“resque”和旧的 resque 插件版本的情况。请参阅:https://devcenter.heroku.com/articles/securing-heroku-redis#connecting-directly-to-stunnel。“此方法仅适用于 `redis` gem `4.0.2` 及更高版本。`4.0.1` 及以下版本忽略 `OpenSSL::SSL::VERIFY_NONE` 作为验证模式,因此不能用于连接原生通过 SSL 到 Heroku Redis。” (4认同)
  • 有用! (2认同)
  • 您也可以将第二部分放入 config/environment/development.rb 中。例如: `config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'], expires_in: 1.hour, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }` (2认同)

Boo*_*age 9

如果您使用 ActionCable,您可能还需要添加verify_mode到 `cable.yml 配置:

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: my_app_production
  ssl_params:
    verify_mode: <%= OpenSSL::SSL::VERIFY_NONE %>
Run Code Online (Sandbox Code Playgroud)

来源: https: //github.com/chatwoot/chatwoot/issues/2420


Dan*_*der 7

如果您使用的是 Rails 5,您将无法ssl_params通过该文件为 ActionCable配置Redis cable.yml。相反,您可以在初始值设定项中手动设置redis_connector属性,如下所示:

# frozen_string_literal: true

require "action_cable/subscription_adapter/redis"

ActionCable::SubscriptionAdapter::Redis.redis_connector = ->(_config) do
  Redis.new(...your options here...)
end
Run Code Online (Sandbox Code Playgroud)

有关使用含义的更多背景信息OpenSSL::SSL::VERIFY_NONE 以及为什么如果您使用 Heroku,它可能没问题:

usingOpenSSL::SSL::VERIFY_NONE告诉客户端可以使用自签名证书,不会尝试验证该证书是否由已知的证书颁发机构签名。

存在的风险是存在中间人攻击的可能性。如果尝试与 Heroku Redis 通信的客户端未验证其遇到的 SSL 证书是否已知属于 Heroku(又名,这些证书由已验证请求证书的实体实际上是 Heroku 的证书颁发机构签名) ),那么位于您的客户端和 Heroku Redis 之间的攻击者就可以创建自己的自签名 SSL 证书并冒充 Heroku。这意味着他们可能会拦截您尝试发送到 Heroku Redis 的任何流量。

在实践中,对于 Heroku dyno 与 Heroku Redis 对话来说,这可能不是一个现实的场景。

以下是来自 Heroku 支持的引用:

MITM 攻击对于托管提供商来说是不切实际的。对于不良行为者来说,很难在 dyno 和 AWS 上托管的 Redis 实例之间进行攻击。这是因为同一可用区中的 EC2 实例在任何时候都不应该路由到 AWS 基础设施之外。在这种情况下,中间人攻击只能由托管服务提供商设施本身内的不良行为者执行,因为网络流量永远不会离开所述设施。

以下是 AWS 文档中的一些片段,似乎证实了这一点:

https://aws.amazon.com/vpc/faqs/

问:当两个实例使用公共 IP 地址进行通信时,或者当实例与公共 AWS 服务终端节点进行通信时,流量是否会通过 Internet 传输?

不会。使用公共地址空间时,AWS 中托管的实例和服务之间的所有通信都使用 AWS 的专用网络。源自 AWS 网络且目的地位于 AWS 网络的数据包将保留在 AWS 全球网络上,进出 AWS 中国区域的流量除外。

此外,流经连接我们的数据中心和区域的 AWS 全球网络的所有数据在离开我们的安全设施之前都会在物理层自动加密。还存在额外的加密层;例如,所有 VPC 跨区域对等流量以及客户或服务到服务传输层安全 (TLS) 连接。

以及https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-vpc.html

Amazon Virtual Private Cloud (Amazon VPC) 使您能够在 AWS 云内您自己的逻辑隔离区域中定义虚拟网络,称为虚拟私有云 (VPC)。

当您创建 AWS 账户时,我们会在每个区域为您创建一个默认 VPC