foreman_vault 0.1.0 → 0.2.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/README.md +74 -14
- data/app/models/concerns/foreman_vault/host_extensions.rb +31 -0
- data/app/models/concerns/foreman_vault/orchestration/vault_policy.rb +59 -0
- data/app/models/setting/vault.rb +73 -0
- data/app/models/vault_connection.rb +3 -1
- data/app/services/foreman_vault/vault_auth_method.rb +58 -0
- data/app/services/foreman_vault/vault_client.rb +4 -2
- data/app/services/foreman_vault/vault_policy.rb +65 -0
- data/app/views/unattended/provisioning_templates/VaultPolicy/default.erb +6 -0
- data/db/seeds.d/103-provisioning_templates.rb +25 -0
- data/lib/foreman_vault/engine.rb +13 -2
- data/lib/foreman_vault/version.rb +1 -1
- data/test/factories/{foreman_vault_factories.rb → vault_connection.rb} +0 -0
- data/test/factories/vault_policy_template.rb +10 -0
- data/test/factories/vault_setting.rb +10 -0
- data/test/fixtures/ca.crt +21 -0
- data/test/models/foreman_vault/orchestration/vault_policy_test.rb +125 -0
- data/test/test_plugin_helper.rb +0 -1
- data/test/unit/services/foreman_vault/vault_auth_method_test.rb +130 -0
- data/test/unit/services/foreman_vault/vault_policy_test.rb +171 -0
- metadata +24 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a11fc63d2584b7fd9f4ad6b561cdbdd471503d3de307d4a77610094d67d26b62
|
4
|
+
data.tar.gz: 215b5f6e87ed318a16b7623bedccb25d17dd001ee73281f144b6726a44aee28b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b73b1a230f9982752e8ede2a38b2afd1a071a7ca397fe5f518d6447dbd30ca4f94efcbf29d4c39430cb8f8bf5b9508d9c4edd542aead2ebde60d00e82f889833
|
7
|
+
data.tar.gz: 3b85d123010e4ff958ed12885792b759cddd81b550c4f3cc287cce45b38881ea6589e700caa99751f0f0baf79002a89c2089f5a5784b23d6dafbf3509dc938cd
|
data/README.md
CHANGED
@@ -2,31 +2,63 @@
|
|
2
2
|
|
3
3
|
[<img src="https://opensourcelogos.aws.dmtech.cloud/dmTECH_opensource_logo.svg" height="21" width="130">](https://www.dmtech.de/)
|
4
4
|
|
5
|
-
|
5
|
+
**Foreman Vault** is a plugin for Foreman that integrates with Hashicorp Vault for different things. Currently, it offers two distinct features.
|
6
6
|
|
7
|
-
##
|
7
|
+
## 1. Vault secrets in Foreman templates
|
8
8
|
|
9
|
-
|
9
|
+
This adds two new macros which can be used in Foreman templates:
|
10
|
+
|
11
|
+
- `vault_secret` - Retreive secrets at a given Vault path
|
12
|
+
- `vault_issue_certificate` - Issues new certificates
|
13
|
+
|
14
|
+
## 2. Management of Vault Policies and AuthMethods
|
15
|
+
|
16
|
+
Vault [policies](https://www.vaultproject.io/docs/concepts/policies) and [auth methods](https://www.vaultproject.io/docs/concepts/auth) (of type _cert_) can be created automatically as part of the **host orchestration**.
|
17
|
+
Auth methods also get deleted after the host is removed from Foreman.
|
18
|
+
|
19
|
+
This allows Foreman to create everything needed to access Hashicorp Vault directly from a VM using it's Puppet certificate (e.g. for _Deferred functions_ in Puppet or other CLI tools).
|
20
|
+
|
21
|
+
## Requirements
|
22
|
+
|
23
|
+
- Foreman >= 1.20
|
24
|
+
- Working Vault instance
|
25
|
+
- with _cert_ auth enabled
|
26
|
+
- with _kv_ secret store enabled
|
27
|
+
- valid Vault Token
|
10
28
|
|
11
|
-
|
29
|
+
**Dev Vault Instance**
|
12
30
|
|
13
|
-
|
31
|
+
To run a local Vault dev environment on MacOS use:
|
14
32
|
|
15
33
|
```
|
16
34
|
$ brew install vault
|
17
35
|
$ vault server -dev
|
18
36
|
$ export VAULT_ADDR='http://127.0.0.1:8200'
|
19
37
|
$ vault secrets enable kv
|
38
|
+
$ vault auth enable cert
|
39
|
+
|
40
|
+
$ vault token create -period=60m
|
41
|
+
[...]
|
20
42
|
```
|
21
43
|
|
22
|
-
|
44
|
+
## Installation
|
45
|
+
|
46
|
+
See [Plugins install instructions](https://theforeman.org/plugins/) for how to install Foreman plugins.
|
47
|
+
|
48
|
+
## Basic configuration
|
49
|
+
|
50
|
+
To create a new Vault connection navigate to `Infrastructure -> Vault Connections` and hit the `Create Vault Connection` button. There you can enter a name, the Vault URL and a secret token.
|
51
|
+
|
52
|
+
## Vault secrets in templates
|
23
53
|
|
24
|
-
|
25
|
-
|
26
|
-
|
54
|
+
At this point you can utilize two new macros in your templates:
|
55
|
+
|
56
|
+
- vault_secret(vault_connection_name, secret_path)
|
57
|
+
- vault_issue_certificate(vault_connection_name, pki_role_path, options...)
|
27
58
|
|
28
59
|
### vault_secret(vault_connection_name, secret_path)
|
29
|
-
|
60
|
+
|
61
|
+
To fetch secrets from Vault (you can write secrets with the `vault write kv/my_secret foo=bar` command), e.g.
|
30
62
|
|
31
63
|
```
|
32
64
|
<%= vault_secret('MyVault', 'kv/my_secret') %>
|
@@ -39,14 +71,42 @@ As result you should get secret data, e.g.
|
|
39
71
|
```
|
40
72
|
|
41
73
|
### vault_issue_certificate(vault_connection_name, pki_role_path, options...)
|
42
|
-
Issueing certificates is just as easy. Be sure to have a correctly set-up PKI, meaning, configure it so you can generate certificates from within the Vault UI. This means that you'll have had to set-up a CA or Intermediate CA. Once done, you can generate a certificate like this:
|
43
74
|
|
75
|
+
Issueing certificates is just as easy. Be sure to have a correctly set-up PKI, meaning, configure it so you can generate certificates from within the Vault UI. This means that you'll have to set-up a CA or Intermediate CA. Once done, you can generate a certificate like this:
|
44
76
|
|
45
77
|
```
|
46
78
|
<%= vault_issue_certificate('MyVault', 'pkiEngine/issue/testRole', common_name: 'test.mydomain.com', ttl: '10s') %>
|
47
79
|
```
|
48
80
|
|
49
|
-
The
|
81
|
+
The _common_name_ and _ttl_ are optional, but there are [more options to configure](https://www.vaultproject.io/api/secret/pki/index.html#generate-certificate)
|
82
|
+
|
83
|
+
## Vault policies and auth methods
|
84
|
+
|
85
|
+
### Policies
|
86
|
+
|
87
|
+
The policy is based on a new template kind `VaultPolicy` which is basically a [Vault Policy](https://www.vaultproject.io/docs/concepts/policies#policy-syntax) extended with ERB.
|
88
|
+
|
89
|
+
The name of the policy is extracted from a _Magic comment_ within the template. Therefore you can use ERB to influence the name:
|
90
|
+
|
91
|
+
```
|
92
|
+
# NAME: <%= @host.owner %>-<%= @host.environment %>
|
93
|
+
|
94
|
+
path "secret/foo" {
|
95
|
+
capabilities = ["read"]
|
96
|
+
}
|
97
|
+
```
|
98
|
+
|
99
|
+
You can create multiple `VaultPolicy` templates and configure the default policy used in host orchestration by setting the Foreman Setting `vault_policy_template` to the desired one.
|
100
|
+
|
101
|
+
**Note: If the policy renders empty (yes, you can use conditions within ERB), the orchestration is skipped!**
|
102
|
+
|
103
|
+
### Auth methods
|
104
|
+
|
105
|
+
[Auth methods of type `cert`](https://www.vaultproject.io/docs/auth/cert) are created with three attributes:
|
106
|
+
|
107
|
+
- **certificate**: content of the Foreman setting `ssl_ca_file`
|
108
|
+
- **allowed_common_names**: FQDN of the host which triggered the orchestration
|
109
|
+
- **token_policies**: This is automatically linked to the policy from above
|
50
110
|
|
51
111
|
## Contributing
|
52
112
|
|
@@ -63,8 +123,8 @@ the Free Software Foundation, either version 3 of the License, or
|
|
63
123
|
|
64
124
|
This program is distributed in the hope that it will be useful,
|
65
125
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
66
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
126
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
67
127
|
GNU General Public License for more details.
|
68
128
|
|
69
129
|
You should have received a copy of the GNU General Public License
|
70
|
-
along with this program.
|
130
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanVault
|
4
|
+
module HostExtensions
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include ForemanVault::Orchestration::VaultPolicy
|
9
|
+
end
|
10
|
+
|
11
|
+
def vault_policy
|
12
|
+
VaultPolicy.new(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def vault_auth_method
|
16
|
+
VaultAuthMethod.new(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def vault_connection
|
20
|
+
return unless vault_connection_name
|
21
|
+
|
22
|
+
::VaultConnection.find_by(name: vault_connection_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def vault_connection_name
|
28
|
+
params['vault_connection'] || Setting['vault_connection']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanVault
|
4
|
+
module Orchestration
|
5
|
+
module VaultPolicy
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
MAGIC_COMMENT_PREFIX = '# NAME: '
|
9
|
+
|
10
|
+
included do
|
11
|
+
after_validation :queue_vault_push
|
12
|
+
before_destroy :queue_vault_destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def queue_vault_push
|
18
|
+
return if !managed? || errors.any?
|
19
|
+
return unless vault_policy.valid?
|
20
|
+
return unless vault_auth_method.valid?
|
21
|
+
|
22
|
+
queue.create(name: _('Push %s data to Vault') % self, priority: 100,
|
23
|
+
action: [self, :set_vault])
|
24
|
+
end
|
25
|
+
|
26
|
+
def queue_vault_destroy
|
27
|
+
return if !managed? || errors.any?
|
28
|
+
|
29
|
+
queue.create(name: _('Clear %s Vault data') % self, priority: 60,
|
30
|
+
action: [self, :del_vault])
|
31
|
+
end
|
32
|
+
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
34
|
+
def set_vault
|
35
|
+
logger.info "Pushing #{name} data to Vault"
|
36
|
+
|
37
|
+
vault_policy.save if vault_policy.new?
|
38
|
+
|
39
|
+
if vault_auth_method.name != old&.vault_auth_method&.name
|
40
|
+
old&.vault_auth_method&.delete
|
41
|
+
vault_auth_method.save
|
42
|
+
end
|
43
|
+
rescue StandardError => e
|
44
|
+
Foreman::Logging.exception("Failed to push #{name} data to Vault.", e)
|
45
|
+
failure format(_('Failed to push %{name} data to Vault: %{message}\n '), name: name, message: e.message), e
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/AbcSize
|
48
|
+
|
49
|
+
def del_vault
|
50
|
+
logger.info "Clearing #{name} Vault data"
|
51
|
+
|
52
|
+
vault_auth_method&.delete
|
53
|
+
rescue StandardError => e
|
54
|
+
Foreman::Logging.exception("Failed to clear #{name} Vault data", e)
|
55
|
+
failure format(_("Failed to clear %{name} Vault data: %{message}\n "), name: name, message: e.message), e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Setting
|
4
|
+
class Vault < ::Setting
|
5
|
+
BLANK_ATTRS << 'vault_connection'
|
6
|
+
BLANK_ATTRS << 'vault_policy_template'
|
7
|
+
|
8
|
+
def self.default_settings
|
9
|
+
[set_vault_connection, set_vault_policy_template]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.load_defaults
|
13
|
+
# Check the table exists
|
14
|
+
return unless super
|
15
|
+
|
16
|
+
transaction do
|
17
|
+
default_settings.each { |s| create! s.update(category: 'Setting::Vault') }
|
18
|
+
end
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.humanized_category
|
24
|
+
N_('Vault')
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
private
|
29
|
+
|
30
|
+
def set_vault_connection
|
31
|
+
set(
|
32
|
+
'vault_connection',
|
33
|
+
N_('Default Vault Connection that can be override using parameters'),
|
34
|
+
default_vault_connection,
|
35
|
+
N_('Default Vault Connection'),
|
36
|
+
nil,
|
37
|
+
collection: vault_connections_collection,
|
38
|
+
include_blank: _('Select Vault Connection')
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_vault_connection
|
43
|
+
return unless VaultConnection.unscoped.count == 1
|
44
|
+
|
45
|
+
VaultConnection.unscoped.first.name
|
46
|
+
end
|
47
|
+
|
48
|
+
def vault_connections_collection
|
49
|
+
proc { Hash[VaultConnection.unscoped.all.map { |vc| [vc.name, vc.name] }] }
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_vault_policy_template
|
53
|
+
set(
|
54
|
+
'vault_policy_template',
|
55
|
+
N_('The name of the ProvisioningTemplate that will be used for Vault Policy'),
|
56
|
+
default_vault_policy_template,
|
57
|
+
N_('Vault Policy template name'),
|
58
|
+
nil,
|
59
|
+
collection: vault_policy_templates_collection,
|
60
|
+
include_blank: _('Select Template')
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_vault_policy_template
|
65
|
+
ProvisioningTemplate.unscoped.of_kind(:VaultPolicy).find_by(name: 'Default Vault Policy')&.name
|
66
|
+
end
|
67
|
+
|
68
|
+
def vault_policy_templates_collection
|
69
|
+
proc { Hash[ProvisioningTemplate.unscoped.of_kind(:VaultPolicy).map { |tmpl| [tmpl.name, tmpl.name] }] }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -13,7 +13,9 @@ class VaultConnection < ApplicationRecord
|
|
13
13
|
|
14
14
|
scope :with_valid_token, -> { where(vault_error: nil).where('expire_time > ?', Time.zone.now) }
|
15
15
|
|
16
|
-
delegate :fetch_expire_time, :fetch_secret, :issue_certificate,
|
16
|
+
delegate :fetch_expire_time, :fetch_secret, :issue_certificate,
|
17
|
+
:policy, :policies, :put_policy, :delete_policy,
|
18
|
+
:set_certificate, :certificates, :delete_certificate, to: :client
|
17
19
|
|
18
20
|
def token_valid?
|
19
21
|
vault_error.nil? && expire_time && expire_time > Time.zone.now
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanVault
|
4
|
+
class VaultAuthMethod
|
5
|
+
def initialize(host)
|
6
|
+
@host = host
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?
|
10
|
+
name.present? && options[:certificate].present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
return if !host || !vault_policy_name
|
15
|
+
|
16
|
+
[host, vault_policy_name].join('-').parameterize
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
return false unless valid?
|
21
|
+
|
22
|
+
set_certificate(name, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete
|
26
|
+
return false unless name
|
27
|
+
|
28
|
+
delete_certificate(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :host
|
34
|
+
delegate :vault_policy, :vault_connection, :fqdn, to: :host
|
35
|
+
delegate :name, to: :vault_policy, prefix: true
|
36
|
+
delegate :set_certificate, :delete_certificate, to: :vault_connection
|
37
|
+
|
38
|
+
def options
|
39
|
+
{
|
40
|
+
certificate: certificate,
|
41
|
+
token_policies: vault_policy_name,
|
42
|
+
allowed_common_names: allowed_common_names
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def allowed_common_names
|
47
|
+
[fqdn].compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def certificate
|
51
|
+
return unless Setting['ssl_ca_file']
|
52
|
+
|
53
|
+
File.read(Setting['ssl_ca_file'])
|
54
|
+
rescue Errno::ENOENT
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'vault'
|
4
|
-
|
5
3
|
module ForemanVault
|
6
4
|
class VaultClient
|
7
5
|
def initialize(base_url, token)
|
@@ -9,6 +7,10 @@ module ForemanVault
|
|
9
7
|
@token = token
|
10
8
|
end
|
11
9
|
|
10
|
+
delegate :sys, :auth_tls, to: :client
|
11
|
+
delegate :policy, :policies, :put_policy, :delete_policy, to: :sys
|
12
|
+
delegate :certificate, :certificates, :set_certificate, :delete_certificate, to: :auth_tls
|
13
|
+
|
12
14
|
def fetch_expire_time
|
13
15
|
response = client.auth_token.lookup_self
|
14
16
|
Time.zone.parse(response.data[:expire_time])
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanVault
|
4
|
+
class VaultPolicy
|
5
|
+
MAGIC_COMMENT_NAME_PREFIX = '# NAME: '
|
6
|
+
|
7
|
+
def initialize(host)
|
8
|
+
@host = host
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?
|
12
|
+
name.present? && rules.present?
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
magic_comment_name&.chomp&.remove(MAGIC_COMMENT_NAME_PREFIX)&.parameterize
|
17
|
+
end
|
18
|
+
|
19
|
+
def new?
|
20
|
+
return unless name
|
21
|
+
|
22
|
+
policies.index(name).nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
return false unless valid?
|
27
|
+
|
28
|
+
put_policy(name, rules)
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete
|
32
|
+
return false unless name
|
33
|
+
|
34
|
+
delete_policy(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :host
|
40
|
+
delegate :params, :render_template, :vault_connection, to: :host
|
41
|
+
delegate :policy, :policies, :put_policy, :delete_policy, to: :vault_connection
|
42
|
+
|
43
|
+
def rules
|
44
|
+
rendered&.remove(magic_comment_name)
|
45
|
+
&.lines
|
46
|
+
&.reject { |l| l.strip.empty? }
|
47
|
+
&.join
|
48
|
+
&.presence
|
49
|
+
end
|
50
|
+
|
51
|
+
def magic_comment_name
|
52
|
+
rendered&.lines&.find { |l| l.start_with?(MAGIC_COMMENT_NAME_PREFIX) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def rendered
|
56
|
+
return unless template
|
57
|
+
|
58
|
+
render_template(template: template)
|
59
|
+
end
|
60
|
+
|
61
|
+
def template
|
62
|
+
::ProvisioningTemplate.find_by(name: Setting['vault_policy_template'])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
User.as_anonymous_admin do
|
4
|
+
templates = [
|
5
|
+
{
|
6
|
+
name: 'Default Vault Policy',
|
7
|
+
source: 'VaultPolicy/default.erb',
|
8
|
+
template_kind: TemplateKind.find_or_create_by(name: 'VaultPolicy')
|
9
|
+
}
|
10
|
+
]
|
11
|
+
|
12
|
+
templates.each do |template|
|
13
|
+
template[:contents] = File.read(File.join(ForemanVault::Engine.root, 'app/views/unattended/provisioning_templates', template[:source]))
|
14
|
+
|
15
|
+
ProvisioningTemplate.where(name: template[:name]).first_or_create do |pt|
|
16
|
+
pt.vendor = 'ForemanVault'
|
17
|
+
pt.default = true
|
18
|
+
pt.locked = true
|
19
|
+
pt.name = template[:name]
|
20
|
+
pt.template = template[:contents]
|
21
|
+
pt.template_kind = template[:template_kind] if template[:template_kind]
|
22
|
+
pt.snippet = template[:snippet] if template[:snippet]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/foreman_vault/engine.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'vault'
|
4
|
+
|
3
5
|
module ForemanVault
|
4
6
|
class Engine < ::Rails::Engine
|
5
7
|
engine_name 'foreman_vault'
|
@@ -10,6 +12,14 @@ module ForemanVault
|
|
10
12
|
config.autoload_paths += Dir["#{config.root}/app/lib"]
|
11
13
|
config.autoload_paths += Dir["#{config.root}/app/jobs"]
|
12
14
|
|
15
|
+
initializer 'foreman_vault.load_default_settings', before: :load_config_initializers do
|
16
|
+
require_dependency File.expand_path('../../app/models/setting/vault.rb', __dir__) if begin
|
17
|
+
Setting.table_exists?
|
18
|
+
rescue StandardError
|
19
|
+
(false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
13
23
|
# Add any db migrations
|
14
24
|
initializer 'foreman_vault.load_app_instance_data' do |app|
|
15
25
|
ForemanVault::Engine.paths['db/migrate'].existent.each do |path|
|
@@ -44,8 +54,9 @@ module ForemanVault
|
|
44
54
|
|
45
55
|
config.to_prepare do
|
46
56
|
begin
|
47
|
-
|
48
|
-
Foreman::Renderer.
|
57
|
+
::Host::Managed.include(ForemanVault::HostExtensions)
|
58
|
+
::Foreman::Renderer::Scope::Base.include(ForemanVault::Macros)
|
59
|
+
::Foreman::Renderer.configure { |c| c.allowed_generic_helpers += [:vault_secret, :vault_issue_certificate] }
|
49
60
|
rescue StandardError => e
|
50
61
|
Rails.logger.warn "ForemanVault: skipping engine hook (#{e})"
|
51
62
|
end
|
File without changes
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
FactoryBot.modify do
|
4
|
+
factory :provisioning_template do
|
5
|
+
trait :vault_policy do
|
6
|
+
name { Setting['vault_policy_template'] || 'Default Vault Policy' }
|
7
|
+
template { File.read(File.join(ForemanVault::Engine.root, 'app/views/unattended/provisioning_templates/VaultPolicy/default.erb')) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDgDCCAmgCCQDSQhCJzHnXejANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMC
|
3
|
+
cGwxDjAMBgNVBAgMBXN0YXRlMQ0wCwYDVQQHDARjaXR5MRAwDgYDVQQKDAdjb21w
|
4
|
+
YW55MRAwDgYDVQQLDAdzZWN0aW9uMQ0wCwYDVQQDDARob3N0MSAwHgYJKoZIhvcN
|
5
|
+
AQkBFhFlbWFpbEBleGFtcGxlLmNvbTAeFw0yMDA0MjkxMzQ1MjdaFw0yMzAyMTcx
|
6
|
+
MzQ1MjdaMIGBMQswCQYDVQQGEwJwbDEOMAwGA1UECAwFc3RhdGUxDTALBgNVBAcM
|
7
|
+
BGNpdHkxEDAOBgNVBAoMB2NvbXBhbnkxEDAOBgNVBAsMB3NlY3Rpb24xDTALBgNV
|
8
|
+
BAMMBGhvc3QxIDAeBgkqhkiG9w0BCQEWEWVtYWlsQGV4YW1wbGUuY29tMIIBIjAN
|
9
|
+
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzQxWM6dJbtdDrIUvG5SBp8XadSst
|
10
|
+
D5Lu/WBwazdiRQI6mF6bOrAviZUJVoN0sFphZHjQpzTkxS9N929fdChBB7fjrP7b
|
11
|
+
vydvcbc8eH+HhK5tYzOjhjw/K2WHriNlSY7tD/Au8ZBkM7PYSM7411GG4Ubxh60+
|
12
|
+
vamBX8rdAp5wEVKWHabdFswqtNbnmFWa00gMRA44ZMoBA5KdDCNnVA+wiA1hSLYl
|
13
|
+
SdSPrKRmYw5gRul7h8lilrvf04Df87NEtRFMjuaHcxrIklVJZMsZ1Mvw5VhlpV3f
|
14
|
+
q1kMGG3wXyeTAOlMDPEFXJ4gs8ZIEqS1T1gfCUF4w/rSDQ0u49WBu2TstQIDAQAB
|
15
|
+
MA0GCSqGSIb3DQEBCwUAA4IBAQBBsovBY2r1+PXJhGTOXvZUMqz+IN/AKi52GIwC
|
16
|
+
dPmVOhFTaztL1LbRTKgtg1cyQGmIdZ8skHGFKVAkESPa1dHu+E5uGs+rFEI1A+KA
|
17
|
+
xKIN2dNXFUEnKDEywcjZhilDHeKqthf1gkcJwkMgv5+DczOtZvtsu7tDF2kcyedw
|
18
|
+
6/A+0GJVG7S72VaL5hcfgglmGXNT5BRjLAWV6ZPViXWSJj43oXLGqqwHWhRBs+d6
|
19
|
+
0+0kNukYjyPLVSLpFpj/DvxvPjQWoDTVzMeT7iTtahd4S9FGPZuHXG2yxnTjCycH
|
20
|
+
jHNvGHXHfYJCJ10RxaeyP1Dz9qG9hH0GiiCCYAuPnf6Eu1qO
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
module ForemanVault
|
6
|
+
module Orchestration
|
7
|
+
class VaultPolicyTest < ActiveSupport::TestCase
|
8
|
+
describe '#queue_vault_push' do
|
9
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
10
|
+
let(:queue) { mock('queue') }
|
11
|
+
let(:vault_policy) { mock('vault_policy') }
|
12
|
+
let(:vault_auth_method) { mock('vault_auth_method') }
|
13
|
+
|
14
|
+
setup do
|
15
|
+
host.stubs(:queue).returns(queue)
|
16
|
+
host.stubs(:vault_policy).returns(vault_policy)
|
17
|
+
host.stubs(:vault_auth_method).returns(vault_auth_method)
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'should queue Vault orchestration' do
|
21
|
+
vault_policy.stubs(:valid?).returns(true)
|
22
|
+
vault_auth_method.stubs(:valid?).returns(true)
|
23
|
+
|
24
|
+
queue.expects(:create).with(
|
25
|
+
name: "Push #{host} data to Vault",
|
26
|
+
priority: 100,
|
27
|
+
action: [host, :set_vault]
|
28
|
+
).once
|
29
|
+
host.send(:queue_vault_push)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when vault_policy is not valid' do
|
33
|
+
test 'should not queue Vault orchestration' do
|
34
|
+
vault_auth_method.stubs(:valid?).returns(true)
|
35
|
+
|
36
|
+
vault_policy.expects(:valid?).returns(false)
|
37
|
+
queue.expects(:create).never
|
38
|
+
host.send(:queue_vault_push)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when vault_auth_method is not valid' do
|
43
|
+
test 'should not queue Vault orchestration' do
|
44
|
+
vault_policy.stubs(:valid?).returns(true)
|
45
|
+
|
46
|
+
vault_auth_method.expects(:valid?).returns(false)
|
47
|
+
queue.expects(:create).never
|
48
|
+
host.send(:queue_vault_push)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#set_vault' do
|
54
|
+
let(:environment) { FactoryBot.create(:environment, name: 'MyEnv') }
|
55
|
+
let(:host) { FactoryBot.create(:host, :managed, environment: environment) }
|
56
|
+
let(:vault_connection) { FactoryBot.create(:vault_connection, :without_callbacks) }
|
57
|
+
let(:new_owner) { FactoryBot.create(:usergroup, name: 'MyOwner') }
|
58
|
+
|
59
|
+
let(:vault_policies) { [] }
|
60
|
+
let(:get_policies_request) do
|
61
|
+
stub_request(:get, "#{vault_connection.url}/v1/sys/policy").to_return(
|
62
|
+
status: 200, headers: { 'Content-Type': 'application/json' },
|
63
|
+
body: { policies: vault_policies }.to_json
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
let(:new_policy_name) { "#{new_owner}-#{host.environment}".parameterize }
|
68
|
+
let(:put_policy_request) do
|
69
|
+
url = "#{vault_connection.url}/v1/sys/policy/#{new_policy_name}"
|
70
|
+
# rubocop:disable Metrics/LineLength
|
71
|
+
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"
|
72
|
+
# rubocop:enable Metrics/LineLength
|
73
|
+
stub_request(:put, url).with(body: JSON.fast_generate(rules: rules)).to_return(status: 200)
|
74
|
+
end
|
75
|
+
|
76
|
+
let(:new_auth_method_name) { "#{host}-#{new_policy_name}".parameterize }
|
77
|
+
let(:post_auth_method_request) do
|
78
|
+
url = "#{vault_connection.url}/v1/auth/cert/certs/#{new_auth_method_name}"
|
79
|
+
stub_request(:post, url).with(
|
80
|
+
body: JSON.fast_generate(
|
81
|
+
certificate: host.vault_auth_method.send(:certificate),
|
82
|
+
token_policies: new_policy_name,
|
83
|
+
allowed_common_names: [host.fqdn]
|
84
|
+
)
|
85
|
+
).to_return(status: 200)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:delete_old_auth_method_request) do
|
89
|
+
url = "#{vault_connection.url}/v1/auth/cert/certs/#{host.vault_auth_method.name}"
|
90
|
+
stub_request(:delete, url).to_return(status: 200)
|
91
|
+
end
|
92
|
+
|
93
|
+
setup do
|
94
|
+
Setting.find_by(name: 'ssl_ca_file').update(value: File.join(ForemanVault::Engine.root, 'test/fixtures/ca.crt'))
|
95
|
+
FactoryBot.create(:setting, :vault_policy)
|
96
|
+
FactoryBot.create(:provisioning_template, :vault_policy, name: Setting['vault_policy_template'])
|
97
|
+
FactoryBot.create(:parameter, name: 'vault_connection', value: vault_connection.name)
|
98
|
+
host.stubs(:skip_orchestration_for_testing?).returns(false)
|
99
|
+
|
100
|
+
get_policies_request
|
101
|
+
put_policy_request
|
102
|
+
post_auth_method_request
|
103
|
+
delete_old_auth_method_request
|
104
|
+
|
105
|
+
host.update(owner: new_owner)
|
106
|
+
end
|
107
|
+
|
108
|
+
it { assert_requested(post_auth_method_request) }
|
109
|
+
it { assert_requested(delete_old_auth_method_request) }
|
110
|
+
|
111
|
+
context 'when policy already exists on Vault' do
|
112
|
+
let(:vault_policies) { [new_policy_name] }
|
113
|
+
|
114
|
+
it { assert_not_requested(put_policy_request) }
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when policy does not exist on Vault' do
|
118
|
+
let(:vault_policies) { [] }
|
119
|
+
|
120
|
+
it { assert_requested(put_policy_request) }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/test/test_plugin_helper.rb
CHANGED
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
class VaultAuthMethodTest < ActiveSupport::TestCase
|
6
|
+
subject { ForemanVault::VaultAuthMethod.new(host) }
|
7
|
+
|
8
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
9
|
+
|
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 }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'without host' do
|
20
|
+
setup do
|
21
|
+
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
|
+
end
|
32
|
+
|
33
|
+
it { assert_nil subject.name }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'valid?' do
|
38
|
+
context 'with name and certificate' do
|
39
|
+
setup do
|
40
|
+
subject.stubs(:name).returns('name')
|
41
|
+
subject.stubs(:certificate).returns('cert')
|
42
|
+
end
|
43
|
+
|
44
|
+
it { assert subject.valid? }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'without name' do
|
48
|
+
setup do
|
49
|
+
subject.stubs(:name).returns(nil)
|
50
|
+
subject.stubs(:certificate).returns('cert')
|
51
|
+
end
|
52
|
+
|
53
|
+
it { assert_not subject.valid? }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'without certificate' do
|
57
|
+
setup do
|
58
|
+
subject.stubs(:name).returns('name')
|
59
|
+
subject.stubs(:certificate).returns(nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
it { assert_not subject.valid? }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#save' do
|
67
|
+
context 'when valid' do
|
68
|
+
it 'creates auth method in the Vault' do
|
69
|
+
subject.stubs(:name).returns('name')
|
70
|
+
subject.stubs(:vault_policy_name).returns('vault_policy_name')
|
71
|
+
subject.stubs(:certificate).returns('cert')
|
72
|
+
|
73
|
+
subject.expects(:set_certificate).once.with(
|
74
|
+
'name',
|
75
|
+
certificate: 'cert',
|
76
|
+
token_policies: 'vault_policy_name',
|
77
|
+
allowed_common_names: [host.fqdn]
|
78
|
+
)
|
79
|
+
subject.save
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when not valid' do
|
84
|
+
it 'does not create auth method in the Vault' do
|
85
|
+
subject.stubs(:valid?).returns(false)
|
86
|
+
|
87
|
+
subject.expects(:set_certificate).never
|
88
|
+
subject.save
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#delete' do
|
94
|
+
context 'with name' do
|
95
|
+
it 'deletes Certificate' do
|
96
|
+
subject.stubs(:name).returns('name')
|
97
|
+
|
98
|
+
subject.expects(:delete_certificate).once.with(subject.name)
|
99
|
+
subject.delete
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'without name' do
|
104
|
+
it 'does not delete Certificate' do
|
105
|
+
subject.stubs(:name).returns(nil)
|
106
|
+
|
107
|
+
subject.expects(:delete_certificate).never
|
108
|
+
subject.delete
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#certificate' do
|
114
|
+
setup do
|
115
|
+
Setting.find_by(name: 'ssl_ca_file').update(value: cert_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when certificate file can be read' do
|
119
|
+
let(:cert_path) { File.join(ForemanVault::Engine.root, 'test/fixtures/ca.crt') }
|
120
|
+
|
121
|
+
it { assert_equal File.read(cert_path), subject.send(:certificate) }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when certificate file cannot be read' do
|
125
|
+
let(:cert_path) { '/tmp/invalid.crt' }
|
126
|
+
|
127
|
+
it { assert_not subject.send(:certificate) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
5
|
+
class VaultPolicyTest < ActiveSupport::TestCase
|
6
|
+
subject { ForemanVault::VaultPolicy.new(host) }
|
7
|
+
|
8
|
+
let(:host) { FactoryBot.create(:host, :managed) }
|
9
|
+
|
10
|
+
setup do
|
11
|
+
FactoryBot.create(:setting, name: 'vault_policy_template', value: 'Default Vault Policy')
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'valid?' do
|
15
|
+
context 'with name and rules' do
|
16
|
+
setup do
|
17
|
+
subject.stubs(:name).returns('name')
|
18
|
+
subject.stubs(:rules).returns('rules')
|
19
|
+
end
|
20
|
+
|
21
|
+
it { assert subject.valid? }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'without name' do
|
25
|
+
setup do
|
26
|
+
subject.stubs(:name).returns(nil)
|
27
|
+
subject.stubs(:rules).returns('rules')
|
28
|
+
end
|
29
|
+
|
30
|
+
it { assert_not subject.valid? }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'without rules' do
|
34
|
+
setup do
|
35
|
+
subject.stubs(:name).returns('name')
|
36
|
+
subject.stubs(:rules).returns(nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
it { assert_not subject.valid? }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#name' do
|
44
|
+
context 'without corresponding Vault Policy template' do
|
45
|
+
it { assert_nil subject.name }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with corresponding Vault Policy template' do
|
49
|
+
setup do
|
50
|
+
FactoryBot.create(:provisioning_template, :vault_policy, template: template)
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:template) { '# NAME: <%= @host.name %>' }
|
54
|
+
|
55
|
+
it { assert_equal host.name.parameterize, subject.name }
|
56
|
+
|
57
|
+
context 'when name is empty' do
|
58
|
+
let(:template) { '# NAME:' }
|
59
|
+
|
60
|
+
it { assert_nil subject.name }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when there is no name magic comment' do
|
64
|
+
let(:template) { '# BLAH:' }
|
65
|
+
|
66
|
+
it { assert_nil subject.name }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#new?' do
|
72
|
+
setup do
|
73
|
+
FactoryBot.create(:provisioning_template, :vault_policy)
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'policy already exists in the Vault' do
|
77
|
+
setup do
|
78
|
+
subject.stubs(:policies).returns([subject.name])
|
79
|
+
end
|
80
|
+
|
81
|
+
it { assert_not subject.new? }
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'policy does not exist in the Vault' do
|
85
|
+
setup do
|
86
|
+
subject.stubs(:policies).returns([])
|
87
|
+
end
|
88
|
+
|
89
|
+
it { assert subject.new? }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#save' do
|
94
|
+
context 'when valid' do
|
95
|
+
it 'creates Vault Policy' do
|
96
|
+
subject.stubs(:name).returns('name')
|
97
|
+
subject.stubs(:rules).returns('rules')
|
98
|
+
|
99
|
+
subject.expects(:put_policy).once.with(subject.name, subject.send(:rules))
|
100
|
+
subject.save
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when not valid' do
|
105
|
+
it 'does not create Vault Policy' do
|
106
|
+
subject.stubs(:valid?).returns(false)
|
107
|
+
|
108
|
+
subject.expects(:set_certificate).never
|
109
|
+
subject.save
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#delete' do
|
115
|
+
context 'with name' do
|
116
|
+
it 'deletes Vault Policy' do
|
117
|
+
subject.stubs(:name).returns('name')
|
118
|
+
|
119
|
+
subject.expects(:delete_policy).once.with(subject.name)
|
120
|
+
subject.delete
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'without name' do
|
125
|
+
it 'does not delete Vault Policy' do
|
126
|
+
subject.stubs(:name).returns(nil)
|
127
|
+
|
128
|
+
subject.expects(:delete_policy).never
|
129
|
+
subject.delete
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#rules' do
|
135
|
+
context 'without corresponding Vault Policy template' do
|
136
|
+
it { assert_nil subject.send(:rules) }
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with corresponding Vault Policy template' do
|
140
|
+
let(:rules) { 'path "secrets/data/*" { capabilities = ["create", "read", "update"] }' }
|
141
|
+
|
142
|
+
setup do
|
143
|
+
FactoryBot.create(:provisioning_template, :vault_policy, template: template)
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:template) do
|
147
|
+
<<~TEMPLATE
|
148
|
+
# NAME: <%= @host.name %>
|
149
|
+
|
150
|
+
#{rules}
|
151
|
+
TEMPLATE
|
152
|
+
end
|
153
|
+
|
154
|
+
it { assert_equal "#{rules}\n", subject.send(:rules) }
|
155
|
+
|
156
|
+
context 'when Vault Policy template renders empty' do
|
157
|
+
let(:template) do
|
158
|
+
<<~TEMPLATE
|
159
|
+
# NAME: <%= @host.name %>
|
160
|
+
|
161
|
+
<% if false %>
|
162
|
+
#{rules}
|
163
|
+
<% end %>
|
164
|
+
TEMPLATE
|
165
|
+
end
|
166
|
+
|
167
|
+
it { assert_nil subject.send(:rules) }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
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: 0.
|
4
|
+
version: 0.2.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: 2020-03
|
11
|
+
date: 2020-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vault
|
@@ -68,14 +68,20 @@ files:
|
|
68
68
|
- app/jobs/refresh_vault_token.rb
|
69
69
|
- app/jobs/refresh_vault_tokens.rb
|
70
70
|
- app/lib/foreman_vault/macros.rb
|
71
|
+
- app/models/concerns/foreman_vault/host_extensions.rb
|
72
|
+
- app/models/concerns/foreman_vault/orchestration/vault_policy.rb
|
73
|
+
- app/models/setting/vault.rb
|
71
74
|
- app/models/vault_connection.rb
|
75
|
+
- app/services/foreman_vault/vault_auth_method.rb
|
72
76
|
- app/services/foreman_vault/vault_client.rb
|
77
|
+
- app/services/foreman_vault/vault_policy.rb
|
73
78
|
- app/views/api/v2/vault_connections/base.json.rabl
|
74
79
|
- app/views/api/v2/vault_connections/create.json.rabl
|
75
80
|
- app/views/api/v2/vault_connections/index.json.rabl
|
76
81
|
- app/views/api/v2/vault_connections/main.json.rabl
|
77
82
|
- app/views/api/v2/vault_connections/show.json.rabl
|
78
83
|
- app/views/api/v2/vault_connections/update.json.rabl
|
84
|
+
- app/views/unattended/provisioning_templates/VaultPolicy/default.erb
|
79
85
|
- app/views/vault_connections/_form.html.erb
|
80
86
|
- app/views/vault_connections/edit.html.erb
|
81
87
|
- app/views/vault_connections/index.html.erb
|
@@ -85,6 +91,7 @@ files:
|
|
85
91
|
- config/routes.rb
|
86
92
|
- db/migrate/20180725072913_create_vault_connection.foreman_vault.rb
|
87
93
|
- db/migrate/20180809172407_rename_vault_status_to_vault_error.foreman_vault.rb
|
94
|
+
- db/seeds.d/103-provisioning_templates.rb
|
88
95
|
- lib/foreman_vault.rb
|
89
96
|
- lib/foreman_vault/engine.rb
|
90
97
|
- lib/foreman_vault/version.rb
|
@@ -93,14 +100,20 @@ files:
|
|
93
100
|
- locale/en/foreman_vault.po
|
94
101
|
- locale/foreman_vault.pot
|
95
102
|
- locale/gemspec.rb
|
96
|
-
- test/factories/
|
103
|
+
- test/factories/vault_connection.rb
|
104
|
+
- test/factories/vault_policy_template.rb
|
105
|
+
- test/factories/vault_setting.rb
|
106
|
+
- test/fixtures/ca.crt
|
97
107
|
- test/functional/api/v2/vault_connections_controller_test.rb
|
98
108
|
- test/jobs/refresh_vault_token_test.rb
|
99
109
|
- test/jobs/refresh_vault_tokens_test.rb
|
110
|
+
- test/models/foreman_vault/orchestration/vault_policy_test.rb
|
100
111
|
- test/models/vault_connection_test.rb
|
101
112
|
- test/test_plugin_helper.rb
|
102
113
|
- test/unit/lib/foreman_vault/macros_test.rb
|
114
|
+
- test/unit/services/foreman_vault/vault_auth_method_test.rb
|
103
115
|
- test/unit/services/foreman_vault/vault_client_test.rb
|
116
|
+
- test/unit/services/foreman_vault/vault_policy_test.rb
|
104
117
|
homepage: https://github.com/dm-drogeriemarkt/foreman_vault
|
105
118
|
licenses:
|
106
119
|
- GPL-3.0
|
@@ -120,16 +133,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
133
|
- !ruby/object:Gem::Version
|
121
134
|
version: '0'
|
122
135
|
requirements: []
|
123
|
-
|
124
|
-
rubygems_version: 2.7.6.2
|
136
|
+
rubygems_version: 3.1.2
|
125
137
|
signing_key:
|
126
138
|
specification_version: 4
|
127
139
|
summary: Adds support for using credentials from Hashicorp Vault
|
128
140
|
test_files:
|
129
141
|
- test/unit/lib/foreman_vault/macros_test.rb
|
130
142
|
- test/unit/services/foreman_vault/vault_client_test.rb
|
143
|
+
- test/unit/services/foreman_vault/vault_policy_test.rb
|
144
|
+
- test/unit/services/foreman_vault/vault_auth_method_test.rb
|
131
145
|
- test/models/vault_connection_test.rb
|
132
|
-
- test/
|
146
|
+
- test/models/foreman_vault/orchestration/vault_policy_test.rb
|
147
|
+
- test/factories/vault_policy_template.rb
|
148
|
+
- test/factories/vault_connection.rb
|
149
|
+
- test/factories/vault_setting.rb
|
150
|
+
- test/fixtures/ca.crt
|
133
151
|
- test/test_plugin_helper.rb
|
134
152
|
- test/jobs/refresh_vault_tokens_test.rb
|
135
153
|
- test/jobs/refresh_vault_token_test.rb
|