From f1c8d5b765edb67b00f95f320739e73419e256fe Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 12 Dec 2024 11:58:03 +0100 Subject: [PATCH] New Cloudflare Setting: Optionally fetch CF IPs on container boot. --- config/defaults/settings.yml | 15 ++++++++++ config/initializers/cloudflare_proxy.rb | 40 +++++++++++++++++++++++++ config/settings.yml | 15 ++++++++++ 3 files changed, 70 insertions(+) create mode 100644 config/initializers/cloudflare_proxy.rb diff --git a/config/defaults/settings.yml b/config/defaults/settings.yml index 816fdb776c96..8ca97a793f72 100644 --- a/config/defaults/settings.yml +++ b/config/defaults/settings.yml @@ -714,6 +714,21 @@ throttling: # - '1.2.3.4' # - '2.3.4.5' +## Cloudflare Proxy +# +# If you are using Cloudflare as a proxy, you will need to set the following +# value to true. This will cause the application to fetch the list of Cloudflare +# proxy IP addresses and add them to the list of trusted proxies. +# +# Note that on application boot, this will trigger two HTTPs requests to fetch +# the list of Cloudflare IP addresses. The requests each have a timeout of 15 seconds +# and may delay on container boot. +# +# Environment Variable Override: +# PWP__CLOUDFLARE_PROXY='false' +# +cloudflare_proxy: false + ### Mail Server Configuration # # When logins are enabled, an SMTP server is required to send emails to users diff --git a/config/initializers/cloudflare_proxy.rb b/config/initializers/cloudflare_proxy.rb new file mode 100644 index 000000000000..904ddbf1c6be --- /dev/null +++ b/config/initializers/cloudflare_proxy.rb @@ -0,0 +1,40 @@ +require "net/http" + +if Settings.cloudflare_proxy + def fetch_with_timeout(url, timeout: 15) + uri = URI(url) + Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: timeout, read_timeout: timeout) do |http| + request = Net::HTTP::Get.new(uri) + http.request(request).body + end + rescue => e + Rails.logger.warn "Failed to fetch #{url}: #{e.message}" + "" + end + + Rails.logger.info "Fetching latest Cloudflare IPs..." + + cf_ipv4_url = "https://www.cloudflare.com/ips-v4" + cf_ipv6_url = "https://www.cloudflare.com/ips-v6" + + begin + # Fetch Cloudflare IP ranges with timeout + ipv4 = fetch_with_timeout(cf_ipv4_url).split("\n") + ipv6 = fetch_with_timeout(cf_ipv6_url).split("\n") + cloudflare_ips = ipv4 + ipv6 + rescue => e + Rails.logger.warn "Failed to fetch Cloudflare IPs: #{e.message}" + cloudflare_ips = [] # Fallback to no Cloudflare IPs + end + + # Add Cloudflare IPs to existing trusted proxies + Rails.application.config.action_dispatch.trusted_proxies ||= [] + Rails.application.config.action_dispatch.trusted_proxies += cloudflare_ips.filter_map do |ip| + IPAddr.new(ip) + rescue ArgumentError => e + Rails.logger.warn "Invalid IP format skipped: #{ip} (#{e.message})" + nil + end + + Rails.logger.info "Cloudflare IPs added to trusted proxies." +end diff --git a/config/settings.yml b/config/settings.yml index 816fdb776c96..8ca97a793f72 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -714,6 +714,21 @@ throttling: # - '1.2.3.4' # - '2.3.4.5' +## Cloudflare Proxy +# +# If you are using Cloudflare as a proxy, you will need to set the following +# value to true. This will cause the application to fetch the list of Cloudflare +# proxy IP addresses and add them to the list of trusted proxies. +# +# Note that on application boot, this will trigger two HTTPs requests to fetch +# the list of Cloudflare IP addresses. The requests each have a timeout of 15 seconds +# and may delay on container boot. +# +# Environment Variable Override: +# PWP__CLOUDFLARE_PROXY='false' +# +cloudflare_proxy: false + ### Mail Server Configuration # # When logins are enabled, an SMTP server is required to send emails to users