diff --git a/CHANGELOG.md b/CHANGELOG.md index 44ed355..2722433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [Unreleased] +## リリース内容は [Releases](https://github.com/SonicGarden/sg_fargate_rails/releases) に移動しました ## [0.1.6](https://github.com/SonicGarden/sg_fargate_rails/compare/v0.1.5...v0.1.6) diff --git a/lib/sg_fargate_rails/config.rb b/lib/sg_fargate_rails/config.rb index 865b5a1..8e8df4f 100644 --- a/lib/sg_fargate_rails/config.rb +++ b/lib/sg_fargate_rails/config.rb @@ -1,9 +1,20 @@ module SgFargateRails class Config - attr_accessor :proxy_ip_addresses, :paths_to_allow_access_only_from_proxy + attr_accessor :paths_to_allow_access_only_from_proxy + attr_reader :proxy_ip_addresses def initialize self.proxy_ip_addresses = ENV['SG_PROXY_IP_ADDRESSES'] end + + def proxy_ip_addresses=(ip_addresses) + @proxy_ip_addresses = Array(ip_addresses).flat_map do |ip_address_str| + ip_address_str.split(',').map(&:strip).reject(&:blank?).map { |ip| IPAddr.new(ip) } + end + end + + def proxy_access?(ip_address) + @proxy_ip_addresses.any? { |proxy_ip_address| proxy_ip_address.include?(ip_address) } + end end end diff --git a/lib/sg_fargate_rails/maintenance.rb b/lib/sg_fargate_rails/maintenance.rb index ed1524f..a1ee4db 100644 --- a/lib/sg_fargate_rails/maintenance.rb +++ b/lib/sg_fargate_rails/maintenance.rb @@ -9,7 +9,7 @@ def initialize(app, options = {}) end def call(env) - if maintenance_mode?(env) && !public_file_access?(env) + if maintenance_mode?(env) && !public_file_access?(env) && !proxy_access?(Rack::Request.new(env)) headers = { 'Content-Type' => 'text/html' } [503, headers, File.open(maintenance_file_path)] else @@ -36,5 +36,9 @@ def public_files def maintenance_file_path Rails.public_path.join('503.html') end + + def proxy_access?(req) + SgFargateRails.config.proxy_access?(req.ip) || req.forwarded_for&.any? { |forwarded_for| SgFargateRails.config.proxy_access?(forwarded_for) } + end end end diff --git a/lib/sg_fargate_rails/rack_attack.rb b/lib/sg_fargate_rails/rack_attack.rb index b3d57fd..c4839b2 100644 --- a/lib/sg_fargate_rails/rack_attack.rb +++ b/lib/sg_fargate_rails/rack_attack.rb @@ -4,13 +4,10 @@ module SgFargateRails class RackAttack class << self def setup - proxy_ip_addresses = Array(SgFargateRails.config.proxy_ip_addresses).flat_map do |ip_address_str| - ip_address_str.split(',').map(&:strip).reject(&:blank?) - end - return if proxy_ip_addresses.empty? + return if SgFargateRails.config.proxy_ip_addresses.empty? Rack::Attack.blocklist('allow only from proxy') do |req| - ip_retricted_path?(req.path) && !access_from?(req, proxy_ip_addresses) + ip_retricted_path?(req.path) && !proxy_access?(req) end end @@ -19,10 +16,8 @@ def ip_retricted_path?(path) rectricted_paths.any? { path.match?(/^#{_1}/) } end - def access_from?(req, proxy_ip_addresses) - proxy_ip_addresses.any? do |proxy_ip_address| - req.ip == proxy_ip_address || req.forwarded_for&.include?(proxy_ip_address) - end + def proxy_access?(req) + SgFargateRails.config.proxy_access?(req.ip) || req.forwarded_for&.any? { |forwarded_for| SgFargateRails.config.proxy_access?(forwarded_for) } end end end diff --git a/lib/sg_fargate_rails/railtie.rb b/lib/sg_fargate_rails/railtie.rb index 8cf3301..17829e6 100644 --- a/lib/sg_fargate_rails/railtie.rb +++ b/lib/sg_fargate_rails/railtie.rb @@ -2,6 +2,7 @@ require 'sg_fargate_rails/healthcheck' require 'sg_fargate_rails/maintenance' require 'sg_fargate_rails/rack_attack' +require 'sg_fargate_rails/remote_ip' require 'sg_fargate_rails/task_protection' module SgFargateRails @@ -13,6 +14,7 @@ class Railtie < ::Rails::Railtie app.config.middleware.insert 0, SgFargateRails::AdjustCloudfrontHeaders app.config.middleware.insert 1, SgFargateRails::Healthcheck app.config.middleware.insert 2, SgFargateRails::Maintenance + app.config.middleware.swap ActionDispatch::RemoteIp, SgFargateRails::RemoteIp, app.config.action_dispatch.ip_spoofing_check, app.config.action_dispatch.trusted_proxies end end end diff --git a/lib/sg_fargate_rails/remote_ip.rb b/lib/sg_fargate_rails/remote_ip.rb new file mode 100644 index 0000000..e550a46 --- /dev/null +++ b/lib/sg_fargate_rails/remote_ip.rb @@ -0,0 +1,12 @@ +module SgFargateRails + # NOTE: HTTP_CLOUDFRONT_VIEWER_ADDRESSを考慮するように上書きしている + # SEE: https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/remote_ip.rb + class RemoteIp < ActionDispatch::RemoteIp + def call(env) + req = ActionDispatch::Request.new env + # NOTE: HTTP_CLOUDFRONT_VIEWER_ADDRESSヘッダには127.0.0.1:3000といったIP4アドレスや2406:2d40:3090:af00:25c1:6071:b820:8e47:3000といったIP6アドレスが入っている + req.remote_ip = req.headers['HTTP_CLOUDFRONT_VIEWER_ADDRESS'] ? req.headers['HTTP_CLOUDFRONT_VIEWER_ADDRESS'].remove(/:\d+$/) : ActionDispatch::RemoteIp::GetIp.new(req, check_ip, proxies) + @app.call(req.env) + end + end +end diff --git a/lib/sg_fargate_rails/version.rb b/lib/sg_fargate_rails/version.rb index f674806..a3b67fb 100644 --- a/lib/sg_fargate_rails/version.rb +++ b/lib/sg_fargate_rails/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SgFargateRails - VERSION = "0.1.6" + VERSION = "0.1.8" end