Skip to content

Commit 1499d2a

Browse files
author
Johan De Wit
committed
[x509] Add x509 support for admin user
* use x509 autentication method for admin user, used to login in the api. * add supported_athentication_mechanisms, whish restricts the suppported authentication mechanism supported by the server.
1 parent 7af3388 commit 1499d2a

File tree

17 files changed

+310
-285
lines changed

17 files changed

+310
-285
lines changed

REFERENCE.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,7 @@ The following parameters are available in the `mongodb::server` class:
12631263
* [`admin_username`](#-mongodb--server--admin_username)
12641264
* [`admin_password`](#-mongodb--server--admin_password)
12651265
* [`admin_auth_mechanism`](#-mongodb--server--admin_auth_mechanism)
1266+
* [`admin_tls_key`](#-mongodb--server--admin_tls_key)
12661267
* [`admin_update_password`](#-mongodb--server--admin_update_password)
12671268
* [`handle_creds`](#-mongodb--server--handle_creds)
12681269
* [`store_creds`](#-mongodb--server--store_creds)
@@ -1934,12 +1935,20 @@ Default value: `undef`
19341935

19351936
##### <a name="-mongodb--server--admin_auth_mechanism"></a>`admin_auth_mechanism`
19361937

1937-
Data type: `Enum['scram_sha_1', 'scram_sha_256']`
1938+
Data type: `Enum['scram_sha_1', 'scram_sha_256', 'x509']`
19381939

19391940

19401941

19411942
Default value: `$mongodb::params::admin_auth_mechanism`
19421943

1944+
##### <a name="-mongodb--server--admin_tls_key"></a>`admin_tls_key`
1945+
1946+
Data type: `Optional[Stdlib::Absolutepath]`
1947+
1948+
Filepath of the administrators x509 certificate. Its the user of this class that needs to manage this certificate.
1949+
1950+
Default value: `undef`
1951+
19431952
##### <a name="-mongodb--server--admin_update_password"></a>`admin_update_password`
19441953

19451954
Data type: `Boolean`
@@ -2042,7 +2051,7 @@ Data type: `String`
20422051

20432052
##### <a name="-mongodb--db--auth_mechanism"></a>`auth_mechanism`
20442053

2045-
Data type: `Enum['scram_sha_1', 'scram_sha_256']`
2054+
Data type: `Enum['scram_sha_1', 'scram_sha_256', 'x509']`
20462055

20472056

20482057

@@ -2360,7 +2369,7 @@ The following parameters are available in the `mongodb_user` type.
23602369

23612370
##### <a name="-mongodb_user--auth_mechanism"></a>`auth_mechanism`
23622371

2363-
Valid values: `scram_sha_256`, `scram_sha_1`
2372+
Valid values: `scram_sha_256`, `scram_sha_1`, `x509`
23642373

23652374
Authentication mechanism. Password verification is not supported with SCRAM-SHA-256.
23662375

lib/facter/is_master.rb

Lines changed: 24 additions & 37 deletions
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+
if mongosh_config['admin']
21+
tlscert = mongosh_config['admin']['tlsCertificateKeyFile'] if mongosh_config['admin']['tlsCertificateKeyFile']
22+
auth_mech = mongosh_config['admin']['auth_mechanism'] if mongosh_config['admin']['auth_mechanism']
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 = []
43-
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?
46+
# use --authenticationMechanism, ---authenticationDatabase
47+
# when
48+
# - authenticationMechanism MONGODB-X509
49+
result << "--authenticationDatabase '$external' --authenticationMechanism MONGODB-X509" if auth_mech && auth_mech == 'x509'
5950

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

lib/puppet/provider/mongodb.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ 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+
if mongosh_config['admin'] && mongosh_config['admin']['tlsCertificateKeyFile']
36+
tlscert = mongosh_config['admin']['tlsCertificateKeyFile']
37+
auth_mech = mongosh_config['admin']['auth_mechanism'] if mongosh_config['admin']['auth_mechanism']
38+
else
39+
tlscert =config['net.tls.certificateKeyFile']
40+
end
41+
3242
{
3343
'bindip' => config['net.bindIp'],
3444
'port' => config['net.port'],
@@ -39,9 +49,10 @@ def self.mongo_conf
3949
'sslca' => config['net.ssl.CAFile'],
4050
'tlsallowInvalidHostnames' => config['net.tls.allowInvalidHostnames'],
4151
'tls' => config['net.tls.mode'],
42-
'tlscert' => config['net.tls.certificateKeyFile'],
52+
'tlscert' => tlscert,
4353
'tlsca' => config['net.tls.CAFile'],
4454
'auth' => config['security.authorization'],
55+
'auth_mechanism' => auth_mech,
4556
'shardsvr' => config['sharding.clusterRole'],
4657
'confsvr' => config['sharding.clusterRole']
4758
}
@@ -92,15 +103,19 @@ 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+
if $config['auth_mechanism'] && $config['auth_mechanism'] == 'x509'
115+
args.push("--authenticationDatabase '$external' --authenticationMechanism MONGODB-X509")
116+
end
117+
118+
args += ['--eval', "\"#{cmd}\""]
104119
mongosh(args)
105120
end
106121

lib/puppet/provider/mongodb_user/mongodb.rb

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ def self.instances
1919

2020
users = JSON.parse out
2121

22+
Puppet.debug("XXXXXXXX In self.instances, retrieved users: #{users}")
23+
2224
users.map do |user|
2325
db = if user['db'] == '$external'
2426
# For external users, we need to retreive the original DB name from here.
@@ -29,10 +31,12 @@ def self.instances
2931
u = new(name: user['_id'],
3032
ensure: :present,
3133
username: user['user'],
32-
database: user['db'],
33-
roles: from_roles(user['roles'], user['db']),
34+
database: db,
35+
roles: from_roles(user['roles'], db),
3436
password_hash: user['credentials']['MONGODB-CR'],
3537
scram_credentials: user['credentials']['SCRAM-SHA-1'])
38+
Puppet.debug("Fetching users, creating the found resources: #{u}")
39+
u
3640
end
3741
else
3842
Puppet.warning 'User info is available only from master host'
@@ -56,6 +60,7 @@ def create
5660
password_hash = @resource[:password_hash]
5761
password_hash = Puppet::Util::MongodbMd5er.md5(@resource[:username], @resource[:password]) if !password_hash && @resource[:password]
5862

63+
5964
command = {
6065
createUser: @resource[:username],
6166
customData: {
@@ -64,17 +69,17 @@ def create
6469
roles: role_hashes(@resource[:roles], @resource[:database]),
6570
}
6671

67-
# is this still needed / we only support verion 4 and higher
68-
if mongo_4? || mongo_5? || mongo_6?
69-
if @resource[:auth_mechanism] == :scram_sha_256
70-
command[:mechanisms] = ['SCRAM-SHA-256']
71-
command[:pwd] = @resource[:password]
72-
command[:digestPassword] = true
73-
else
74-
command[:mechanisms] = ['SCRAM-SHA-1']
75-
command[:pwd] = password_hash
76-
command[:digestPassword] = false
77-
end
72+
case @resource[:auth_mechanism]
73+
when :scram_sha_256 # rubocop:disable Naming/VariableNumber
74+
command[:mechanisms] = ['SCRAM-SHA-256']
75+
command[:pwd] = @resource[:password]
76+
command[:digestPassword] = true
77+
when :scram_sha_1 # rubocop:disable Naming/VariableNumber
78+
command[:mechanisms] = ['SCRAM-SHA-1']
79+
command[:pwd] = password_hash
80+
command[:digestPassword] = false
81+
when :x509
82+
command[:mechanisms] = ['MONGODB-X509']
7883
else
7984
command[:pwd] = password_hash
8085
command[:digestPassword] = false
@@ -93,6 +98,9 @@ def create
9398
@property_hash[:roles] = @resource[:roles]
9499

95100
exists?
101+
102+
else
103+
Puppet.warning 'User creation is available only from master host'
96104
end
97105
end
98106

lib/puppet/type/mongodb_user.rb

Lines changed: 10 additions & 8 deletions
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
100-
newvalues(:scram_sha_256, :scram_sha_1)
100+
newvalues(:scram_sha_256, :scram_sha_1, :x509)
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
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
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

manifests/db.pp

Lines changed: 21 additions & 17 deletions
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}":

manifests/mongos/params.pp

Lines changed: 2 additions & 7 deletions
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

manifests/params.pp

Lines changed: 0 additions & 1 deletion
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)