Rails 生产在 AWS 负载均衡器中不起作用

Rails production not work in AWS load balancer

我的 Rails 6 应用程序在 EC2 实例中的开发模式下运行良好。但是当配置使用生产模式时。负载均衡器无法进行健康检查,也无法 运行 应用程序。

我的健康检查:

安全:负载均衡器

安全性:Rails 个应用程序

负载均衡器在开发中工作

此处使用负载均衡器进行开发

开始 rails:

rails s -p 3000 -b 0.0.0.0

然后回复

=> Booting Puma
=> Rails 6.0.3.2 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000

config/environments/development.rb

Rails.application.configure do
  config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
  config.cache_classes = false
  config.eager_load = false
  config.consider_all_requests_local = true
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
    config.action_controller.perform_caching = true
    config.action_controller.enable_fragment_cache_logging = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }
  else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
  end
  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.default_url_options = { :host => 'localhost:3000' }

  config.action_mailer.perform_caching = false
  config.active_support.deprecation = :log
  config.assets.debug = true
  config.assets.quiet = true
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end

下面是生产(不工作)

config/environments/production.rb

开始 rails:

RAILS_ENV=production rails s -p 3000 -b 0.0.0.0

然后回复:

=> Booting Puma
=> Rails 6.0.3.2 application starting in production 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: production
* Listening on tcp://0.0.0.0:3000


Rails.application.configure do
  config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" #This is public dns of load balance
  config.hosts << "3.14.65.84"
  config.cache_classes = true
  config.eager_load = true
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
  config.assets.compile = false
  config.log_level = :debug
  config.log_tags = [ :request_id ]
  config.action_mailer.perform_caching = false
  config.i18n.fallbacks = true
  config.active_support.deprecation = :notify
  config.log_formatter = ::Logger::Formatter.new
  if ENV["RAILS_LOG_TO_STDOUT"].present?
    logger           = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger    = ActiveSupport::TaggedLogging.new(logger)
  end
end

负载均衡器:健康检查不工作!

我也试过:

  1. 将config/environments/development.rb复制到production.rb然后运行作为生产环境结果=====> Health Check Not Work!
  2. 将config/environment/production.rb复制到development.rb然后运行作为开发环境结果=====> Health Check Work!

似乎与 rails 配置无关,但它在 AWS 中处理生产的方式

帮助:如何使这个 Rails6 在带有负载均衡器的 AWS EC2 中作为生产环境工作?

我认为如果您创建自己的应用程序健康检查路由,而不是 ping 到根路径会更好:

# controller
class HealthCheckController < ApplicationController
  def show
    render body: nil, status: 200
  end
end

# routes
get '/health_check', to: 'health_check#show'

然后将 LB 健康检查中的 ping 路径更新为 /health_check

编辑:

在生产配置文件中添加 config.hosts.clear 替换 config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" 以使 rails 接受请求

我的公司刚刚 运行 遇到了一个听起来非常相似的问题。一旦 ECS 启动任务,我们就可以通过 ELB 访问 Rails 应用程序,但是健康检查会失败,它会自动关闭它尝试启动的每个容器。

我们最终将 IP 运行ge 添加到主机配置中。在生产中完全禁用它感觉不对,所以我们得出了类似的结果:

config.hosts = [
  "publicdomain.com",
  "localhost",
  IPAddr.new("10.X.X.X/23")
]

列入白名单的 IP 地址与 ECS 在容器中创建和插入时将使用的 运行ge 匹配。希望对您有所帮助!

此处缺少的信息是 Rails 默认情况下不会在生产中设置 config.hostsconfig.hosts 的目的是防止由于存在 web-console.

而在开发环境中重新绑定 DNS

这是我找到的关于该主题的最佳文章:https://prathamesh.tech/2019/09/02/dns-rebinding-attacks-protection-in-rails-6/

对于我们来说,我们在 application.rb 中为我们的主域和子域设置了 config.hosts,然后在所有其他环境中对其进行了自定义。因此,这会导致 config.hosts 在生产中强制执行,然后 OP 观察到的 AWS 健康检查失败。

您有两个选择:

  1. 在生产中完全删除 config.hosts。由于这不是由 Rails 默认设置的,因此假设 DNS 重新绑定攻击在产品中不是问题。
  2. 确定production.rb中的请求ip。上述解决方案将应用程序绑定到不好的基础架构。如果您想将应用程序部署到新区域怎么办?您可以动态或静态地执行此操作。
    1. 静态:设置环境变量以获取 ELB 请求 ip 地址。如果您使用的是 AWS,希望您使用的是 CloudFormation,这样您就可以将适当的值作为 ENV 或 ParameterStore 变量传递。
    2. 动态:使用 AWS Ruby SDK 获取 ELB ip 地址

对于遇到此问题的人来说,这里是另一个:https://discuss.rubyonrails.org/t/feature-proposal-list-of-paths-to-skip-when-checking-host-authorization/76246

今天遇到了同样的问题。就我而言,我只是降低了标准以接受 403 是健康的。这并不理想,但我们不应该牺牲主机保护或为可预测的 IP 广泛开放它。


更新 1:

Rails 已经支持从 6.1

中排除配置
config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }

参考:https://api.rubyonrails.org/classes/ActionDispatch/HostAuthorization.html

主要原因是从目标组到健康检查容器的连接使用 IP,而不是域,所以 rails 响应 403。 接受 403 或将其从主机授权中排除。