foreman_vault 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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