diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index adbf7ab7cf2c3438284dbed26243562ccbb50265..aa2466372e1293e58fc55d4f40769e515bef21e3 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -497,7 +497,8 @@ def visible_attributes :projects_api_rate_limit_unauthenticated, :gitlab_dedicated_instance, :ci_max_includes, - :allow_account_deletion + :allow_account_deletion, + :gitlab_shell_operation_limit ].tap do |settings| next if Gitlab.com? diff --git a/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml b/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..4bd44b922fabd5329effe9fab37cff832d0423d8 --- /dev/null +++ b/app/views/admin/application_settings/_gitlab_shell_operation_limits.html.haml @@ -0,0 +1,19 @@ +%section.settings.no-animate#js-gitlab-shell-operation-limits-settings{ class: ('expanded' if expanded_by_default?), 'data-testid': 'gitlab-shell-operation-limits' } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only + = s_('ShellOperations|Git SSH operations rate limit') + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded_by_default? ? _('Collapse') : _('Expand') + %p + = s_('ShellOperations|Limit the number of Git operations a user can perform per minute, per repository.') + = link_to _('Learn more.'), help_page_path('user/admin_area/settings/rate_limits_on_git_ssh_operations.md'), target: '_blank', rel: 'noopener noreferrer' + .settings-content + = gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-gitlab-shell-operation-limits-settings'), html: { class: 'fieldset-form' } do |f| + = form_errors(@application_setting) + + %fieldset + .form-group + = f.label :gitlab_shell_operation_limit, s_('ShellOperations|Maximum number of Git operations per minute'), class: 'gl-font-bold' + = f.number_field :gitlab_shell_operation_limit, class: 'form-control gl-form-input' + + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml index 18ce7c1ceba3d37b0ca506afbd9d8ee00ea9a855..3b9fb930fd769024715a4ed2b059d022560f4170 100644 --- a/app/views/admin/application_settings/network.html.haml +++ b/app/views/admin/application_settings/network.html.haml @@ -84,6 +84,9 @@ .settings-content = render 'git_lfs_limits' + += render 'gitlab_shell_operation_limits' + %section.settings.as-outbound.no-animate#js-outbound-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'outbound_requests_content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only diff --git a/doc/api/settings.md b/doc/api/settings.md index ab78b9b7c74255f8bd9950bf43138c7f22bdabb3..bf4d4c201f1aca5c1bb0f3d3f7f8c0932c577123 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -550,6 +550,7 @@ listed in the descriptions of the relevant settings. | `wiki_page_max_content_bytes` | integer | no | Maximum wiki page content size in **bytes**. Default: 52428800 Bytes (50 MB). The minimum value is 1024 bytes. | | `jira_connect_application_key` | String | no | Application ID of the OAuth application that should be used to authenticate with the GitLab for Jira Cloud app | | `jira_connect_proxy_url` | String | no | URL of the GitLab instance that should be used as a proxy for the GitLab for Jira Cloud app | +| `gitlab_shell_operation_limit` | integer | no | Maximum number of Git operations per minute a user can perform. Default: `600`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412088) in GitLab 16.2. | ### Configure inactive project deletion diff --git a/doc/security/rate_limits.md b/doc/security/rate_limits.md index d835d8eb08c2ec9a48d0a023a6d6e1b89e47b2d4..74d1226942ca5316c53234e9a3f4389263b5b3a3 100644 --- a/doc/security/rate_limits.md +++ b/doc/security/rate_limits.md @@ -39,6 +39,7 @@ You can set these rate limits in the Admin Area of your instance: - [User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md) - [Package registry rate limits](../user/admin_area/settings/package_registry_rate_limits.md) - [Git LFS rate limits](../user/admin_area/settings/git_lfs_rate_limits.md) +- [Rate limits on Git SSH operations](../user/admin_area/settings/rate_limits_on_git_ssh_operations.md) - [Files API rate limits](../user/admin_area/settings/files_api_rate_limits.md) - [Deprecated API rate limits](../user/admin_area/settings/deprecated_api_rate_limits.md) - [GitLab Pages rate limits](../administration/pages/index.md#rate-limits) @@ -73,24 +74,6 @@ For configuration information, see ## Non-configurable limits -### Git operations using SSH - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78373) in GitLab 14.7 [with a flag](../administration/feature_flags.md) named `rate_limit_gitlab_shell`. Available by default without a feature flag from 15.8. - -GitLab applies rate limits to Git operations that use SSH by user account and project. When the rate limit is exceeded, GitLab rejects -further connection requests from that user for the project. - -The rate limit applies at the Git command ([plumbing](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain)) level. -Each command has a rate limit of 600 per minute. For example: - -- `git push` has a rate limit of 600 per minute. -- `git pull` has its own rate limit of 600 per minute. - -Because the same commands are shared by `git-upload-pack`, `git pull`, and `git clone`, they share a rate limit. - -The requests per minute threshold for this rate limit is not configurable. Self-managed customers can disable this -rate limit. - ### Repository archives > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25750) in GitLab 12.9. diff --git a/doc/user/admin_area/settings/rate_limits_on_git_ssh_operations.md b/doc/user/admin_area/settings/rate_limits_on_git_ssh_operations.md new file mode 100644 index 0000000000000000000000000000000000000000..7c6a5df604019f6558880f5654160fc937b793ec --- /dev/null +++ b/doc/user/admin_area/settings/rate_limits_on_git_ssh_operations.md @@ -0,0 +1,33 @@ +--- +stage: Create +group: Source Code +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +type: reference +--- + +# Rate limits on Git SSH operations **(FREE SELF)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78373) in GitLab 14.7 [with a flag](../../../administration/feature_flags.md) named `rate_limit_gitlab_shell`. Available by default without a feature flag from 15.8. + +GitLab applies rate limits to Git operations that use SSH by user account and project. When the rate limit is exceeded, GitLab rejects +further connection requests from that user for the project. + +The rate limit applies at the Git command ([plumbing](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain)) level. +Each command has a rate limit of 600 per minute. For example: + +- `git push` has a rate limit of 600 per minute. +- `git pull` has its own rate limit of 600 per minute. + +Because the same commands are shared by `git-upload-pack`, `git pull`, and `git clone`, they share a rate limit. + +Users on self-managed GitLab can disable this rate limit. + +## Configure GitLab Shell operation limit + +`Git operations using SSH` is enabled by default. Defaults to 600 per user per minute. + +1. On the left sidebar, select **Your work > Admin Area**. +1. On the left sidebar, select **Settings > Network**. +1. Expand **Git SSH operations rate limit**. +1. Enter a value for **Maximum number of Git operations per minute**. +1. Select **Save changes**. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4a033ded0bd4ea5358af0060a1f9dbb71849a53b..9ac4269fc18995e759245ba7e6f524cb2436587e 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -42630,6 +42630,15 @@ msgstr "" msgid "SharedRunnersMinutesSettings|When you reset the compute usage for this namespace, the compute usage changes to zero." msgstr "" +msgid "ShellOperations|Git SSH operations rate limit" +msgstr "" + +msgid "ShellOperations|Limit the number of Git operations a user can perform per minute, per repository." +msgstr "" + +msgid "ShellOperations|Maximum number of Git operations per minute" +msgstr "" + msgid "Shimo|Go to Shimo Workspace" msgstr "" diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 5f0d697b1e0b16762afbb0662684cd8432fb2ab8..7cbee63cc5ec453e198dea4a207ab6c7eb7aa62a 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -775,6 +775,18 @@ expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else]) end + it 'changes gitlab shell operation limits settings' do + visit network_admin_application_settings_path + + page.within('[data-testid="gitlab-shell-operation-limits"]') do + fill_in 'Maximum number of Git operations per minute', with: 100 + click_button 'Save changes' + end + + expect(page).to have_content "Application settings saved successfully" + expect(current_settings.gitlab_shell_operation_limit).to eq(100) + end + it 'changes Projects API rate limits settings' do visit network_admin_application_settings_path diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 79e96d7ea3ebc80018b21c9d6a52b5de51e8112f..28c4b0b3f084858d0c043bb2cd87fa1f0bb4519b 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -80,6 +80,7 @@ expect(json_response['valid_runner_registrars']).to match_array(%w(project group)) expect(json_response['ci_max_includes']).to eq(150) expect(json_response['allow_account_deletion']).to eq(true) + expect(json_response['gitlab_shell_operation_limit']).to eq(600) end end @@ -196,7 +197,8 @@ slack_app_signing_secret: 'SLACK_APP_SIGNING_SECRET', slack_app_verification_token: 'SLACK_APP_VERIFICATION_TOKEN', valid_runner_registrars: ['group'], - allow_account_deletion: false + allow_account_deletion: false, + gitlab_shell_operation_limit: 500 } expect(response).to have_gitlab_http_status(:ok) @@ -277,6 +279,7 @@ expect(json_response['slack_app_verification_token']).to eq('SLACK_APP_VERIFICATION_TOKEN') expect(json_response['valid_runner_registrars']).to eq(['group']) expect(json_response['allow_account_deletion']).to be(false) + expect(json_response['gitlab_shell_operation_limit']).to be(500) end end