Skip to content

Commit 75c74b7

Browse files
committed
feat: implement initial root API token management
1 parent 36caf82 commit 75c74b7

File tree

5 files changed

+134
-2
lines changed

5 files changed

+134
-2
lines changed

REFERENCE.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
### Classes
88

9+
#### Public Classes
10+
911
* [`gitlab`](#gitlab): This module installs and configures Gitlab with the Omnibus package.
1012
* [`gitlab::backup`](#gitlab--backup): This class is called from gitlab for backup config.
1113
* [`gitlab::host_config`](#gitlab--host_config): This class is for setting host configurations required for gitlab installation.
@@ -14,6 +16,10 @@
1416
* [`gitlab::omnibus_package_repository`](#gitlab--omnibus_package_repository): This class is used to configure gitlab repositories
1517
* [`gitlab::service`](#gitlab--service): This class is meant to be called from gitlab. It ensure the service is running.
1618

19+
#### Private Classes
20+
21+
* `gitlab::initial_root_token`: Manages initial root token
22+
1723
### Defined types
1824

1925
* [`gitlab::custom_hook`](#gitlab--custom_hook): Manage custom hook files within a GitLab project.
@@ -129,6 +135,9 @@ The following parameters are available in the `gitlab` class:
129135
* [`pgpass_file_location`](#-gitlab--pgpass_file_location)
130136
* [`pgpass_file_ensure`](#-gitlab--pgpass_file_ensure)
131137
* [`pgbouncer_password`](#-gitlab--pgbouncer_password)
138+
* [`create_initial_root_token`](#-gitlab--create_initial_root_token)
139+
* [`initial_root_token`](#-gitlab--initial_root_token)
140+
* [`initial_root_token_ttl_minutes`](#-gitlab--initial_root_token_ttl_minutes)
132141
* [`consul`](#-gitlab--consul)
133142
* [`custom_hooks_dir`](#-gitlab--custom_hooks_dir)
134143
* [`system_hooks_dir`](#-gitlab--system_hooks_dir)
@@ -919,6 +928,30 @@ Password for the gitlab-consul database user in the pgbouncer database
919928

920929
Default value: `undef`
921930

931+
##### <a name="-gitlab--create_initial_root_token"></a>`create_initial_root_token`
932+
933+
Data type: `Boolean`
934+
935+
Whether to create an initial root token. If set to true and initial_root_token is undef, a random token string will be generated.
936+
937+
Default value: `false`
938+
939+
##### <a name="-gitlab--initial_root_token"></a>`initial_root_token`
940+
941+
Data type: `Optional[Sensitive[String[1]]]`
942+
943+
Preset a root token to allow API usage immediately.
944+
945+
Default value: `undef`
946+
947+
##### <a name="-gitlab--initial_root_token_ttl_minutes"></a>`initial_root_token_ttl_minutes`
948+
949+
Data type: `Integer[0]`
950+
951+
Initial root token time to live (in minutes).
952+
953+
Default value: `60`
954+
922955
##### <a name="-gitlab--consul"></a>`consul`
923956

924957
Data type: `Optional[Hash]`

manifests/init.pp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,17 @@
117117
# @param backup_cron_minute The minute when to run the daily backup cron job
118118
# @param backup_cron_hour The hour when to run the daily backup cron job
119119
# @param backup_cron_skips Array of items to skip valid values: db, uploads, repositories, builds, artifacts, lfs, registry, pages
120-
# @param package_hold Wether to hold the specified package version. Available options are 'hold' or 'none'. Defaults to 'none'. Available only for Debian/Solaris package managers.
120+
# @param package_hold Wether to hold the specified package version. Available options are 'hold' or 'none'. Defaults to 'none'. Available only for Debian/Solaris package managers.
121121
# @param package_name The internal packaging system's name for the package. This name will automatically be changed by the gitlab::edition parameter. Can be overridden for the purposes of installing custom compiled version of gitlab-omnibus.
122122
# @param manage_package Should the GitLab package be managed?
123123
# @param repository_configuration A hash of repository types and attributes for configuraiton the gitlab package repositories. See docs in README.md
124124
# @param manage_omnibus_repository Set to false if you wish to manage gitlab without configuring the package repository
125125
# @param pgpass_file_location Path to location of .pgpass file used by consul to authenticate with pgbouncer database
126126
# @param pgpass_file_ensure Create .pgpass file for pgbouncer authentication. When set to present requires valid value for pgbouncer_password.
127127
# @param pgbouncer_password Password for the gitlab-consul database user in the pgbouncer database
128+
# @param create_initial_root_token Whether to create an initial root token. If set to true and initial_root_token is undef, a random token string will be generated.
129+
# @param initial_root_token Preset a root token to allow API usage immediately.
130+
# @param initial_root_token_ttl_minutes Initial root token time to live (in minutes).
128131
class gitlab (
129132
Hash $repository_configuration,
130133
# package configuration
@@ -224,6 +227,9 @@
224227
Optional[Hash] $gitlab_workhorse = undef,
225228
Optional[Hash] $user = undef,
226229
Optional[Hash] $web_server = undef,
230+
Boolean $create_initial_root_token = false,
231+
Optional[Sensitive[String[1]]] $initial_root_token = undef,
232+
Integer[0] $initial_root_token_ttl_minutes = 60,
227233
Boolean $backup_cron_enable = false,
228234
Integer[0,59] $backup_cron_minute = 0,
229235
Integer[0,23] $backup_cron_hour = 2,
@@ -238,11 +244,13 @@
238244
contain gitlab::omnibus_config
239245
contain gitlab::install
240246
contain gitlab::service
247+
contain gitlab::initial_root_token
241248

242249
Class['gitlab::host_config']
243250
-> Class['gitlab::omnibus_config']
244251
-> Class['gitlab::install']
245252
-> Class['gitlab::service']
253+
-> Class['gitlab::initial_root_token']
246254

247255
$custom_hooks.each |$name, $options| {
248256
gitlab::custom_hook { $name:

manifests/initial_root_token.pp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# @summary Manages initial root token
2+
#
3+
# **NOTE** This hack allows to use the gitlab instance via API immediately.
4+
# While this way is quite convenient, it cannot be called a good one..
5+
# Use it at your own risk!
6+
#
7+
# Remove the /etc/gitlab/initial_root_token file to regenerate the token in a
8+
# next Puppet run.
9+
#
10+
# @see https://docs.gitlab.com/administration/operations/rails_console/#using-the-rails-runner
11+
# @see https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token-programmatically
12+
#
13+
# @api private
14+
class gitlab::initial_root_token {
15+
$token_file_path = '/etc/gitlab/initial_root_token'
16+
$script_path = '/etc/gitlab/create_initial_root_token.rb'
17+
18+
if $gitlab::create_initial_root_token {
19+
$script_ensure = 'file'
20+
$script_content = epp('gitlab/create_initial_root_token.rb.epp',
21+
token => $gitlab::initial_root_token,
22+
token_ttl_minutes => $gitlab::initial_root_token_ttl_minutes,
23+
token_file_path => $token_file_path,
24+
)
25+
26+
# Execute after the script is created, but only if token is managed
27+
exec { 'create_initial_root_token':
28+
command => "/usr/bin/gitlab-rails runner '${script_path}'",
29+
creates => $token_file_path,
30+
require => File[$script_path],
31+
}
32+
} else {
33+
$script_ensure = 'absent'
34+
$script_content = undef
35+
}
36+
37+
file { $script_path:
38+
ensure => $script_ensure,
39+
owner => 'root',
40+
group => 'git', # gitlab-rails runner executes this script as 'git' user
41+
mode => '0640',
42+
content => $script_content,
43+
}
44+
}

spec/classes/init_spec.rb

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
it { is_expected.to contain_class('gitlab::host_config').that_comes_before('Class[gitlab::install]') }
1212
it { is_expected.to contain_class('gitlab::omnibus_config').that_comes_before('Class[gitlab::install]') }
1313
it { is_expected.to contain_class('gitlab::install').that_comes_before('Class[gitlab::service]') }
14-
it { is_expected.to contain_class('gitlab::service') }
14+
it { is_expected.to contain_class('gitlab::service').that_comes_before('Class[gitlab::initial_root_token]') }
15+
it { is_expected.to contain_class('gitlab::initial_root_token') }
16+
it { is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').with_ensure('absent') }
17+
it { is_expected.not_to contain_exec('create_initial_root_token') }
1518
it { is_expected.to contain_exec('gitlab_reconfigure').that_subscribes_to('Class[gitlab::omnibus_config]') }
1619
it { is_expected.to contain_file('/etc/gitlab/gitlab.rb') }
1720
it { is_expected.to contain_package('gitlab-omnibus').with_ensure('installed').with_name('gitlab-ce') }
@@ -511,6 +514,29 @@
511514
is_expected.to contain_package('gitlab-omnibus').with('ensure' => '16.10.3-ce.0', 'name' => 'gitlab-ce', 'mark' => 'hold')
512515
}
513516
end
517+
describe 'create_intial_root_token' do
518+
let(:params) { { create_initial_root_token: true } }
519+
520+
it do
521+
is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').
522+
with_content(%r{^token_value = 'glpat-' \+ SecureRandom.alphanumeric\(20\)$}).
523+
with_content(%r{^token_ttl_minutes = 60$}).
524+
with_content(%r{^token_file_path = '/etc/gitlab/initial_root_token'$})
525+
end
526+
it { is_expected.to contain_exec('create_initial_root_token').with_creates('/etc/gitlab/initial_root_token') }
527+
528+
describe 'initial_root_token' do
529+
let(:params) { super().merge(initial_root_token: sensitive('foobarbaz')) }
530+
531+
it { is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').with_content(%r{^token_value = 'foobarbaz'$}) }
532+
end
533+
534+
describe 'initial_root_token_ttl_minutes' do
535+
let(:params) { super().merge(initial_root_token_ttl_minutes: 123) }
536+
537+
it { is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').with_content(%r{^token_ttl_minutes = 123$}) }
538+
end
539+
end
514540
end
515541
end
516542
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<%-|
2+
Optional[Sensitive[String[1]]] $token,
3+
Integer[0] $token_ttl_minutes,
4+
Stdlib::AbsolutePath $token_file_path,
5+
|-%>
6+
# This scripts creates an initial root token and stores it to the
7+
# $token_file_path file.
8+
require 'securerandom'
9+
10+
token_value = <%= $token.then |$x| { "'${$x.unwrap}'" }.lest || { "'glpat-' + SecureRandom.alphanumeric(20)" } %>
11+
token_ttl_minutes = <%= $token_ttl_minutes %>
12+
token_file_path = '<%= $token_file_path %>'
13+
14+
t = User.find(1).personal_access_tokens.create(
15+
scopes: [:api],
16+
name: 'Gitlab Puppet module initial root token',
17+
expires_at: token_ttl_minutes.minutes.from_now,
18+
)
19+
t.set_token(token_value)
20+
t.save!
21+
File.write(token_file_path, token_value)

0 commit comments

Comments
 (0)