Skip to content
Snippets Groups Projects
Verified Commit 9e62df22 authored by Pedro Pombeiro's avatar Pedro Pombeiro Committed by GitLab
Browse files

Merge branch...

Merge branch '448796-add-ui-to-allow-disabling-use-of-registration-tokens-in-admin-panel' into 'master' 

Add UI to allow disabling use of registration tokens admin panel

See merge request !147559



Merged-by: default avatarPedro Pombeiro <noreply@pedro.pombei.ro>
Approved-by: default avatarFiona Neill <fneill@gitlab.com>
Approved-by: Alex Buijs's avatarAlex Buijs <abuijs@gitlab.com>
Approved-by: Gina Doyle's avatarGina Doyle <gdoyle@gitlab.com>
Approved-by: default avatardrew stachon <730684-drew@users.noreply.gitlab.com>
Approved-by: default avatarMireya Andres <mandres@gitlab.com>
Approved-by: default avatarPedro Pombeiro <noreply@pedro.pombei.ro>
Reviewed-by: default avatarPedro Pombeiro <noreply@pedro.pombei.ro>
Reviewed-by: Miguel Rincon's avatarMiguel Rincon <mrincon@gitlab.com>
Reviewed-by: default avatarMireya Andres <mandres@gitlab.com>
Reviewed-by: default avatarFiona Neill <fneill@gitlab.com>
Reviewed-by: Gina Doyle's avatarGina Doyle <gdoyle@gitlab.com>
Co-authored-by: Miguel Rincon's avatarMiguel Rincon <mrincon@gitlab.com>
parents a6d26191 7e4b4f7d
No related branches found
No related tags found
1 merge request!147559Add UI to allow disabling use of registration tokens admin panel
Pipeline #1238495055 passed
Showing
with 180 additions and 55 deletions
......@@ -66,9 +66,15 @@ export default {
type: String,
required: true,
},
allowRegistrationToken: {
type: Boolean,
required: false,
default: false,
},
registrationToken: {
type: String,
required: true,
required: false,
default: null,
},
},
data() {
......@@ -212,6 +218,7 @@ export default {
{{ s__('Runners|New instance runner') }}
</gl-button>
<registration-dropdown
:allow-registration-token="allowRegistrationToken"
:registration-token="registrationToken"
:type="$options.INSTANCE_TYPE"
placement="right"
......
......@@ -7,6 +7,7 @@ import { provide } from 'ee_else_ce/ci/runner/admin_runners/provide';
import { visitUrl } from '~/lib/utils/url_utility';
import { updateOutdatedUrl } from '~/ci/runner/runner_search_utils';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import { createLocalState } from '../graphql/list/local_state';
import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
import AdminRunnersApp from './admin_runners_app.vue';
......@@ -32,7 +33,7 @@ export const initAdminRunners = (selector = '#js-admin-runners') => {
return null;
}
const { newRunnerPath, registrationToken } = el.dataset;
const { newRunnerPath, allowRegistrationToken, registrationToken } = el.dataset;
const { cacheConfig, typeDefs, localMutations } = createLocalState();
const apolloProvider = new VueApollo({
......@@ -50,6 +51,7 @@ export const initAdminRunners = (selector = '#js-admin-runners') => {
return h(AdminRunnersApp, {
props: {
newRunnerPath,
allowRegistrationToken: parseBoolean(allowRegistrationToken),
registrationToken,
},
});
......
......@@ -5,8 +5,10 @@ import {
GlDisclosureDropdownItem,
GlDisclosureDropdownGroup,
GlIcon,
GlLink,
GlSprintf,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
import {
......@@ -21,30 +23,34 @@ import {
import RegistrationToken from './registration_token.vue';
import RegistrationTokenResetDropdownItem from './registration_token_reset_dropdown_item.vue';
const REGISTRATION_TOKEN_ENABLED = 'REGISTRATION_TOKEN_ENABLED';
const REGISTRATION_TOKEN_DISABLED = 'REGISTRATION_TOKEN_DISABLED';
const REGISTRATION_TOKEN_HIDDEN = 'REGISTRATION_TOKEN_HIDDEN';
export default {
i18n: {
showInstallationInstructions: s__(
'Runners|Show runner installation and registration instructions',
),
supportForRegistrationTokensDeprecated: s__(
'Runners|Support for registration tokens is deprecated',
),
},
components: {
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlDisclosureDropdownGroup,
GlDropdownForm,
GlIcon,
GlLink,
GlSprintf,
RegistrationToken,
RunnerInstructionsModal,
RegistrationTokenResetDropdownItem,
},
mixins: [glFeatureFlagMixin()],
props: {
allowRegistrationToken: {
type: Boolean,
required: false,
default: false,
},
registrationToken: {
type: String,
required: true,
required: false,
default: null,
},
type: {
type: String,
......@@ -72,6 +78,23 @@ export default {
return I18N_REGISTER_RUNNER;
}
},
isRegistrationTokenPresent() {
return Boolean(this.registrationToken);
},
state() {
if (this.registrationToken && this.allowRegistrationToken) {
// Legacy registration with registration token can be used, will be fully removed by 18.0
return REGISTRATION_TOKEN_ENABLED;
}
if (!this.allowRegistrationToken) {
// If registration is disabled by admins or group owners, display the dropdown with a message
return REGISTRATION_TOKEN_DISABLED;
}
// If registration is still enabled for the instance or group, but the user cannot see the
// token due to permissions, hide this control as they don't have access
return REGISTRATION_TOKEN_HIDDEN;
},
},
methods: {
onShowInstructionsClick() {
......@@ -86,11 +109,18 @@ export default {
this.$refs.runnerRegistrationDropdown.close();
},
},
REGISTRATION_TOKEN_ENABLED,
REGISTRATION_TOKEN_DISABLED,
REGISTRATION_TOKEN_HIDDEN,
registrationTokenDisabledHelpPagePath: helpPagePath('ci/runners/new_creation_workflow.html', {
anchor: 'using-registration-tokens-after-gitlab-170',
}),
};
</script>
<template>
<gl-disclosure-dropdown
v-if="state !== $options.REGISTRATION_TOKEN_HIDDEN"
ref="runnerRegistrationDropdown"
:toggle-text="actionText"
toggle-class="gl-px-3!"
......@@ -101,30 +131,48 @@ export default {
text-sr-only
no-caret
>
<gl-dropdown-form class="gl-p-4!">
<registration-token input-id="token-value" :value="currentRegistrationToken" @copy="onCopy">
<template #label-description>
<gl-icon name="warning" class="gl-text-orange-500" />
<span class="gl-text-secondary">
{{ $options.i18n.supportForRegistrationTokensDeprecated }}
</span>
</template>
</registration-token>
</gl-dropdown-form>
<gl-disclosure-dropdown-group bordered>
<gl-disclosure-dropdown-item @action="onShowInstructionsClick">
<template #list-item>
{{ $options.i18n.showInstallationInstructions }}
<runner-instructions-modal
ref="runnerInstructionsModal"
:registration-token="currentRegistrationToken"
data-testid="runner-instructions-modal"
/>
</template>
</gl-disclosure-dropdown-item>
</gl-disclosure-dropdown-group>
<gl-disclosure-dropdown-group bordered>
<registration-token-reset-dropdown-item :type="type" @tokenReset="onTokenReset" />
</gl-disclosure-dropdown-group>
<div v-if="state == $options.REGISTRATION_TOKEN_DISABLED" class="gl-px-4 gl-py-2">
<gl-icon name="error" class="gl-text-red-500" />
<gl-sprintf
:message="
s__(
'Runners|Creating runners with runner registration tokens is disabled. %{linkStart}Learn more%{linkEnd}.',
)
"
>
<template #link="{ content }"
><gl-link :href="$options.registrationTokenDisabledHelpPagePath">{{
content
}}</gl-link></template
>
</gl-sprintf>
</div>
<template v-if="state == $options.REGISTRATION_TOKEN_ENABLED">
<gl-dropdown-form class="gl-p-4!">
<registration-token input-id="token-value" :value="currentRegistrationToken" @copy="onCopy">
<template #label-description>
<gl-icon name="warning" class="gl-text-orange-500" />
<span class="gl-text-secondary">
{{ s__('Runners|Support for registration tokens is deprecated') }}
</span>
</template>
</registration-token>
</gl-dropdown-form>
<gl-disclosure-dropdown-group bordered>
<gl-disclosure-dropdown-item @action="onShowInstructionsClick">
<template #list-item>
{{ s__('Runners|Show runner installation and registration instructions') }}
<runner-instructions-modal
ref="runnerInstructionsModal"
:registration-token="currentRegistrationToken"
data-testid="runner-instructions-modal"
/>
</template>
</gl-disclosure-dropdown-item>
</gl-disclosure-dropdown-group>
<gl-disclosure-dropdown-group bordered>
<registration-token-reset-dropdown-item :type="type" @tokenReset="onTokenReset" />
</gl-disclosure-dropdown-group>
</template>
</gl-disclosure-dropdown>
</template>
......@@ -65,6 +65,11 @@ export default {
required: false,
default: null,
},
allowRegistrationToken: {
type: Boolean,
required: false,
default: false,
},
registrationToken: {
type: String,
required: false,
......@@ -223,7 +228,7 @@ export default {
{{ s__('Runners|New group runner') }}
</gl-button>
<registration-dropdown
v-if="registrationToken"
:allow-registration-token="allowRegistrationToken"
:registration-token="registrationToken"
:type="$options.GROUP_TYPE"
placement="right"
......
......@@ -2,6 +2,7 @@ import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import { createLocalState } from '../graphql/list/local_state';
import GroupRunnersApp from './group_runners_app.vue';
......@@ -16,6 +17,7 @@ export const initGroupRunners = (selector = '#js-group-runners') => {
}
const {
allowRegistrationToken,
registrationToken,
runnerInstallHelpPage,
newRunnerPath,
......@@ -44,9 +46,10 @@ export const initGroupRunners = (selector = '#js-group-runners') => {
render(h) {
return h(GroupRunnersApp, {
props: {
registrationToken,
groupFullPath,
newRunnerPath,
allowRegistrationToken: parseBoolean(allowRegistrationToken),
registrationToken,
},
});
},
......
......@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import RegistrationDropdown from '~/ci/runner/components/registration/registration_dropdown.vue';
import { PROJECT_TYPE } from '~/ci/runner/constants';
import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(VueApollo);
......@@ -15,7 +16,7 @@ export const initProjectRunnersRegistrationDropdown = (
return null;
}
const { registrationToken, projectId } = el.dataset;
const { allowRegistrationToken, registrationToken, projectId } = el.dataset;
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
......@@ -30,6 +31,7 @@ export const initProjectRunnersRegistrationDropdown = (
render(h) {
return h(RegistrationDropdown, {
props: {
allowRegistrationToken: parseBoolean(allowRegistrationToken),
registrationToken,
type: PROJECT_TYPE,
},
......
......@@ -10,7 +10,9 @@ class Groups::RunnersController < Groups::ApplicationController
urgency :low
def index
@allow_registration_token = @group.allow_runner_registration_token?
@group_runner_registration_token = @group.runners_token if can?(current_user, :register_group_runners, group)
@group_new_runner_path = new_group_runner_path(@group) if can?(current_user, :create_runner, group)
Gitlab::Tracking.event(self.class.name, 'index', user: current_user, namespace: @group)
......
......@@ -59,6 +59,7 @@ def admin_runners_data_attributes
# https://gitlab.com/gitlab-org/gitlab-runner
runner_install_help_page: 'https://docs.gitlab.com/runner/install/',
new_runner_path: new_admin_runner_path,
allow_registration_token: Gitlab::CurrentSettings.allow_runner_registration_token.to_s,
registration_token: Gitlab::CurrentSettings.runners_registration_token,
online_contact_timeout_secs: ::Ci::Runner::ONLINE_CONTACT_TIMEOUT.to_i,
stale_timeout_secs: ::Ci::Runner::STALE_TIMEOUT.to_i,
......
......@@ -501,6 +501,8 @@ def pick_repository_storage
end
def runners_registration_token
return unless Gitlab::CurrentSettings.allow_runner_registration_token
ensure_runners_registration_token!
end
......
......@@ -776,6 +776,8 @@ def refresh_project_authorizations
# we do this on read since migrating all existing groups is not a feasible
# solution.
def runners_token
return unless allow_runner_registration_token?
ensure_runners_token!
end
......
......@@ -2249,6 +2249,8 @@ def visibility_level_allowed?(level = self.visibility_level)
end
def runners_token
return unless namespace.allow_runner_registration_token?
ensure_runners_token!
end
......
......@@ -110,6 +110,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
@subject.runner_registration_enabled?
end
condition(:runner_registration_token_enabled, scope: :subject) do
@subject.allow_runner_registration_token?
end
condition(:raise_admin_package_to_owner_enabled) do
Feature.enabled?(:raise_group_admin_package_permission_to_owner, @subject)
end
......@@ -375,6 +379,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
prevent :create_runner
end
rule { ~runner_registration_token_enabled }.policy do
prevent :register_group_runners
end
rule { migration_bot }.policy do
enable :read_resource_access_tokens
enable :destroy_resource_access_tokens
......
......@@ -53,6 +53,8 @@ def attrs_from_token
strong_memoize_attr :attrs_from_token
def registration_token_allowed?(attrs)
return false if registration_token.nil?
case attrs[:runner_type]
when :group_type
token_scope.allow_runner_registration_token?
......@@ -64,6 +66,8 @@ def registration_token_allowed?(attrs)
end
def runner_registration_token_valid?(registration_token)
return false if registration_token.nil?
ActiveSupport::SecurityUtils.secure_compare(registration_token, Gitlab::CurrentSettings.runners_registration_token)
end
......
......@@ -15,13 +15,13 @@
%h5
= s_('Runners|Runner registration')
%span.form-text.gl-mb-3.gl-mt-0
= s_('Runners|If both settings are disabled, new runners cannot be registered.')
= link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
= hidden_field_tag "application_setting[valid_runner_registrars][]", nil
- ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES.each do |type|
= f.gitlab_ui_checkbox_component :valid_runner_registrars, s_("Runners|Members of the %{type} can register runners") % { type: type },
checkbox_options: { multiple: true, checked: valid_runner_registrars.include?(type) },
checked_value: type,
unchecked_value: nil
= f.gitlab_ui_checkbox_component :allow_runner_registration_token, s_("AdminSettings|Allow runner registration token"), help_text: s_("AdminSettings|When disabled, runner registration tokens are disabled from runner pages, and maintainers and owners cannot use registration tokens to register runners. They can use runner authentication tokens instead as the more secure runner registration method.")
= hidden_field_tag "application_setting[valid_runner_registrars][]", nil
- ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES.each do |type|
= f.gitlab_ui_checkbox_component :valid_runner_registrars, s_("Runners|Members of the %{type} can create runners") % { type: type },
checkbox_options: { multiple: true, checked: valid_runner_registrars.include?(type) },
checked_value: type,
unchecked_value: nil
= f.submit _('Save changes'), pajamas_button: true
- page_title s_('Runners|Runners')
#js-group-runners{ data: group_runners_data_attributes(@group).merge({ registration_token: @group_runner_registration_token, new_runner_path: @group_new_runner_path }) }
#js-group-runners{ data: group_runners_data_attributes(@group).merge({ allow_registration_token: @allow_registration_token.to_s, registration_token: @group_runner_registration_token, new_runner_path: @group_new_runner_path }) }
......@@ -8,7 +8,11 @@
= render Pajamas::ButtonComponent.new(href: new_project_runner_path(@project), variant: :confirm) do
= s_('Runners|New project runner')
.gl-display-inline
#js-project-runner-registration-dropdown{ data: { registration_token: @project.runners_token, project_id: @project.id } }
#js-project-runner-registration-dropdown{ data: {
allow_registration_token: @project.namespace.allow_runner_registration_token?.to_s,
registration_token: @project.runners_token,
project_id: @project.id
} }
- else
= _('Please contact an admin to create runners.')
= link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
......
......@@ -3553,6 +3553,9 @@ msgstr ""
msgid "AdminSettings|Allow migrating GitLab groups and projects by direct transfer"
msgstr ""
 
msgid "AdminSettings|Allow runner registration token"
msgstr ""
msgid "AdminSettings|Auto DevOps domain"
msgstr ""
 
......@@ -3931,6 +3934,9 @@ msgstr ""
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
 
msgid "AdminSettings|When disabled, runner registration tokens are disabled from runner pages, and maintainers and owners cannot use registration tokens to register runners. They can use runner authentication tokens instead as the more secure runner registration method."
msgstr ""
msgid "AdminSettings|When to delete inactive projects"
msgstr ""
 
......@@ -43527,6 +43533,9 @@ msgstr ""
msgid "Runners|Created by %{user} %{timeAgo}"
msgstr ""
 
msgid "Runners|Creating runners with runner registration tokens is disabled. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "Runners|Creator"
msgstr ""
 
......@@ -43652,9 +43661,6 @@ msgstr ""
msgid "Runners|Idle"
msgstr ""
 
msgid "Runners|If both settings are disabled, new runners cannot be registered."
msgstr ""
msgid "Runners|If you haven't already configured your Google Cloud project, this step enables the required services and creates a service account with the required permissions. "
msgstr ""
 
......@@ -43745,7 +43751,7 @@ msgstr ""
msgid "Runners|Median"
msgstr ""
 
msgid "Runners|Members of the %{type} can register runners"
msgid "Runners|Members of the %{type} can create runners"
msgstr ""
 
msgid "Runners|Minor version upgrades are available."
......@@ -11,8 +11,11 @@
let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
let!(:instance_runner) { create(:ci_runner, :instance) }
let(:runner_registration_enabled) { true }
before do
namespace_settings.update!(runner_registration_enabled: runner_registration_enabled)
sign_in(user)
end
......@@ -76,6 +79,17 @@
expect(assigns(:group_runner_registration_token)).not_to be_nil
expect(assigns(:group_new_runner_path)).to eq(new_group_runner_path(group))
end
context 'when runner registration is disabled' do
let(:runner_registration_enabled) { false }
it 'does not expose runner creation and registration variables' do
execute_get_request
expect(assigns(:group_runner_registration_token)).to be_nil
expect(assigns(:group_new_runner_path)).to be_nil
end
end
end
context 'when user is not maintainer' do
......
......@@ -5,8 +5,11 @@
RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:project_auto_devops) { create(:project_auto_devops) }
let_it_be(:project) { project_auto_devops.project }
let(:project) { project_auto_devops.project }
before_all do
project.namespace.namespace_settings = create(:namespace_settings, allow_runner_registration_token: true)
end
context 'as a maintainer' do
before do
......
......@@ -608,4 +608,14 @@
path { 'gitlab-profile' }
files { { 'README.md' => 'Hello World' } }
end
trait :allow_runner_registration_token do
after :create do |project|
if project.namespace.namespace_settings.nil?
project.namespace.namespace_settings = create(:namespace_settings, namespace: project.namespace)
end
project.namespace.allow_runner_registration_token = true
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment