Skip to content

Commit 0ffda59

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

File tree

4 files changed

+97
-2
lines changed

4 files changed

+97
-2
lines changed

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: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
} else {
26+
$script_ensure = 'absent'
27+
$script_content = undef
28+
}
29+
30+
file { $script_path:
31+
ensure => $script_ensure,
32+
owner => 'root',
33+
group => 'git', # gitlab-rails runner executes this script as 'git' user
34+
mode => '0640',
35+
content => $script_content,
36+
}
37+
-> exec { 'create_initial_root_token':
38+
command => "/usr/bin/gitlab-rails runner '${script_path}'",
39+
creates => $token_file_path,
40+
}
41+
}

spec/classes/init_spec.rb

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
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') }
1517
it { is_expected.to contain_exec('gitlab_reconfigure').that_subscribes_to('Class[gitlab::omnibus_config]') }
1618
it { is_expected.to contain_file('/etc/gitlab/gitlab.rb') }
1719
it { is_expected.to contain_package('gitlab-omnibus').with_ensure('installed').with_name('gitlab-ce') }
@@ -511,6 +513,29 @@
511513
is_expected.to contain_package('gitlab-omnibus').with('ensure' => '16.10.3-ce.0', 'name' => 'gitlab-ce', 'mark' => 'hold')
512514
}
513515
end
516+
describe 'create_intial_root_token' do
517+
let(:params) { { create_initial_root_token: true } }
518+
519+
it do
520+
is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').
521+
with_content(%r{^token_value = 'glpat-' \+ SecureRandom.alphanumeric\(20\)$}).
522+
with_content(%r{^token_ttl_minutes = 60$}).
523+
with_content(%r{^token_file_path = '/etc/gitlab/initial_root_token'$})
524+
end
525+
it { is_expected.to contain_exec('create_initial_root_token').with_creates('/etc/gitlab/initial_root_token') }
526+
527+
describe 'initial_root_token' do
528+
let(:params) { super().merge(initial_root_token: sensitive('foobarbaz')) }
529+
530+
it { is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').with_content(%r{^token_value = 'foobarbaz'$}) }
531+
end
532+
533+
describe 'initial_root_token_ttl_minutes' do
534+
let(:params) { super().merge(initial_root_token_ttl_minutes: 123) }
535+
536+
it { is_expected.to contain_file('/etc/gitlab/create_initial_root_token.rb').with_content(%r{^token_ttl_minutes = 123$}) }
537+
end
538+
end
514539
end
515540
end
516541
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)