chef 18.1.0-x64-mingw-ucrt → 18.2.7-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -3
- data/chef-universal-mingw-ucrt.gemspec +2 -2
- data/chef.gemspec +1 -1
- data/distro/powershell/chef/chef.psm1 +459 -0
- data/lib/chef/application/base.rb +18 -2
- data/lib/chef/client.rb +23 -6
- data/lib/chef/http/authenticator.rb +117 -34
- data/lib/chef/platform/query_helpers.rb +4 -2
- data/lib/chef/resource/apt_repository.rb +20 -2
- data/lib/chef/resource/bash.rb +13 -0
- data/lib/chef/resource/dsc_script.rb +1 -1
- data/lib/chef/resource/launchd.rb +2 -2
- data/lib/chef/resource/macos_userdefaults.rb +9 -5
- data/lib/chef/resource/rhsm_register.rb +1 -1
- data/lib/chef/resource/selinux_fcontext.rb +1 -1
- data/lib/chef/resource/selinux_login.rb +129 -0
- data/lib/chef/resource/selinux_permissive.rb +1 -1
- data/lib/chef/resource/selinux_port.rb +1 -1
- data/lib/chef/resource/selinux_state.rb +1 -1
- data/lib/chef/resource/selinux_user.rb +137 -0
- data/lib/chef/resource/service.rb +1 -1
- data/lib/chef/resource/user.rb +2 -2
- data/lib/chef/resource/windows_user_privilege.rb +14 -10
- data/lib/chef/resources.rb +2 -0
- data/lib/chef/version.rb +1 -1
- data/spec/data/trusted_certs/intermediate.pem +38 -27
- data/spec/data/trusted_certs/opscode.pem +33 -54
- data/spec/functional/resource/macos_userdefaults_spec.rb +4 -4
- data/spec/integration/client/client_spec.rb +22 -16
- data/spec/spec_helper.rb +3 -3
- data/spec/unit/client_spec.rb +26 -2
- data/spec/unit/compliance/runner_spec.rb +8 -0
- data/spec/unit/http/authenticator_spec.rb +64 -11
- data/spec/unit/provider/apt_repository_spec.rb +26 -5
- data/spec/unit/resource/macos_user_defaults_spec.rb +4 -4
- data/spec/unit/resource/selinux_login_spec.rb +73 -0
- data/spec/unit/resource/selinux_user_spec.rb +92 -0
- metadata +16 -12
- data/lib/chef/powershell.rb +0 -81
@@ -102,12 +102,12 @@ class Chef
|
|
102
102
|
self.class.get_cert_password
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
106
|
-
self.class.
|
105
|
+
def encrypt_pfx_pass_with_vector
|
106
|
+
self.class.encrypt_pfx_pass_with_vector
|
107
107
|
end
|
108
108
|
|
109
|
-
def
|
110
|
-
self.class.
|
109
|
+
def decrypt_pfx_pass_with_vector
|
110
|
+
self.class.decrypt_pfx_pass_with_vector
|
111
111
|
end
|
112
112
|
|
113
113
|
# Detects if a private key exists in a certificate repository like Keychain (macOS) or Certificate Store (Windows)
|
@@ -123,9 +123,18 @@ class Chef
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
def self.get_cert_user
|
127
|
+
Chef::Config[:auth_key_registry_type] == "user" ? "CurrentUser" : "LocalMachine"
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.get_registry_user
|
131
|
+
Chef::Config[:auth_key_registry_type] == "user" ? "HKEY_CURRENT_USER" : "HKEY_LOCAL_MACHINE"
|
132
|
+
end
|
133
|
+
|
126
134
|
def self.check_certstore_for_key(client_name)
|
135
|
+
store = get_cert_user
|
127
136
|
powershell_code = <<~CODE
|
128
|
-
$cert = Get-ChildItem -path cert
|
137
|
+
$cert = Get-ChildItem -path cert:\\#{store}\\My -Recurse -Force | Where-Object { $_.Subject -Match "chef-#{client_name}" } -ErrorAction Stop
|
129
138
|
if (($cert.HasPrivateKey -eq $true) -and ($cert.PrivateKey.Key.ExportPolicy -ne "NonExportable")) {
|
130
139
|
return $true
|
131
140
|
}
|
@@ -164,49 +173,86 @@ class Chef
|
|
164
173
|
end
|
165
174
|
|
166
175
|
def self.get_cert_password
|
176
|
+
store = get_registry_user
|
167
177
|
@win32registry = Chef::Win32::Registry.new
|
168
|
-
path = "
|
178
|
+
path = "#{store}\\Software\\Progress\\Authentication"
|
169
179
|
# does the registry key even exist?
|
170
|
-
|
171
|
-
|
180
|
+
# password_blob should be an array of hashes
|
181
|
+
password_blob = @win32registry.get_values(path)
|
182
|
+
if password_blob.nil? || password_blob.empty?
|
172
183
|
raise Chef::Exceptions::Win32RegKeyMissing
|
173
184
|
end
|
174
185
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
186
|
+
# Did someone have just the password stored in the registry?
|
187
|
+
raw_data = password_blob.map { |x| x[:data] }
|
188
|
+
vector = raw_data[2]
|
189
|
+
if !!vector
|
190
|
+
decrypted_password = decrypt_pfx_pass_with_vector(password_blob)
|
191
|
+
else
|
192
|
+
decrypted_password = decrypt_pfx_pass_with_password(password_blob)
|
193
|
+
if !!decrypted_password
|
194
|
+
migrate_pass_to_use_vector(decrypted_password)
|
195
|
+
else
|
196
|
+
Chef::Log.error("Failed to retrieve certificate password")
|
179
197
|
end
|
180
198
|
end
|
181
|
-
|
182
|
-
raise Chef::Exceptions::Win32RegKeyMissing
|
183
|
-
|
199
|
+
decrypted_password
|
184
200
|
rescue Chef::Exceptions::Win32RegKeyMissing
|
185
201
|
# if we don't have a password, log that and generate one
|
186
|
-
|
187
|
-
new_path = "
|
202
|
+
store = get_registry_user
|
203
|
+
new_path = "#{store}\\Software\\Progress\\Authentication"
|
188
204
|
unless @win32registry.key_exists?(new_path)
|
189
205
|
@win32registry.create_key(new_path, true)
|
190
206
|
end
|
191
|
-
|
192
|
-
size = 14
|
193
|
-
password = SecureRandom.alphanumeric(size)
|
194
|
-
encrypted_pass = encrypt_pfx_pass(password)
|
195
|
-
values = { name: "PfxPass", type: :string, data: encrypted_pass }
|
196
|
-
@win32registry.set_value(new_path, values)
|
197
|
-
password
|
207
|
+
create_and_store_new_password
|
198
208
|
end
|
199
209
|
|
200
|
-
def self.
|
210
|
+
def self.encrypt_pfx_pass_with_vector(password)
|
201
211
|
powershell_code = <<~CODE
|
202
|
-
$
|
203
|
-
$
|
204
|
-
|
212
|
+
$AES = [System.Security.Cryptography.Aes]::Create()
|
213
|
+
$key_temp = [System.Convert]::ToBase64String($AES.Key)
|
214
|
+
$iv_temp = [System.Convert]::ToBase64String($AES.IV)
|
215
|
+
$encryptor = $AES.CreateEncryptor()
|
216
|
+
[System.Byte[]]$Bytes = [System.Text.Encoding]::Unicode.GetBytes("#{password}")
|
217
|
+
$EncryptedBytes = $encryptor.TransformFinalBlock($Bytes,0,$Bytes.Length)
|
218
|
+
$EncryptedBase64String = [System.Convert]::ToBase64String($EncryptedBytes)
|
219
|
+
# create array of encrypted pass, key, iv
|
220
|
+
$password_blob = @($EncryptedBase64String, $key_temp, $iv_temp)
|
221
|
+
return $password_blob
|
205
222
|
CODE
|
206
223
|
powershell_exec!(powershell_code).result
|
207
224
|
end
|
208
225
|
|
209
|
-
def self.
|
226
|
+
def self.decrypt_pfx_pass_with_vector(password_blob)
|
227
|
+
raw_data = password_blob.map { |x| x[:data] }
|
228
|
+
password = raw_data[0]
|
229
|
+
key = raw_data[1]
|
230
|
+
vector = raw_data[2]
|
231
|
+
|
232
|
+
powershell_code = <<~CODE
|
233
|
+
$KeyBytes = [System.Convert]::FromBase64String("#{key}")
|
234
|
+
$IVBytes = [System.Convert]::FromBase64String("#{vector}")
|
235
|
+
$aes = [System.Security.Cryptography.Aes]::Create()
|
236
|
+
$aes.Key = $KeyBytes
|
237
|
+
$aes.IV = $IVBytes
|
238
|
+
$EncryptedBytes = [System.Convert]::FromBase64String("#{password}")
|
239
|
+
$Decryptor = $aes.CreateDecryptor()
|
240
|
+
$DecryptedBytes = $Decryptor.TransformFinalBlock($EncryptedBytes,0,$EncryptedBytes.Length)
|
241
|
+
$DecryptedString = [System.Text.Encoding]::Unicode.GetString($DecryptedBytes)
|
242
|
+
return $DecryptedString
|
243
|
+
CODE
|
244
|
+
results = powershell_exec!(powershell_code).result
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.decrypt_pfx_pass_with_password(password_blob)
|
248
|
+
password = ""
|
249
|
+
password_blob.each do |secret|
|
250
|
+
if secret[:name] == "PfxPass"
|
251
|
+
password = secret[:data]
|
252
|
+
else
|
253
|
+
Chef::Log.error("Failed to retrieve a password for the private key")
|
254
|
+
end
|
255
|
+
end
|
210
256
|
powershell_code = <<~CODE
|
211
257
|
$secure_string = "#{password}" | ConvertTo-SecureString
|
212
258
|
$string = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((($secure_string))))
|
@@ -215,14 +261,49 @@ class Chef
|
|
215
261
|
powershell_exec!(powershell_code).result
|
216
262
|
end
|
217
263
|
|
218
|
-
def self.
|
219
|
-
|
264
|
+
def self.migrate_pass_to_use_vector(password)
|
265
|
+
store = get_cert_user
|
266
|
+
corrected_store = (store == "CurrentUser" ? "HKCU" : "HKLM")
|
267
|
+
powershell_code = <<~CODE
|
268
|
+
Remove-ItemProperty -Path "#{corrected_store}:\\Software\\Progress\\Authentication" -Name "PfXPass"
|
269
|
+
CODE
|
270
|
+
powershell_exec!(powershell_code)
|
271
|
+
create_and_store_new_password(password)
|
272
|
+
end
|
220
273
|
|
274
|
+
# This method name is a bit of a misnomer. We call it to legit create a new password using the vector format.
|
275
|
+
# But we also call it with a password that needs to be migrated to use the vector format too.
|
276
|
+
def self.create_and_store_new_password(password = nil)
|
277
|
+
@win32registry = Chef::Win32::Registry.new
|
278
|
+
store = get_registry_user
|
279
|
+
path = "#{store}\\Software\\Progress\\Authentication"
|
280
|
+
if password.nil?
|
281
|
+
require "securerandom" unless defined?(SecureRandom)
|
282
|
+
size = 14
|
283
|
+
password = SecureRandom.alphanumeric(size)
|
284
|
+
end
|
285
|
+
encrypted_blob = encrypt_pfx_pass_with_vector(password)
|
286
|
+
encrypted_password = encrypted_blob[0]
|
287
|
+
key = encrypted_blob[1]
|
288
|
+
vector = encrypted_blob[2]
|
289
|
+
values = [
|
290
|
+
{ name: "PfxPass", type: :string, data: encrypted_password },
|
291
|
+
{ name: "PfxKey", type: :string, data: key },
|
292
|
+
{ name: "PfxIV", type: :string, data: vector },
|
293
|
+
]
|
294
|
+
values.each do |i|
|
295
|
+
@win32registry.set_value(path, i)
|
296
|
+
end
|
297
|
+
password
|
298
|
+
end
|
299
|
+
|
300
|
+
def self.retrieve_certificate_key(client_name)
|
221
301
|
if ChefUtils.windows?
|
302
|
+
require "openssl" unless defined?(OpenSSL)
|
222
303
|
password = get_cert_password
|
223
304
|
return false unless password
|
224
305
|
|
225
|
-
if check_certstore_for_key(client_name)
|
306
|
+
if !!check_certstore_for_key(client_name)
|
226
307
|
ps_blob = powershell_exec!(get_the_key_ps(client_name, password)).result
|
227
308
|
file_path = ps_blob["PSPath"].split("::")[1]
|
228
309
|
pkcs = OpenSSL::PKCS12.new(File.binread(file_path), password)
|
@@ -252,10 +333,11 @@ class Chef
|
|
252
333
|
end
|
253
334
|
|
254
335
|
def self.get_the_key_ps(client_name, password)
|
336
|
+
store = get_cert_user
|
255
337
|
powershell_code = <<~CODE
|
256
338
|
Try {
|
257
339
|
$my_pwd = ConvertTo-SecureString -String "#{password}" -Force -AsPlainText;
|
258
|
-
$cert = Get-ChildItem -path cert
|
340
|
+
$cert = Get-ChildItem -path cert:\\#{store}\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } -ErrorAction Stop;
|
259
341
|
$tempfile = [System.IO.Path]::GetTempPath() + "export_pfx.pfx";
|
260
342
|
Export-PfxCertificate -Cert $cert -Password $my_pwd -FilePath $tempfile;
|
261
343
|
}
|
@@ -266,8 +348,9 @@ class Chef
|
|
266
348
|
end
|
267
349
|
|
268
350
|
def self.delete_old_key_ps(client_name)
|
351
|
+
store = get_cert_user
|
269
352
|
powershell_code = <<~CODE
|
270
|
-
Get-ChildItem -path cert
|
353
|
+
Get-ChildItem -path cert:\\#{store}\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } | Remove-Item -ErrorAction Stop;
|
271
354
|
CODE
|
272
355
|
end
|
273
356
|
|
@@ -17,11 +17,14 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require "chef-utils" unless defined?(ChefUtils::CANARY)
|
20
|
+
require_relative "../mixin/powershell_exec"
|
20
21
|
|
21
22
|
class Chef
|
22
23
|
class Platform
|
23
24
|
|
24
25
|
class << self
|
26
|
+
include Chef::Mixin::PowershellExec
|
27
|
+
|
25
28
|
def windows?
|
26
29
|
ChefUtils.windows?
|
27
30
|
end
|
@@ -58,8 +61,7 @@ class Chef
|
|
58
61
|
end
|
59
62
|
|
60
63
|
def dsc_refresh_mode_disabled?(node)
|
61
|
-
|
62
|
-
exec = Chef::PowerShell.new("Get-DscLocalConfigurationManager")
|
64
|
+
exec = powershell_exec!("Get-DscLocalConfigurationManager")
|
63
65
|
exec.error!
|
64
66
|
exec.result["RefreshMode"] == "Disabled"
|
65
67
|
end
|
@@ -187,6 +187,24 @@ class Chef
|
|
187
187
|
end.compact
|
188
188
|
end
|
189
189
|
|
190
|
+
# run the specified command and extract the public key ids
|
191
|
+
# accepts the command so it can be used to extract both the current keys
|
192
|
+
# and the new keys
|
193
|
+
# @param [Array<String>] cmd the command to run
|
194
|
+
#
|
195
|
+
# @return [Array] an array of key ids
|
196
|
+
def extract_public_keys_from_cmd(*cmd)
|
197
|
+
so = shell_out(*cmd)
|
198
|
+
# Sample output
|
199
|
+
# pub:-:4096:1:D94AA3F0EFE21092:1336774248:::-:::scSC::::::23::0:
|
200
|
+
so.stdout.split(/\n/).map do |t|
|
201
|
+
if t.match(/^pub:/)
|
202
|
+
f = t.split(":")
|
203
|
+
f.slice(0, 6).join(":")
|
204
|
+
end
|
205
|
+
end.compact
|
206
|
+
end
|
207
|
+
|
190
208
|
# validate the key against the apt keystore to see if that version is expired
|
191
209
|
# @param [String] key
|
192
210
|
#
|
@@ -222,8 +240,8 @@ class Chef
|
|
222
240
|
def no_new_keys?(file)
|
223
241
|
# Now we are using the option --with-colons that works across old os versions
|
224
242
|
# as well as the latest (16.10). This for both `apt-key` and `gpg` commands
|
225
|
-
installed_keys =
|
226
|
-
proposed_keys =
|
243
|
+
installed_keys = extract_public_keys_from_cmd(*LIST_APT_KEY_FINGERPRINTS)
|
244
|
+
proposed_keys = extract_public_keys_from_cmd("gpg", "--with-fingerprint", "--with-colons", file)
|
227
245
|
(installed_keys & proposed_keys).sort == proposed_keys.sort
|
228
246
|
end
|
229
247
|
|
data/lib/chef/resource/bash.rb
CHANGED
@@ -43,6 +43,19 @@ class Chef
|
|
43
43
|
end
|
44
44
|
```
|
45
45
|
|
46
|
+
**Using escape characters in a string of code**
|
47
|
+
|
48
|
+
In the following example, the `find` command uses an escape character (`\`). Use a second escape character (`\\`) to preserve the escape character in the code string:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
bash 'delete some archives ' do
|
52
|
+
code <<-EOH
|
53
|
+
find ./ -name "*.tar.Z" -mtime +180 -exec rm -f {} \\;
|
54
|
+
EOH
|
55
|
+
ignore_failure true
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
46
59
|
**Install a file from a remote location**
|
47
60
|
|
48
61
|
The following is an example of how to install the foo123 module for Nginx. This module adds shell-style functionality to an Nginx configuration file and does the following:
|
@@ -34,7 +34,7 @@ class Chef
|
|
34
34
|
resource in #{ChefUtils::Dist::Infra::PRODUCT}, such as the Archive resource, a custom DSC resource, an existing DSC script that performs an important
|
35
35
|
task, and so on. Use the dsc_script resource to embed the code that defines a DSC configuration directly within a #{ChefUtils::Dist::Infra::PRODUCT} recipe.
|
36
36
|
|
37
|
-
Warning: The **dsc_script** resource
|
37
|
+
Warning: The **dsc_script** resource is only available on 64-bit Chef Infra Client.
|
38
38
|
DESC
|
39
39
|
|
40
40
|
default_action :run
|
@@ -21,7 +21,7 @@ require_relative "../resource"
|
|
21
21
|
class Chef
|
22
22
|
class Resource
|
23
23
|
class Launchd < Chef::Resource
|
24
|
-
provides :launchd
|
24
|
+
provides :launchd, os: "darwin"
|
25
25
|
|
26
26
|
description "Use the **launchd** resource to manage system-wide services (daemons) and per-user services (agents) on the macOS platform."
|
27
27
|
introduced "12.8"
|
@@ -129,7 +129,7 @@ class Chef
|
|
129
129
|
property :abandon_process_group, [ TrueClass, FalseClass ],
|
130
130
|
description: "If a job dies, all remaining processes with the same process ID may be kept running. Set to true to kill all remaining processes."
|
131
131
|
|
132
|
-
property :associated_bundle_identifiers,
|
132
|
+
property :associated_bundle_identifiers, Array,
|
133
133
|
description: "This optional key indicates which bundles the Login Items Added by Apps panel associates with the helper executable."
|
134
134
|
|
135
135
|
property :debug, [ TrueClass, FalseClass ],
|
@@ -50,15 +50,17 @@ class Chef
|
|
50
50
|
end
|
51
51
|
```
|
52
52
|
|
53
|
-
**
|
53
|
+
**Setting a value for specific user and hosts**
|
54
54
|
|
55
55
|
```ruby
|
56
|
-
macos_userdefaults '
|
57
|
-
key '
|
58
|
-
value
|
59
|
-
|
56
|
+
macos_userdefaults 'Enable macOS firewall' do
|
57
|
+
key 'globalstate'
|
58
|
+
value 1
|
59
|
+
user 'jane'
|
60
|
+
host :current
|
60
61
|
end
|
61
62
|
```
|
63
|
+
|
62
64
|
DOC
|
63
65
|
|
64
66
|
property :domain, String,
|
@@ -79,6 +81,7 @@ class Chef
|
|
79
81
|
|
80
82
|
property :host, [String, Symbol],
|
81
83
|
description: "Set either :current, :all or a hostname to set the user default at the host level.",
|
84
|
+
default: :all,
|
82
85
|
desired_state: false,
|
83
86
|
introduced: "16.3"
|
84
87
|
|
@@ -94,6 +97,7 @@ class Chef
|
|
94
97
|
|
95
98
|
property :user, [String, Symbol],
|
96
99
|
description: "The system user that the default will be applied to. Set :current for current user, :all for all users or pass a valid username",
|
100
|
+
default: :current,
|
97
101
|
desired_state: false
|
98
102
|
|
99
103
|
property :sudo, [TrueClass, FalseClass],
|
@@ -92,7 +92,7 @@ class Chef
|
|
92
92
|
|
93
93
|
property :release,
|
94
94
|
[Float, String],
|
95
|
-
description: "Sets the operating system minor release to use for subscriptions for the system. Products and updates are limited to the specified minor release version. This is used with the `auto_attach`
|
95
|
+
description: "Sets the operating system minor release to use for subscriptions for the system. Products and updates are limited to the specified minor release version. This is used with the `auto_attach` or `activation_key` options. For example, `release '6.4'` will append `--release=6.4` to the register command.",
|
96
96
|
introduced: "17.8"
|
97
97
|
|
98
98
|
action :register, description: "Register the node with RHSM." do
|
@@ -22,7 +22,7 @@ class Chef
|
|
22
22
|
|
23
23
|
provides :selinux_fcontext
|
24
24
|
|
25
|
-
description "Use **selinux_fcontext** resource to set the SELinux context of files
|
25
|
+
description "Use the **selinux_fcontext** resource to set the SELinux context of files using the `semanage fcontext` command."
|
26
26
|
introduced "18.0"
|
27
27
|
examples <<~DOC
|
28
28
|
**Allow http servers (e.g. nginx/apache) to modify moodle files**:
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
|
+
# you may not use this file except in compliance with the License.
|
4
|
+
# You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
# See the License for the specific language governing permissions and
|
12
|
+
# limitations under the License.
|
13
|
+
|
14
|
+
require_relative "../resource"
|
15
|
+
require_relative "selinux/common_helpers"
|
16
|
+
|
17
|
+
class Chef
|
18
|
+
class Resource
|
19
|
+
class SelinuxLogin < Chef::Resource
|
20
|
+
unified_mode true
|
21
|
+
|
22
|
+
provides :selinux_login
|
23
|
+
|
24
|
+
description "Use the **selinux_login** resource to add, update, or remove SELinux user to OS login mappings."
|
25
|
+
introduced "18.1"
|
26
|
+
examples <<~DOC
|
27
|
+
**Manage test OS user mapping with a range of s0 and associated SELinux user test_u**:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
selinux_login 'test' do
|
31
|
+
user 'test_u'
|
32
|
+
range 's0'
|
33
|
+
end
|
34
|
+
```
|
35
|
+
DOC
|
36
|
+
|
37
|
+
property :login, String,
|
38
|
+
name_property: true,
|
39
|
+
description: "An optional property to set the OS user login value if it differs from the resource block's name."
|
40
|
+
|
41
|
+
property :user, String,
|
42
|
+
description: "SELinux user to be mapped."
|
43
|
+
|
44
|
+
property :range, String,
|
45
|
+
description: "MLS/MCS security range for the SELinux user."
|
46
|
+
|
47
|
+
load_current_value do |new_resource|
|
48
|
+
logins = shell_out!("semanage login -l").stdout.split("\n")
|
49
|
+
|
50
|
+
current_login = logins.grep(/^#{Regexp.escape(new_resource.login)}\s+/) do |l|
|
51
|
+
l.match(/^(?<login>[^\s]+)\s+(?<user>[^\s]+)\s+(?<range>[^\s]+)/)
|
52
|
+
# match returns [<Match 'data'>] or [], shift converts that to <Match 'data'> or nil
|
53
|
+
end.shift
|
54
|
+
|
55
|
+
current_value_does_not_exist! unless current_login
|
56
|
+
|
57
|
+
# Existing resources should maintain their current configuration unless otherwise specified
|
58
|
+
new_resource.user ||= current_login[:user]
|
59
|
+
new_resource.range ||= current_login[:range]
|
60
|
+
|
61
|
+
user current_login[:user]
|
62
|
+
range current_login[:range]
|
63
|
+
end
|
64
|
+
|
65
|
+
action_class do
|
66
|
+
include Chef::SELinux::CommonHelpers
|
67
|
+
|
68
|
+
def semanage_login_args
|
69
|
+
# Generate arguments for semanage login -a or -m
|
70
|
+
args = ""
|
71
|
+
|
72
|
+
args += " -s #{new_resource.user}" if new_resource.user
|
73
|
+
args += " -r #{new_resource.range}" if new_resource.range
|
74
|
+
|
75
|
+
args
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
action :manage, description: "Sets the SELinux login mapping to the desired settings regardless of previous state." do
|
80
|
+
run_action(:add)
|
81
|
+
run_action(:modify)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create if doesn't exist, do not touch if user already exists
|
85
|
+
action :add, description: "Creates the SELinux login mapping if not previously created." do
|
86
|
+
raise "The user property must be populated to create a new SELinux login" if new_resource.user.to_s.empty?
|
87
|
+
|
88
|
+
if selinux_disabled?
|
89
|
+
Chef::Log.warn("Unable to add SELinux login #{new_resource.login} as SELinux is disabled")
|
90
|
+
return
|
91
|
+
end
|
92
|
+
|
93
|
+
unless current_resource
|
94
|
+
converge_if_changed do
|
95
|
+
shell_out!("semanage login -a#{semanage_login_args} #{new_resource.login}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Only modify port if it exists & doesn't have the correct context already
|
101
|
+
action :modify, description: "Updates the SELinux login mapping if previously created." do
|
102
|
+
if selinux_disabled?
|
103
|
+
Chef::Log.warn("Unable to modify SELinux login #{new_resource.login} as SELinux is disabled")
|
104
|
+
return
|
105
|
+
end
|
106
|
+
|
107
|
+
if current_resource
|
108
|
+
converge_if_changed do
|
109
|
+
shell_out!("semanage login -m#{semanage_login_args} #{new_resource.login}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Delete if exists
|
115
|
+
action :delete, description: "Removes the SELinux login mapping if previously created." do
|
116
|
+
if selinux_disabled?
|
117
|
+
Chef::Log.warn("Unable to delete SELinux login #{new_resource.login} as SELinux is disabled")
|
118
|
+
return
|
119
|
+
end
|
120
|
+
|
121
|
+
if current_resource
|
122
|
+
converge_by "deleting SELinux login #{new_resource.login}" do
|
123
|
+
shell_out!("semanage login -d #{new_resource.login}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -20,7 +20,7 @@ class Chef
|
|
20
20
|
|
21
21
|
provides :selinux_permissive
|
22
22
|
|
23
|
-
description "Use **selinux_permissive** resource to
|
23
|
+
description "Use the **selinux_permissive** resource to allow some domains to misbehave without stopping them. This is not as good as setting specific policies, but better than disabling SELinux entirely."
|
24
24
|
introduced "18.0"
|
25
25
|
examples <<~DOC
|
26
26
|
**Disable enforcement on Apache**:
|
@@ -21,7 +21,7 @@ class Chef
|
|
21
21
|
|
22
22
|
provides :selinux_port
|
23
23
|
|
24
|
-
description "Use **selinux_port** resource to
|
24
|
+
description "Use the **selinux_port** resource to assign a network port to a specific SELinux context. For example, running a web server on a non-standard port."
|
25
25
|
introduced "18.0"
|
26
26
|
examples <<~DOC
|
27
27
|
**Allow nginx/apache to bind to port 5678 by giving it the http_port_t context**:
|
@@ -56,7 +56,7 @@ class Chef
|
|
56
56
|
|
57
57
|
property :persistent, [true, false],
|
58
58
|
default: true,
|
59
|
-
description: "
|
59
|
+
description: "Set the status update in the SELinux configuration file."
|
60
60
|
|
61
61
|
property :policy, String,
|
62
62
|
default: lazy { default_policy_platform },
|