foreman_vault 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/concerns/foreman_vault/orchestration/vault_policy.rb +1 -5
- data/app/models/setting/vault.rb +19 -1
- data/app/services/foreman_vault/vault_auth_method.rb +2 -2
- data/app/views/unattended/provisioning_templates/VaultPolicy/default.erb +3 -3
- data/lib/foreman_vault/version.rb +1 -1
- data/lib/tasks/foreman_vault_tasks.rake +44 -1
- data/test/lib/tasks/push_auth_methods_test.rb +49 -0
- data/test/lib/tasks/push_policies_test.rb +49 -0
- data/test/models/foreman_vault/orchestration/vault_policy_test.rb +25 -12
- data/test/unit/services/foreman_vault/vault_auth_method_test.rb +2 -15
- data/test/unit/services/foreman_vault/vault_policy_test.rb +5 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39553e728b4ff3661a8b0fc008ee0959e5fdbba5f915a9f7f9d09bdd24d9d65a
|
4
|
+
data.tar.gz: 34b06a3ffc2cfdd6055356c4af15e91bb7d94de7954983d0becc20881c85fef3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04fe38f150fb63017eeb3803c14ea02fe6eb557a8a51d13f7f089bc4a7e5ca12f08182ede2c642e5dd6b47d5ab53e5adcc80e45117ad714ad6154cec2df486de
|
7
|
+
data.tar.gz: d6ecb38160b4180a137a6db4f0d9e7fa6e9e14d32ebc5e98cae09a92f18997946bacc548adc4a55f7e19107ae6f2fcdbe7e43ab5a540b0d96706239dd81aa462
|
@@ -38,11 +38,7 @@ module ForemanVault
|
|
38
38
|
logger.info "Pushing #{name} data to Vault"
|
39
39
|
|
40
40
|
vault_policy.save if vault_policy.new?
|
41
|
-
|
42
|
-
if vault_auth_method.name != old&.vault_auth_method&.name
|
43
|
-
old&.vault_auth_method&.delete
|
44
|
-
vault_auth_method.save
|
45
|
-
end
|
41
|
+
vault_auth_method.save
|
46
42
|
true
|
47
43
|
rescue StandardError => e
|
48
44
|
Foreman::Logging.exception("Failed to push #{name} data to Vault.", e)
|
data/app/models/setting/vault.rb
CHANGED
@@ -9,16 +9,34 @@ class Setting
|
|
9
9
|
[set_vault_connection, set_vault_policy_template, set_vault_orchestration_enabled]
|
10
10
|
end
|
11
11
|
|
12
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
12
13
|
def self.load_defaults
|
13
14
|
# Check the table exists
|
14
15
|
return unless super
|
15
16
|
|
16
17
|
transaction do
|
17
|
-
default_settings.each
|
18
|
+
default_settings.each do |s|
|
19
|
+
setting = create! s.update(category: 'Setting::Vault')
|
20
|
+
|
21
|
+
Foreman.try(:settings)&._add(
|
22
|
+
s[:name],
|
23
|
+
s.slice(:description, :default, :full_name, :encrypted)
|
24
|
+
.merge(category: 'Setting::Vault')
|
25
|
+
.yield_self do |params|
|
26
|
+
unless Gem::Version.new(SETTINGS[:version].notag) < Gem::Version.new('2.6')
|
27
|
+
params[:context] = :vault
|
28
|
+
params[:type] = setting.settings_type
|
29
|
+
end
|
30
|
+
params
|
31
|
+
end
|
32
|
+
)
|
33
|
+
end
|
18
34
|
end
|
19
35
|
|
36
|
+
Foreman.try(:settings)&.load
|
20
37
|
true
|
21
38
|
end
|
39
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
22
40
|
|
23
41
|
def self.humanized_category
|
24
42
|
N_('Vault')
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# NAME: <%= @host.owner %>-<%= @host.
|
1
|
+
# NAME: <%= @host.owner %>-<%= @host.name %>
|
2
2
|
|
3
|
-
# allow access to secrets from puppet hosts from <foreman_owner>-<
|
4
|
-
path "secrets/data/<%= @host.owner %>/<%= @host.
|
3
|
+
# allow access to secrets from puppet hosts from <foreman_owner>-<hostname>
|
4
|
+
path "secrets/data/<%= @host.owner %>/<%= @host.name %>/*" {
|
5
5
|
capabilities = ["create", "read", "update"]
|
6
6
|
}
|
@@ -3,7 +3,50 @@
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
|
5
5
|
# Tasks
|
6
|
-
namespace :foreman_vault do
|
6
|
+
namespace :foreman_vault do # rubocop:disable Metrics/BlockLength
|
7
|
+
namespace :auth_methods do
|
8
|
+
desc 'Push auth methods for all hosts to Vault'
|
9
|
+
task push: :environment do
|
10
|
+
User.as_anonymous_admin do
|
11
|
+
hosts = Host::Managed.where(managed: true)
|
12
|
+
|
13
|
+
hosts.each_with_index do |host, index|
|
14
|
+
begin
|
15
|
+
result = host.reload.vault_auth_method.save
|
16
|
+
if result
|
17
|
+
puts "[#{index + 1}/#{hosts.count}] Auth-Method of \"#{host.name}\" pushed to Vault server \"#{host.vault_connection.url}\""
|
18
|
+
else
|
19
|
+
puts "[#{index + 1}/#{hosts.count}] Failed to push \"#{host.name}\": #{result}"
|
20
|
+
end
|
21
|
+
rescue StandardError => err
|
22
|
+
puts "[#{index + 1}/#{hosts.count}] Failed to push \"#{host.name}\": #{err}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :policies do
|
30
|
+
desc 'Push policies for all hosts to Vault'
|
31
|
+
task push: :environment do
|
32
|
+
User.as_anonymous_admin do
|
33
|
+
hosts = Host::Managed.where(managed: true)
|
34
|
+
|
35
|
+
hosts.each_with_index do |host, index|
|
36
|
+
begin
|
37
|
+
result = host.reload.vault_policy.save
|
38
|
+
if result
|
39
|
+
puts "[#{index + 1}/#{hosts.count}] Policy of \"#{host.name}\" pushed to Vault server \"#{host.vault_connection.url}\""
|
40
|
+
else
|
41
|
+
puts "[#{index + 1}/#{hosts.count}] Failed to push \"#{host.name}\": #{result}"
|
42
|
+
end
|
43
|
+
rescue StandardError => err
|
44
|
+
puts "[#{index + 1}/#{hosts.count}] Failed to push \"#{host.name}\": #{err}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
7
50
|
end
|
8
51
|
|
9
52
|
# Tests
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
module ForemanVault
|
7
|
+
class PushAuthMethodsTest < ActiveSupport::TestCase
|
8
|
+
TASK_NAME = 'foreman_vault:auth_methods:push'
|
9
|
+
|
10
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
11
|
+
let(:vault_connection) { FactoryBot.create(:vault_connection, :without_callbacks) }
|
12
|
+
|
13
|
+
setup do
|
14
|
+
Rake.application.rake_require 'tasks/foreman_vault_tasks'
|
15
|
+
|
16
|
+
Rake::Task.define_task(:environment)
|
17
|
+
Rake::Task[TASK_NAME].reenable
|
18
|
+
|
19
|
+
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
20
|
+
|
21
|
+
ForemanVault::VaultAuthMethod.any_instance.stubs(:vault_policy_name).returns('vault_policy_name')
|
22
|
+
ForemanVault::VaultAuthMethod.any_instance.stubs(:certificate).returns('cert')
|
23
|
+
|
24
|
+
ForemanVault::VaultClient.any_instance.stubs(:set_certificate).returns(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does successfully push auth methods' do
|
28
|
+
host
|
29
|
+
|
30
|
+
stdout, _stderr = capture_io do
|
31
|
+
Rake::Task[TASK_NAME].invoke
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_match("[1/1] Auth-Method of \"#{host.name}\" pushed to Vault server \"#{host.vault_connection.url}\"", stdout)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does throw an error when host was deleted' do
|
38
|
+
host
|
39
|
+
|
40
|
+
Host::Managed.any_instance.stubs(:reload).raises(ActiveRecord::RecordNotFound)
|
41
|
+
|
42
|
+
stdout, _stderr = capture_io do
|
43
|
+
Rake::Task[TASK_NAME].invoke
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_match("[1/1] Failed to push \"#{host.name}\"", stdout)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
module ForemanVault
|
7
|
+
class PushPoliciesTest < ActiveSupport::TestCase
|
8
|
+
TASK_NAME = 'foreman_vault:policies:push'
|
9
|
+
|
10
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
11
|
+
let(:vault_connection) { FactoryBot.create(:vault_connection, :without_callbacks) }
|
12
|
+
|
13
|
+
setup do
|
14
|
+
Rake.application.rake_require 'tasks/foreman_vault_tasks'
|
15
|
+
|
16
|
+
Rake::Task.define_task(:environment)
|
17
|
+
Rake::Task[TASK_NAME].reenable
|
18
|
+
|
19
|
+
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
20
|
+
|
21
|
+
ForemanVault::VaultPolicy.any_instance.stubs(:name).returns('vault_policy_name')
|
22
|
+
ForemanVault::VaultPolicy.any_instance.stubs(:rules).returns('rules')
|
23
|
+
|
24
|
+
ForemanVault::VaultClient.any_instance.stubs(:put_policy).returns(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does successfully push policies' do
|
28
|
+
host
|
29
|
+
|
30
|
+
stdout, _stderr = capture_io do
|
31
|
+
Rake::Task[TASK_NAME].invoke
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_match("[1/1] Policy of \"#{host.name}\" pushed to Vault server \"#{host.vault_connection.url}\"", stdout)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does throw an error when host was deleted' do
|
38
|
+
host
|
39
|
+
|
40
|
+
Host::Managed.any_instance.stubs(:reload).raises(ActiveRecord::RecordNotFound)
|
41
|
+
|
42
|
+
stdout, _stderr = capture_io do
|
43
|
+
Rake::Task[TASK_NAME].invoke
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_match("[1/1] Failed to push \"#{host.name}\"", stdout)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -17,7 +17,11 @@ module ForemanVault
|
|
17
17
|
host.stubs(:vault_policy).returns(vault_policy)
|
18
18
|
host.stubs(:vault_auth_method).returns(vault_auth_method)
|
19
19
|
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
20
|
-
|
20
|
+
if Setting.find_by(name: 'vault_orchestration_enabled')
|
21
|
+
Setting['vault_orchestration_enabled'] = true
|
22
|
+
else
|
23
|
+
FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
test 'should queue Vault orchestration' do
|
@@ -65,7 +69,11 @@ module ForemanVault
|
|
65
69
|
host.stubs(:vault_policy).returns(vault_policy)
|
66
70
|
host.stubs(:vault_auth_method).returns(vault_auth_method)
|
67
71
|
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
68
|
-
|
72
|
+
if Setting.find_by(name: 'vault_orchestration_enabled')
|
73
|
+
Setting['vault_orchestration_enabled'] = true
|
74
|
+
else
|
75
|
+
FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
|
76
|
+
end
|
69
77
|
end
|
70
78
|
|
71
79
|
context 'when auth_method is valid' do
|
@@ -92,8 +100,7 @@ module ForemanVault
|
|
92
100
|
end
|
93
101
|
|
94
102
|
describe '#set_vault' do
|
95
|
-
let(:
|
96
|
-
let(:host) { FactoryBot.create(:host, :managed, environment: environment) }
|
103
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
97
104
|
let(:vault_connection) { FactoryBot.create(:vault_connection, :without_callbacks) }
|
98
105
|
let(:new_owner) { FactoryBot.create(:usergroup, name: 'MyOwner') }
|
99
106
|
|
@@ -105,16 +112,16 @@ module ForemanVault
|
|
105
112
|
)
|
106
113
|
end
|
107
114
|
|
108
|
-
let(:new_policy_name) { "#{new_owner}-#{host.
|
115
|
+
let(:new_policy_name) { "#{new_owner}-#{host.name}".parameterize }
|
109
116
|
let(:put_policy_request) do
|
110
117
|
url = "#{vault_connection.url}/v1/sys/policy/#{new_policy_name}"
|
111
118
|
# rubocop:disable Metrics/LineLength
|
112
|
-
rules = "# allow access to secrets from puppet hosts from <foreman_owner>-<
|
119
|
+
rules = "# allow access to secrets from puppet hosts from <foreman_owner>-<hostname>\npath \"secrets/data/MyOwner/#{host.name}/*\" {\n capabilities = [\"create\", \"read\", \"update\"]\n}\n"
|
113
120
|
# rubocop:enable Metrics/LineLength
|
114
121
|
stub_request(:put, url).with(body: JSON.fast_generate(rules: rules)).to_return(status: 200)
|
115
122
|
end
|
116
123
|
|
117
|
-
let(:new_auth_method_name) {
|
124
|
+
let(:new_auth_method_name) { host.name.parameterize }
|
118
125
|
let(:post_auth_method_request) do
|
119
126
|
url = "#{vault_connection.url}/v1/auth/cert/certs/#{new_auth_method_name}"
|
120
127
|
stub_request(:post, url).with(
|
@@ -126,15 +133,23 @@ module ForemanVault
|
|
126
133
|
).to_return(status: 200)
|
127
134
|
end
|
128
135
|
|
129
|
-
let(:
|
136
|
+
let(:override_old_auth_method_request) do
|
130
137
|
url = "#{vault_connection.url}/v1/auth/cert/certs/#{host.vault_auth_method.name}"
|
131
138
|
stub_request(:delete, url).to_return(status: 200)
|
132
139
|
end
|
133
140
|
|
134
141
|
setup do
|
135
142
|
Setting.find_by(name: 'ssl_ca_file').update(value: File.join(ForemanVault::Engine.root, 'test/fixtures/ca.crt'))
|
136
|
-
|
137
|
-
|
143
|
+
if Setting.find_by(name: 'vault_orchestration_enabled')
|
144
|
+
Setting['vault_orchestration_enabled'] = true
|
145
|
+
else
|
146
|
+
FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
|
147
|
+
end
|
148
|
+
if Setting.find_by(name: 'vault_policy_template')
|
149
|
+
Setting['vault_policy_template'] = 'Default Vault Policy'
|
150
|
+
else
|
151
|
+
FactoryBot.create(:setting, :vault_policy)
|
152
|
+
end
|
138
153
|
FactoryBot.create(:provisioning_template, :vault_policy, name: Setting['vault_policy_template'])
|
139
154
|
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
140
155
|
host.stubs(:skip_orchestration_for_testing?).returns(false)
|
@@ -142,13 +157,11 @@ module ForemanVault
|
|
142
157
|
get_policies_request
|
143
158
|
put_policy_request
|
144
159
|
post_auth_method_request
|
145
|
-
delete_old_auth_method_request
|
146
160
|
|
147
161
|
host.update(owner: new_owner)
|
148
162
|
end
|
149
163
|
|
150
164
|
it { assert_requested(post_auth_method_request) }
|
151
|
-
it { assert_requested(delete_old_auth_method_request) }
|
152
165
|
|
153
166
|
context 'when policy already exists on Vault' do
|
154
167
|
let(:vault_policies) { [new_policy_name] }
|
@@ -8,26 +8,13 @@ class VaultAuthMethodTest < ActiveSupport::TestCase
|
|
8
8
|
let(:host) { FactoryBot.create(:host, :managed) }
|
9
9
|
|
10
10
|
describe '#name' do
|
11
|
-
context 'with host
|
12
|
-
|
13
|
-
subject.stubs(:vault_policy_name).returns('vault_policy_name')
|
14
|
-
end
|
15
|
-
|
16
|
-
it { assert_equal "#{host}-vault_policy_name".parameterize, subject.name }
|
11
|
+
context 'with host' do
|
12
|
+
it { assert_equal host.name.parameterize, subject.name }
|
17
13
|
end
|
18
14
|
|
19
15
|
context 'without host' do
|
20
16
|
setup do
|
21
17
|
subject.stubs(:host).returns(nil)
|
22
|
-
subject.stubs(:vault_policy_name).returns('vault_policy_name')
|
23
|
-
end
|
24
|
-
|
25
|
-
it { assert_nil subject.name }
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'without vault_policy_name' do
|
29
|
-
setup do
|
30
|
-
subject.stubs(:vault_policy_name).returns(nil)
|
31
18
|
end
|
32
19
|
|
33
20
|
it { assert_nil subject.name }
|
@@ -8,7 +8,11 @@ class VaultPolicyTest < ActiveSupport::TestCase
|
|
8
8
|
let(:host) { FactoryBot.create(:host, :managed) }
|
9
9
|
|
10
10
|
setup do
|
11
|
-
|
11
|
+
if Setting.find_by(name: 'vault_policy_template')
|
12
|
+
Setting['vault_policy_template'] = 'Default Vault Policy'
|
13
|
+
else
|
14
|
+
FactoryBot.create(:setting, name: 'vault_policy_template', value: 'Default Vault Policy')
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
describe 'valid?' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_vault
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dmTECH GmbH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vault
|
@@ -109,6 +109,8 @@ files:
|
|
109
109
|
- test/functional/api/v2/vault_connections_controller_test.rb
|
110
110
|
- test/jobs/refresh_vault_token_test.rb
|
111
111
|
- test/jobs/refresh_vault_tokens_test.rb
|
112
|
+
- test/lib/tasks/push_auth_methods_test.rb
|
113
|
+
- test/lib/tasks/push_policies_test.rb
|
112
114
|
- test/models/foreman_vault/orchestration/vault_policy_test.rb
|
113
115
|
- test/models/vault_connection_test.rb
|
114
116
|
- test/models/vault_policy_template_test.rb
|
@@ -136,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
138
|
- !ruby/object:Gem::Version
|
137
139
|
version: '0'
|
138
140
|
requirements: []
|
139
|
-
rubygems_version: 3.
|
141
|
+
rubygems_version: 3.2.28
|
140
142
|
signing_key:
|
141
143
|
specification_version: 4
|
142
144
|
summary: Adds support for using credentials from Hashicorp Vault
|
@@ -151,6 +153,8 @@ test_files:
|
|
151
153
|
- test/factories/vault_policy_template.rb
|
152
154
|
- test/factories/vault_connection.rb
|
153
155
|
- test/factories/vault_setting.rb
|
156
|
+
- test/lib/tasks/push_policies_test.rb
|
157
|
+
- test/lib/tasks/push_auth_methods_test.rb
|
154
158
|
- test/fixtures/ca.crt
|
155
159
|
- test/test_plugin_helper.rb
|
156
160
|
- test/jobs/refresh_vault_tokens_test.rb
|