Commit 7002b287 authored by Andy Soiron's avatar Andy Soiron

Merge branch '337829-deduplicate-regular-throttles' into 'master'

Add the idea of a regular throttle

See merge request gitlab-org/gitlab!70421
parents 907d9ad8 14fdd1ca
......@@ -82,9 +82,21 @@ module Gitlab
end
def self.configure_throttles(rack_attack)
throttle_or_track(rack_attack, 'throttle_unauthenticated_api', Gitlab::Throttle.unauthenticated_api_options) do |req|
if req.throttle_unauthenticated_api?
req.ip
# Each of these settings follows the same pattern of specifying separate
# authenticated and unauthenticated rates via settings
Gitlab::Throttle::REGULAR_THROTTLES.each do |throttle|
unauthenticated_options = Gitlab::Throttle.options(throttle, authenticated: false)
throttle_or_track(rack_attack, "throttle_unauthenticated_#{throttle}", unauthenticated_options) do |req|
if req.throttle?(throttle, authenticated: false)
req.ip
end
end
authenticated_options = Gitlab::Throttle.options(throttle, authenticated: true)
throttle_or_track(rack_attack, "throttle_authenticated_#{throttle}", authenticated_options) do |req|
if req.throttle?(throttle, authenticated: true)
req.throttled_user_id([:api])
end
end
end
......@@ -94,12 +106,6 @@ module Gitlab
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_api', Gitlab::Throttle.authenticated_api_options) do |req|
if req.throttle_authenticated_api?
req.throttled_user_id([:api])
end
end
# Product analytics feature is in experimental stage.
# At this point we want to limit amount of events registered
# per application (aid stands for application id).
......@@ -133,36 +139,12 @@ module Gitlab
end
end
throttle_or_track(rack_attack, 'throttle_unauthenticated_packages_api', Gitlab::Throttle.unauthenticated_packages_api_options) do |req|
if req.throttle_unauthenticated_packages_api?
req.ip
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_packages_api', Gitlab::Throttle.authenticated_packages_api_options) do |req|
if req.throttle_authenticated_packages_api?
req.throttled_user_id([:api])
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_git_lfs', Gitlab::Throttle.throttle_authenticated_git_lfs_options) do |req|
if req.throttle_authenticated_git_lfs?
req.throttled_user_id([:api])
end
end
throttle_or_track(rack_attack, 'throttle_unauthenticated_files_api', Gitlab::Throttle.unauthenticated_files_api_options) do |req|
if req.throttle_unauthenticated_files_api?
req.ip
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_files_api', Gitlab::Throttle.authenticated_files_api_options) do |req|
if req.throttle_authenticated_files_api?
req.throttled_user_id([:api])
end
end
rack_attack.safelist('throttle_bypass_header') do |req|
Gitlab::Throttle.bypass_header.present? &&
req.get_header(Gitlab::Throttle.bypass_header) == '1'
......
......@@ -60,6 +60,12 @@ module Gitlab
path =~ protected_paths_regex
end
def throttle?(throttle, authenticated:)
fragment = Gitlab::Throttle.throttle_fragment!(throttle, authenticated: authenticated)
__send__("#{fragment}?") # rubocop:disable GitlabSecurity/PublicSend
end
def throttle_unauthenticated_api?
api_request? &&
!should_be_skipped? &&
......
......@@ -4,6 +4,11 @@ module Gitlab
class Throttle
DEFAULT_RATE_LIMITING_RESPONSE_TEXT = 'Retry later'
# Each of these settings follows the same pattern of specifying separate
# authenticated and unauthenticated rates via settings. New throttles should
# ideally be regular as well.
REGULAR_THROTTLES = [:api, :packages_api, :files_api].freeze
def self.settings
Gitlab::CurrentSettings.current_application_settings
end
......@@ -24,28 +29,38 @@ module Gitlab
"HTTP_#{env_value.upcase.tr('-', '_')}"
end
def self.unauthenticated_api_options
limit_proc = proc { |req| settings.throttle_unauthenticated_api_requests_per_period }
period_proc = proc { |req| settings.throttle_unauthenticated_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
class << self
def options(throttle, authenticated:)
fragment = throttle_fragment!(throttle, authenticated: authenticated)
# rubocop:disable GitlabSecurity/PublicSend
limit_proc = proc { |req| settings.public_send("#{fragment}_requests_per_period") }
period_proc = proc { |req| settings.public_send("#{fragment}_period_in_seconds").seconds }
# rubocop:enable GitlabSecurity/PublicSend
{ limit: limit_proc, period: period_proc }
end
def throttle_fragment!(throttle, authenticated:)
raise("Unknown throttle: #{throttle}") unless REGULAR_THROTTLES.include?(throttle)
"throttle_#{'un' unless authenticated}authenticated_#{throttle}"
end
end
def self.unauthenticated_web_options
# TODO: Columns will be renamed in https://gitlab.com/gitlab-org/gitlab/-/issues/340031
# Once this is done, web can be made into a regular throttle
limit_proc = proc { |req| settings.throttle_unauthenticated_requests_per_period }
period_proc = proc { |req| settings.throttle_unauthenticated_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.authenticated_api_options
limit_proc = proc { |req| settings.throttle_authenticated_api_requests_per_period }
period_proc = proc { |req| settings.throttle_authenticated_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.authenticated_web_options
limit_proc = proc { |req| settings.throttle_authenticated_web_requests_per_period }
period_proc = proc { |req| settings.throttle_authenticated_web_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
......@@ -56,20 +71,6 @@ module Gitlab
{ limit: limit_proc, period: period_proc }
end
def self.unauthenticated_packages_api_options
limit_proc = proc { |req| settings.throttle_unauthenticated_packages_api_requests_per_period }
period_proc = proc { |req| settings.throttle_unauthenticated_packages_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.authenticated_packages_api_options
limit_proc = proc { |req| settings.throttle_authenticated_packages_api_requests_per_period }
period_proc = proc { |req| settings.throttle_authenticated_packages_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.throttle_authenticated_git_lfs_options
limit_proc = proc { |req| settings.throttle_authenticated_git_lfs_requests_per_period }
period_proc = proc { |req| settings.throttle_authenticated_git_lfs_period_in_seconds.seconds }
......@@ -77,20 +78,6 @@ module Gitlab
{ limit: limit_proc, period: period_proc }
end
def self.unauthenticated_files_api_options
limit_proc = proc { |req| settings.throttle_unauthenticated_files_api_requests_per_period }
period_proc = proc { |req| settings.throttle_unauthenticated_files_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.authenticated_files_api_options
limit_proc = proc { |req| settings.throttle_authenticated_files_api_requests_per_period }
period_proc = proc { |req| settings.throttle_authenticated_files_api_period_in_seconds.seconds }
{ limit: limit_proc, period: period_proc }
end
def self.rate_limiting_response_text
(settings.rate_limiting_response_text.presence || DEFAULT_RATE_LIMITING_RESPONSE_TEXT) + "\n"
end
......
......@@ -10,19 +10,19 @@ RSpec.describe Gitlab::RackAttack, :aggregate_failures do
let(:throttles) do
{
throttle_unauthenticated_api: Gitlab::Throttle.unauthenticated_api_options,
throttle_unauthenticated_api: Gitlab::Throttle.options(:api, authenticated: false),
throttle_authenticated_api: Gitlab::Throttle.options(:api, authenticated: true),
throttle_unauthenticated_web: Gitlab::Throttle.unauthenticated_web_options,
throttle_authenticated_api: Gitlab::Throttle.authenticated_api_options,
throttle_product_analytics_collector: { limit: 100, period: 60 },
throttle_authenticated_web: Gitlab::Throttle.authenticated_web_options,
throttle_product_analytics_collector: { limit: 100, period: 60 },
throttle_unauthenticated_protected_paths: Gitlab::Throttle.protected_paths_options,
throttle_authenticated_protected_paths_api: Gitlab::Throttle.protected_paths_options,
throttle_authenticated_protected_paths_web: Gitlab::Throttle.protected_paths_options,
throttle_unauthenticated_packages_api: Gitlab::Throttle.unauthenticated_packages_api_options,
throttle_authenticated_packages_api: Gitlab::Throttle.authenticated_packages_api_options,
throttle_unauthenticated_packages_api: Gitlab::Throttle.options(:packages_api, authenticated: false),
throttle_authenticated_packages_api: Gitlab::Throttle.options(:packages_api, authenticated: true),
throttle_authenticated_git_lfs: Gitlab::Throttle.throttle_authenticated_git_lfs_options,
throttle_unauthenticated_files_api: Gitlab::Throttle.unauthenticated_files_api_options,
throttle_authenticated_files_api: Gitlab::Throttle.authenticated_files_api_options
throttle_unauthenticated_files_api: Gitlab::Throttle.options(:files_api, authenticated: false),
throttle_authenticated_files_api: Gitlab::Throttle.options(:files_api, authenticated: true)
}
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment