Skip to content

Commit 2636d3f

Browse files
author
Johan De Wit
committed
Add x509 authentication support for admin user
1 parent 97f1c14 commit 2636d3f

File tree

17 files changed

+308
-280
lines changed

17 files changed

+308
-280
lines changed

Diff for: REFERENCE.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ The following parameters are available in the `mongodb::server` class:
13091309
* [`admin_username`](#-mongodb--server--admin_username)
13101310
* [`admin_password`](#-mongodb--server--admin_password)
13111311
* [`admin_auth_mechanism`](#-mongodb--server--admin_auth_mechanism)
1312+
* [`admin_tls_key`](#-mongodb--server--admin_tls_key)
13121313
* [`admin_update_password`](#-mongodb--server--admin_update_password)
13131314
* [`admin_roles`](#-mongodb--server--admin_roles)
13141315
* [`handle_creds`](#-mongodb--server--handle_creds)
@@ -2026,12 +2027,20 @@ Default value: `undef`
20262027

20272028
##### <a name="-mongodb--server--admin_auth_mechanism"></a>`admin_auth_mechanism`
20282029

2029-
Data type: `Enum['scram_sha_1', 'scram_sha_256']`
2030+
Data type: `Enum['scram_sha_1', 'scram_sha_256', 'x509']`
20302031

20312032
Administrator authentication mechanism. scram_sha_256 password synchronization verification is not supported.
20322033

20332034
Default value: `$mongodb::params::admin_auth_mechanism`
20342035

2036+
##### <a name="-mongodb--server--admin_tls_key"></a>`admin_tls_key`
2037+
2038+
Data type: `Optional[Stdlib::Absolutepath]`
2039+
2040+
Filepath of the administrators x509 certificate. Its the user of this class that needs to manage this certificate.
2041+
2042+
Default value: `undef`
2043+
20352044
##### <a name="-mongodb--server--admin_update_password"></a>`admin_update_password`
20362045

20372046
Data type: `Boolean`
@@ -2137,7 +2146,7 @@ Database username.
21372146

21382147
##### <a name="-mongodb--db--auth_mechanism"></a>`auth_mechanism`
21392148

2140-
Data type: `Enum['scram_sha_1', 'scram_sha_256']`
2149+
Data type: `Enum['scram_sha_1', 'scram_sha_256', 'x509']`
21412150

21422151
- Authentication mechanism. scram_sha_256 password verification is not supported. Defaults to 'scram_sha_1'.
21432152

@@ -2455,7 +2464,7 @@ The following parameters are available in the `mongodb_user` type.
24552464

24562465
##### <a name="-mongodb_user--auth_mechanism"></a>`auth_mechanism`
24572466

2458-
Valid values: `scram_sha_256`, `scram_sha_1`
2467+
Valid values: `scram_sha_256`, `scram_sha_1`, `x509`
24592468

24602469
Authentication mechanism. Password verification is not supported with SCRAM-SHA-256.
24612470

Diff for: lib/facter/is_master.rb

+24-37
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,23 @@ def mongod_conf_file
88
locations.find { |location| File.exist? location }
99
end
1010

11+
def mongosh_conf_file
12+
'/root/.mongosh.yaml' if File.exist?('/root/mongosh.yaml')
13+
end
14+
1115
def get_options_from_hash_config(config)
16+
# read also the mongoshrc.yaml yaml file, to retrieve the admins certkey file
17+
if mongosh_conf_file
18+
mongosh_config = YAML.load_file(mongosh_conf_file)
19+
# check which tlscert we need to use
20+
tlscert = if config['setParameter'] && config['setParameter']['authenticationMechanisms'] == 'MONGODB-X509' &&
21+
mongosh_config['admin'] && mongosh_config['admin']['tlsCertificateKeyFile']
22+
mongosh_config['admin']['tlsCertificateKeyFile']
23+
end
24+
else
25+
tlscert = config['net.tls.certificateKeyFile']
26+
end
27+
1228
result = []
1329

1430
result << "--port #{config['net.port']}" unless config['net.port'].nil?
@@ -23,52 +39,23 @@ def get_options_from_hash_config(config)
2339
# - tlsMode is "requireTLS"
2440
# - Parameter --tlsCertificateKeyFile is set
2541
# - Parameter --tlsCAFile is set
26-
result << "--tls --host #{Facter.value(:fqdn)}" if config['net.tls.mode'] == 'requireTLS' || !config['net.tls.certificateKeyFile'].nil? || !config['net.tls.CAFile'].nil?
27-
result << "--tlsCertificateKeyFile #{config['net.tls.certificateKeyFile']}" unless config['net.tls.certificateKeyFile'].nil?
42+
result << "--tls --host #{Facter.value(:fqdn)}" if config['net.tls.mode'] == 'requireTLS' || !tlscert.nil? || !config['net.tls.CAFile'].nil?
43+
result << "--tlsCertificateKeyFile #{tlscert}" unless tlscert.nil?
2844
result << "--tlsCAFile #{config['net.tls.CAFile']}" unless config['net.tls.CAFile'].nil?
2945

30-
result << '--ipv6' unless config['net.ipv6'].nil?
31-
32-
result.join(' ')
33-
end
34-
35-
def get_options_from_keyvalue_config(file)
36-
config = {}
37-
File.readlines(file).map do |line|
38-
k, v = line.split('=')
39-
config[k.rstrip] = v.lstrip.chomp if k && v
40-
end
41-
42-
result = []
46+
# use --authenticationMechanism, ---authenticationDatabase
47+
# when
48+
# - authenticationMechanism MONGODB-X509
49+
result << "--authenticationDatabase '$external' --authenticationMechanism MONGODB-X509" unless config['setParameter'].nil? || config['setParameter']['authenticationMechanisms'] != 'MONGODB-X509'
4350

44-
result << "--port #{config['port']}" unless config['port'].nil?
45-
# use --ssl and --host if:
46-
# - sslMode is "requireSSL"
47-
# - Parameter --sslPEMKeyFile is set
48-
# - Parameter --sslCAFile is set
49-
result << "--ssl --host #{Facter.value(:fqdn)}" if config['ssl'] == 'requireSSL' || !config['sslcert'].nil? || !config['sslca'].nil?
50-
result << "--sslPEMKeyFile #{config['sslcert']}" unless config['sslcert'].nil?
51-
result << "--sslCAFile #{config['sslca']}" unless config['sslca'].nil?
52-
# use --tls and --host if:
53-
# - tlsMode is "requireTLS"
54-
# - Parameter --tlsCertificateKeyFile is set
55-
# - Parameter --tlsCAFile is set
56-
result << "--tls --host #{Facter.value(:fqdn)}" if config['tls'] == 'requireTLS' || !config['tlscert'].nil? || !config['tlsca'].nil?
57-
result << "--tlsCertificateKeyFile #{config['tlscert']}" unless config['tlscert'].nil?
58-
result << "--tlsCAFile #{config['tlsca']}" unless config['tlsca'].nil?
59-
60-
result << '--ipv6' unless config['ipv6'].nil?
51+
result << '--ipv6' unless config['net.ipv6'].nil?
6152

6253
result.join(' ')
6354
end
6455

6556
def get_options_from_config(file)
6657
config = YAML.load_file(file)
67-
if config.is_a?(Hash) # Using a valid YAML file for mongo 2.6
68-
get_options_from_hash_config(config)
69-
else # It has to be a key-value config file
70-
get_options_from_keyvalue_config(file)
71-
end
58+
get_options_from_hash_config(config)
7259
end
7360

7461
Facter.add('mongodb_is_master') do

Diff for: lib/puppet/provider/mongodb.rb

+14-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ def self.mongod_conf_file
2929

3030
def self.mongo_conf
3131
config = YAML.load_file(mongod_conf_file) || {}
32+
mongosh_config = {}
33+
mongosh_config = YAML.load_file("#{Facter.value(:root_home)}/.mongosh.yaml") if File.file?("#{Facter.value(:root_home)}/.mongosh.yaml")
34+
# determine if we need the tls for connecion or client
35+
tlscert = if config['setParameter'] && config['setParameter']['authenticationMechanisms'] == 'MONGODB-X509'
36+
if mongosh_config['admin'] && mongosh_config['admin']['tlsCertificateKeyFile']
37+
mongosh_config['admin']['tlsCertificateKeyFile']
38+
else
39+
config['net.tls.certificateKeyFile']
40+
end
41+
end
42+
3243
{
3344
'bindip' => config['net.bindIp'],
3445
'port' => config['net.port'],
@@ -39,7 +50,7 @@ def self.mongo_conf
3950
'sslca' => config['net.ssl.CAFile'],
4051
'tlsallowInvalidHostnames' => config['net.tls.allowInvalidHostnames'],
4152
'tls' => config['net.tls.mode'],
42-
'tlscert' => config['net.tls.certificateKeyFile'],
53+
'tlscert' => tlscert,
4354
'tlsca' => config['net.tls.CAFile'],
4455
'auth' => config['security.authorization'],
4556
'shardsvr' => config['sharding.clusterRole'],
@@ -92,15 +103,15 @@ def self.mongosh_cmd(db, host, cmd)
92103

93104
if tls_is_enabled(config)
94105
args.push('--tls')
95-
args += ['--tlsCertificateKeyFile', config['tlscert']]
96106

97107
tls_ca = config['tlsca']
98108
args += ['--tlsCAFile', tls_ca] unless tls_ca.nil?
109+
args += ['--tlsCertificateKeyFile', config['tlscert']]
99110

100111
args.push('--tlsAllowInvalidHostnames') if tls_invalid_hostnames(config)
101112
end
102113

103-
args += ['--eval', cmd]
114+
args += ['--eval', "\"#{cmd}\""]
104115
mongosh(args)
105116
end
106117

Diff for: lib/puppet/provider/mongodb_user/mongodb.rb

+10-6
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,22 @@ def create
6060

6161
# is this still needed / we only support verion 4 and higher
6262
if mongo_4? || mongo_5? || mongo_6?
63-
if @resource[:auth_mechanism] == :scram_sha_256 # rubocop:disable Naming/VariableNumber
63+
case @resource[:auth_mechanism]
64+
when :scram_sha_256 # rubocop:disable Naming/VariableNumber
6465
command[:mechanisms] = ['SCRAM-SHA-256']
6566
command[:pwd] = @resource[:password]
6667
command[:digestPassword] = true
67-
else
68+
when :scram_sha_1 # rubocop:disable Naming/VariableNumber
6869
command[:mechanisms] = ['SCRAM-SHA-1']
6970
command[:pwd] = password_hash
7071
command[:digestPassword] = false
72+
when :x509
73+
command[:mechanisms] = ['MONGODB-X509']
74+
else
75+
command[:pwd] = password_hash
76+
command[:digestPassword] = false
77+
7178
end
72-
else
73-
command[:pwd] = password_hash
74-
command[:digestPassword] = false
7579
end
7680

7781
mongo_eval("db.runCommand(#{command.to_json})", @resource[:database])
@@ -120,7 +124,7 @@ def password=(value)
120124
digestPassword: true
121125
}
122126

123-
if mongo_4? || mongo_5?
127+
if mongo_4? || mongo_5? || mongo_6?
124128
command[:mechanisms] = @resource[:auth_mechanism] == :scram_sha_256 ? ['SCRAM-SHA-256'] : ['SCRAM-SHA-1'] # rubocop:disable Naming/VariableNumber
125129
end
126130

Diff for: lib/puppet/type/mongodb_user.rb

+10-8
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def to_s?(value)
5757
newproperty(:password_hash) do
5858
desc 'The password hash of the user. Use mongodb_password() for creating hash. Only available on MongoDB 3.0 and later. SCRAM-SHA-256 authentication mechanism is not supported.'
5959
defaultto do
60-
raise Puppet::Error, "Property 'password_hash' must be set. Use mongodb_password() for creating hash." if @resource[:password].nil? && (provider.database == :absent)
60+
raise Puppet::Error, "Property 'password_hash' must be set. Use mongodb_password() for creating hash." if @resource[:auth_mechanism] != :x509 && @resource[:password].nil? && (@resource[:password].nil? && (provider.database == :absent))
6161
end
6262
newvalue(%r{^\w+$})
6363

@@ -97,7 +97,7 @@ def insync?(_is)
9797
newparam(:auth_mechanism) do
9898
desc 'Authentication mechanism. Password verification is not supported with SCRAM-SHA-256.'
9999
defaultto :scram_sha_1 # rubocop:disable Naming/VariableNumber
100-
newvalues(:scram_sha_256, :scram_sha_1) # rubocop:disable Naming/VariableNumber
100+
newvalues(:scram_sha_256, :scram_sha_1, :x509) # rubocop:disable Naming/VariableNumber
101101
end
102102

103103
newparam(:update_password, boolean: true) do
@@ -122,12 +122,14 @@ def insync?(_is)
122122
end
123123

124124
validate do
125-
if self[:password_hash].nil? && self[:password].nil? && provider.password.nil? && provider.password_hash.nil?
126-
err("Either 'password_hash' or 'password' should be provided")
127-
elsif !self[:password_hash].nil? && !self[:password].nil?
128-
err("Only one of 'password_hash' or 'password' should be provided")
129-
elsif !self[:password_hash].nil? && self[:auth_mechanism] == :scram_sha_256 # rubocop:disable Naming/VariableNumber
130-
err("'password_hash' is not supported with SCRAM-SHA-256 authentication mechanism")
125+
if self[:auth_mechanism] != :x509
126+
if self[:password_hash].nil? && self[:password].nil? && provider.password.nil? && provider.password_hash.nil?
127+
err("Either 'password_hash' or 'password' should be provided")
128+
elsif !self[:password_hash].nil? && !self[:password].nil?
129+
err("Only one of 'password_hash' or 'password' should be provided")
130+
elsif !self[:password_hash].nil? && self[:auth_mechanism] == :scram_sha_256 # rubocop:disable Naming/VariableNumber
131+
err("'password_hash' is not supported with SCRAM-SHA-256 authentication mechanism")
132+
end
131133
end
132134
raise("The parameter 'scram_credentials' is read-only and cannot be changed") if should(:scram_credentials)
133135
end

Diff for: manifests/db.pp

+21-17
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#
2020
define mongodb::db (
2121
String $user,
22-
Enum['scram_sha_1', 'scram_sha_256'] $auth_mechanism = 'scram_sha_1',
22+
Enum['scram_sha_1', 'scram_sha_256', 'x509'] $auth_mechanism = 'scram_sha_1',
2323
String $db_name = $name,
2424
Optional[Variant[String[1], Sensitive[String[1]]]] $password_hash = undef,
2525
Optional[Variant[String[1], Sensitive[String[1]]]] $password = undef,
@@ -33,25 +33,29 @@
3333
tries => $tries,
3434
}
3535

36-
if $password_hash =~ Sensitive[String] {
37-
$hash = $password_hash.unwrap
38-
} elsif $password_hash {
39-
$hash = $password_hash
40-
} elsif $password {
41-
$hash = mongodb_password($user, $password)
42-
} else {
43-
fail("Parameter 'password_hash' or 'password' should be provided to mongodb::db.")
44-
}
36+
if $auth_mechanism != 'x509' {
37+
if $password_hash =~ Sensitive[String] {
38+
$hash = $password_hash.unwrap
39+
} elsif $password_hash {
40+
$hash = $password_hash
41+
} elsif $password {
42+
$hash = mongodb_password($user, $password)
43+
} else {
44+
fail("Parameter 'password_hash' or 'password' should be provided to mongodb::db.")
45+
}
4546

46-
if $auth_mechanism == 'scram_sha_256' {
47-
$password_config = {
48-
password => $password,
49-
update_password => $update_password,
47+
if $auth_mechanism == 'scram_sha_256' {
48+
$password_config = {
49+
password => $password,
50+
update_password => $update_password,
51+
}
52+
} else {
53+
$password_config = {
54+
password_hash => $hash,
55+
}
5056
}
5157
} else {
52-
$password_config = {
53-
password_hash => $hash,
54-
}
58+
$password_config = {}
5559
}
5660

5761
mongodb_user { "User ${user} on db ${db_name}":

Diff for: manifests/mongos/params.pp

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@
55
$version = $mongodb::globals::version
66

77
$package_ensure = pick($version, 'present')
8-
if $manage_package {
9-
$package_name = "mongodb-${mongodb::globals::edition}-mongos"
10-
} elsif $facts['os']['family'] in ['RedHat', 'Suse'] {
11-
$package_name = "mongodb-${mongodb::globals::edition}-mongos"
12-
} else {
13-
$package_name = 'mongodb-server'
14-
}
8+
# from versoin 4.4 on, package name is all the same in the upstream repositories
9+
$package_name = "mongodb-${mongodb::globals::edition}-mongos"
1510

1611
$config_content = undef
1712
$config_template = undef

Diff for: manifests/params.pp

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
$manage_package = pick($mongodb::globals::manage_package, $mongodb::globals::manage_package_repo, false)
2828
$pidfilemode = pick($mongodb::globals::pidfilemode, '0644')
2929
$manage_pidfile = pick($mongodb::globals::manage_pidfile, true)
30-
3130
$version = $mongodb::globals::version
3231

3332
$config_data = undef

0 commit comments

Comments
 (0)