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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6107c566ac8bf65dd8b0c11f2c6534d26303e781407fef11f29612d5ca77325e
4
- data.tar.gz: ae555560613c5b4dbe17281c05c7db8df0d244f82ffd27c56785e805c7ac04da
3
+ metadata.gz: 39553e728b4ff3661a8b0fc008ee0959e5fdbba5f915a9f7f9d09bdd24d9d65a
4
+ data.tar.gz: 34b06a3ffc2cfdd6055356c4af15e91bb7d94de7954983d0becc20881c85fef3
5
5
  SHA512:
6
- metadata.gz: 3a86e4e2f4fc926c0c8ade16116830d311be2b54b00cca629465d1af4c4ecfaa84cd42614ebb8090c17b50eb92ce1f732d15969f1bbfea972e9fe489b73d12f3
7
- data.tar.gz: 30afd42d83d3d91ce4d72fc4419cd2b0f360f495462d6e916b209db7619a63ada8a365169ec8903508aa738e9686a627bb9577b4648851bacffa8bf60b8592f5
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)
@@ -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 { |s| create! s.update(category: 'Setting::Vault') }
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')
@@ -11,9 +11,9 @@ module ForemanVault
11
11
  end
12
12
 
13
13
  def name
14
- return if !host || !vault_policy_name
14
+ return unless host
15
15
 
16
- [host, vault_policy_name].join('-').parameterize
16
+ host.name.parameterize
17
17
  end
18
18
 
19
19
  def save
@@ -1,6 +1,6 @@
1
- # NAME: <%= @host.owner %>-<%= @host.environment %>
1
+ # NAME: <%= @host.owner %>-<%= @host.name %>
2
2
 
3
- # allow access to secrets from puppet hosts from <foreman_owner>-<puppet_environment>
4
- path "secrets/data/<%= @host.owner %>/<%= @host.environment %>/*" {
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
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanVault
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -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
- FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
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
- FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
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(:environment) { FactoryBot.create(:environment, name: 'MyEnv') }
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.environment}".parameterize }
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>-<puppet_environment>\npath \"secrets/data/MyOwner/MyEnv/*\" {\n capabilities = [\"create\", \"read\", \"update\"]\n}\n"
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) { "#{host}-#{new_policy_name}".parameterize }
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(:delete_old_auth_method_request) do
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
- FactoryBot.create(:setting, name: :vault_orchestration_enabled, value: true)
137
- FactoryBot.create(:setting, :vault_policy)
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 and vault_policy_name' do
12
- setup do
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
- FactoryBot.create(:setting, name: 'vault_policy_template', value: 'Default Vault Policy')
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.0.0
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-01-11 00:00:00.000000000 Z
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.1.4
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