简体   繁体   English

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

[英]Rails production not work in AWS load balancer

My Rails 6 App work fine with development mode in EC2 instances.我的 Rails 6 应用程序在 EC2 实例中的开发模式下运行良好。 But when config to use production mode.但是当配置使用生产模式时。 The load balancer not able to do health check and not able to run the app.负载均衡器无法进行健康检查,也无法运行应用程序。

My health check:我的健康检查:

在此处输入图像描述

Security: Load Balancer安全性:负载均衡器

在此处输入图像描述

在此处输入图像描述

Security: Rails App(s)安全性:Rails 应用程序

在此处输入图像描述

在此处输入图像描述

Load balancer worked in development负载均衡器在开发中工作

在此处输入图像描述

Here the development that work with load balancer这里是使用负载均衡器的开发

Start rails:启动轨道:

rails s -p 3000 -b 0.0.0.0

then responded然后回应

=> 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配置/环境/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

Below is production(that not working)以下是生产(不工作)

config/environments/production.rb配置/环境/production.rb

Start rails:启动轨道:

RAILS_ENV=production rails s -p 3000 -b 0.0.0.0

then responded:然后回复:

=> 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

Load Balancer: Health Check not work!负载均衡器:运行状况检查不起作用!

在此处输入图像描述

I also tried:我也试过:

  1. copy config/environments/development.rb to production.rb and then run as production environment the result =====> Health Check Not Work!将 config/environments/development.rb 复制到 production.rb 然后作为生产环境运行,结果 =====> 健康检查不起作用!
  2. copy config/environment/production.rb to development.rb and then run as development environment the result =====> Health Check Work!将 config/environment/production.rb 复制到 development.rb 然后作为开发环境运行结果 =====> 健康检查工作!

It seems nothing about the rails config, but the way it handle production in AWS rails 配置似乎与它无关,而是它在 AWS 中处理生产的方式

Help: How to make this Rails 6 work as production in AWS EC2 with load balancer?帮助:如何使用负载均衡器使这个 Rails 6 在 AWS EC2 中作为生产环境工作?

My company just ran into a very similar sounding issue.我的公司刚刚遇到了一个听起来非常相似的问题。 Once ECS spun up the tasks, we were able to access the Rails app through the ELB, but the health checks would fail and it would automatically shut down each container it tried to spin up.一旦 ECS 启动任务,我们就可以通过 ELB 访问 Rails 应用程序,但是健康检查会失败,它会自动关闭它尝试启动的每个容器。

We ended up adding our IP range to the hosts configuration.我们最终将 IP 范围添加到主机配置中。 Completely disabling it in production didn't feel right, so we arrived at something akin to this:在生产中完全禁用它感觉不对,所以我们得出了类似这样的结果:

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

The whitelisted IP address matches the range that will be used by ECS when creating and slotting in the containers.列入白名单的 IP 地址与 ECS 在容器中创建和插入时将使用的范围相匹配。 Hopefully that helps!希望这会有所帮助!

Instead of ping to root path, I think better if you create your own routes for health check in application like this:而不是 ping 到根路径,我认为如果您创建自己的路由以在应用程序中进行健康检查,如下所示:

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

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

then update ping path in LB health check to /health_check然后将 LB 健康检查中的 ping 路径更新为/health_check

Edit:编辑:

Add config.hosts.clear replaced config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com" in production config file to make rails accept request在生产配置文件中添加config.hosts.clear替换config.hosts << "xxxxxxxx.us-east-2.elb.amazonaws.com"以使 Rails 接受请求

The missing information here is that Rails by default does not set config.hosts in production.这里缺少的信息是 Rails 默认情况下不会在生产环境中设置config.hosts The purpose of config.hosts is to protect against DNS rebinding in development environments due to the presence of web-console . config.hosts的目的是防止由于web-console的存在而在开发环境中重新绑定 DNS。

This is the best article I found on the topic: https://prathamesh.tech/2019/09/02/dns-rebinding-attacks-protection-in-rails-6/这是我在该主题上找到的最好的文章: https://prathamesh.tech/2019/09/02/dns-rebinding-attacks-protection-in-rails-6/

For us, we have set config.hosts in application.rb for our primary domain and subdomain and then customized it in all the other environments.对于我们来说,我们在 application.rb 中为我们的主域和子域设置了config.hosts ,然后在所有其他环境中对其进行了自定义。 As such, this causes config.hosts to be enforced in production and then fail AWS health checks as observed by the OP.因此,这会导致config.hosts在生产中强制执行,然后 OP 观察到的 AWS 运行状况检查失败。

You have two options:你有两个选择:

  1. Remove config.hosts completely in production.在生产环境中完全删除config.hosts Since this is not set by Rails by default, the presumption is that DNS rebinding attacks are not an issue in prod.由于默认情况下 Rails 未设置此设置,因此假设 DNS 重新绑定攻击在 prod 中不是问题。
  2. Determine the request ip in production.rb.在production.rb中确定请求ip。 The above solutions tie the app to the infrastructure which is not good.上述解决方案将应用程序绑定到不好的基础设施。 What if you want to deploy your app to a new region?如果您想将应用程序部署到新区域怎么办? You can do this dynamically or statically.您可以动态或静态地执行此操作。
    1. Static: set an environment variable to pull in the ELB request ip addresses. Static:设置环境变量以拉入 ELB 请求 ip 地址。 If you're using AWS, hopefully you're using CloudFormation, so you can pass the appropriate values through as ENV or as ParameterStore variable.如果您使用的是 AWS,希望您使用的是 CloudFormation,因此您可以将适当的值作为 ENV 或作为 ParameterStore 变量传递。
    2. Dynamically: Use the AWS Ruby SDK to pull in the ELB ip addresses动态:使用 AWS Ruby SDK 拉入 ELB ip 地址

Another to those who come across this is here: https://discuss.rubyonrails.org/t/feature-proposal-list-of-paths-to-skip-when-checking-host-authorization/76246另一个遇到这个问题的人在这里: https://discuss.rubyonrails.org/t/feature-proposal-list-of-paths-to-skip-when-checking-host-authorization/76246

Had the same issue today.今天有同样的问题。 In my case, I simply lower the bar to accept 403 as healthy.就我而言,我只是降低标准以接受 403 是健康的。 It's not ideal, but we shouldn't sacrifice hosts protection or open it widely for predictable IPs.这并不理想,但我们不应该牺牲主机保护或为可预测的 IP 广泛开放它。

健康检查配置


Updated 1:更新1:

Rails already support exclude config from 6.1 Rails 已经支持从 6.1 中排除配置

config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }

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

The main reason is connection from target group to container for healthcheck uses IP, not domain, so rails response 403. Accept 403 or exclude it from host authorization.主要原因是从目标组到容器的健康检查连接使用 IP,而不是域,所以轨道响应 403。接受 403 或将其从主机授权中排除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM