Commit 981ad651 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch '250480-enforce-ssh-key-expiry' into 'master'

Adds ability to enforce SSH key expiration

See merge request gitlab-org/gitlab!51921
parents 0bc6bbf0 56c480e5
......@@ -31,6 +31,7 @@
= render_if_exists 'admin/application_settings/personal_access_token_expiration_policy', form: f
= render_if_exists 'admin/application_settings/enforce_pat_expiration', form: f
= render_if_exists 'admin/application_settings/enforce_ssh_key_expiration', form: f
.form-group
= f.label :user_oauth_applications, _('User OAuth applications'), class: 'label-bold'
......
---
title: Add enforced SSH key expiration
merge_request: 51921
author:
type: added
# frozen_string_literal: true
class AddEnforceSshKeyExpirationToApplicationSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :application_settings, :enforce_ssh_key_expiration, :boolean, default: false, null: false
end
end
f33cc3eebc9197db381d81150a140582e30905d3964d6fb444caad6c9eff1b31
\ No newline at end of file
......@@ -9410,6 +9410,7 @@ CREATE TABLE application_settings (
rate_limiting_response_text text,
invisible_captcha_enabled boolean DEFAULT false NOT NULL,
container_registry_cleanup_tags_service_max_list_size integer DEFAULT 200 NOT NULL,
enforce_ssh_key_expiration boolean DEFAULT false NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
......
......@@ -164,6 +164,40 @@ Once a lifetime for personal access tokens is set, GitLab will:
- After three hours, revoke old tokens with no expiration date or with a lifetime longer than the
allowed lifetime. Three hours is given to allow administrators to change the allowed lifetime,
or remove it, before revocation takes place.
## Enforcement of SSH key expiration **(ULTIMATE ONLY)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.9.
> - It is deployed behind a feature flag, disabled by default.
> - It is disabled on GitLab.com.
> - It is not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-enforcement-of-ssh-key-expiration-feature). **(CORE ONLY)**
GitLab administrators can choose to enforce the expiration of SSH keys after their expiration dates.
If you enable this feature, this disables all _expired_ SSH keys.
To do this:
1. Navigate to **Admin Area > Settings > General**.
1. Expand the **Account and limit** section.
1. Select the **Enforce SSH key expiration** checkbox.
### Enable or disable enforcement of SSH key expiration Feature **(CORE ONLY)**
Enforcement of SSH key expiry is deployed behind a feature flag and is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) can enable it for your instance from the [rails console](../../../administration/feature_flags.md#start-the-gitlab-rails-console).
To enable it:
```ruby
Feature.enable(:ff_enforce_ssh_key_expiration)
```
To disable it:
```ruby
Feature.disable(:ff_enforce_ssh_key_expiration)
```
## Optional enforcement of Personal Access Token expiry **(ULTIMATE SELF)**
......
......@@ -50,6 +50,7 @@ module EE
:elasticsearch_analyzers_kuromoji_search,
:enforce_namespace_storage_limit,
:enforce_pat_expiration,
:enforce_ssh_key_expiration,
:geo_node_allowed_ips,
:geo_status_timeout,
:help_text,
......
......@@ -8,12 +8,28 @@ module EE
include UsageStatistics
scope :ldap, -> { where(type: 'LDAPKey') }
validate :expiration, if: -> { ::Key.expiration_enforced? }
def expiration
errors.add(:key, 'has expired and the instance administrator has enforced expiration') if expired?
end
end
class_methods do
def regular_keys
where(type: ['LDAPKey', 'Key', nil])
end
def expiration_enforced?
return false unless enforce_ssh_key_expiration_feature_available?
::Gitlab::CurrentSettings.enforce_ssh_key_expiration?
end
def enforce_ssh_key_expiration_feature_available?
License.feature_available?(:enforce_ssh_key_expiration) && ::Feature.enabled?(:ff_enforce_ssh_key_expiration)
end
end
end
end
......@@ -142,6 +142,7 @@ class License < ApplicationRecord
dependency_scanning
devops_adoption
enforce_pat_expiration
enforce_ssh_key_expiration
enterprise_templates
environment_alerts
group_ci_cd_analytics
......
- return unless Key.enforce_ssh_key_expiration_feature_available?
- form = local_assigns.fetch(:form)
.form-group
.form-check
= form.check_box :enforce_ssh_key_expiration, class: 'form-check-input'
= form.label :enforce_ssh_key_expiration, class: 'form-check-label' do
= _('Enforce SSH key expiration')
---
name: ff_enforce_ssh_key_expiration
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51921
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299092
milestone: '13.9'
type: development
group: group::compliance
default_enabled: false
......@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe EE::ApplicationSettingsHelper do
describe '.visible_attributes' do
context 'personal access token parameters' do
it { expect(visible_attributes).to include(*%i(max_personal_access_token_lifetime enforce_pat_expiration)) }
it { expect(visible_attributes).to include(*%i(max_personal_access_token_lifetime enforce_pat_expiration enforce_ssh_key_expiration)) }
end
end
end
......@@ -779,6 +779,23 @@ RSpec.describe Gitlab::GitAccess do
end
end
describe '#check_valid_actor!' do
context 'key expiration is enforced' do
let(:actor) { build(:personal_key, expires_at: 2.days.ago) }
before do
stub_licensed_features(enforce_ssh_key_expiration: true)
stub_feature_flags(ff_enforce_ssh_key_expiration: true)
stub_ee_application_setting(enforce_ssh_key_expiration: true)
end
it 'does not allow expired keys', :aggregate_failures do
expect { push_changes }.to raise_forbidden('Your SSH key has expired and the instance administrator has enforced expiration.')
expect { pull_changes }.to raise_forbidden('Your SSH key has expired and the instance administrator has enforced expiration.')
end
end
end
private
def access
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Key do
describe 'validations' do
describe 'expiration' do
using RSpec::Parameterized::TableSyntax
where(:key, :expiration_enforced, :valid ) do
build(:personal_key, expires_at: 2.days.ago) | true | false
build(:personal_key, expires_at: 2.days.ago) | false | true
build(:personal_key) | false | true
build(:personal_key) | true | true
end
with_them do
it 'checks if ssh key expiration is enforced' do
expect(Key).to receive(:expiration_enforced?).and_return(expiration_enforced)
expect(key.valid?).to eq(valid)
end
end
end
end
describe '.expiration_enforced?' do
using RSpec::Parameterized::TableSyntax
where(:feature_enabled, :licensed, :application_setting, :available) do
true | true | true | true
true | true | false | false
true | false | true | false
true | false | false | false
false | true | true | false
false | true | false | false
false | false | true | false
false | false | false | false
end
with_them do
before do
stub_feature_flags(ff_enforce_ssh_key_expiration: feature_enabled)
stub_licensed_features(enforce_ssh_key_expiration: licensed)
stub_ee_application_setting(enforce_ssh_key_expiration: application_setting)
end
it 'checks if ssh key expiration is enforced' do
expect(described_class.expiration_enforced?).to be(available)
end
end
end
end
......@@ -10926,6 +10926,9 @@ msgstr ""
msgid "Enforce DNS rebinding attack protection"
msgstr ""
msgid "Enforce SSH key expiration"
msgstr ""
msgid "Enforce personal access token expiration"
msgstr ""
......
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