foreman_vault 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -3
- data/app/lib/foreman_vault/macros.rb +9 -0
- data/app/models/vault_connection.rb +2 -1
- data/app/services/foreman_vault/vault_client.rb +7 -0
- data/app/views/vault_connections/welcome.html.erb +12 -0
- data/lib/foreman_vault/engine.rb +1 -1
- data/lib/foreman_vault/version.rb +1 -1
- data/test/factories/foreman_vault_factories.rb +3 -3
- data/test/functional/api/v2/vault_connections_controller_test.rb +1 -1
- data/test/unit/services/foreman_vault/vault_client_test.rb +23 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 340e62f20ed55a76d6d22ef7e5bf7b3b58a8197a42224019e48384fd10e8b090
|
4
|
+
data.tar.gz: 5f5d0490d9d4ea43d46653abba3120b8a4e1eb08da85ff1927d1364fe7ab2de3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 142d5f6e82b6c30674c03653ebde20cdecece4f093f2a7b3fd0e3e621aaff4a7fa892683d69f14497d579b8b84167bbe1cc1e908eefef527e1cd26c3f49ffe15
|
7
|
+
data.tar.gz: 134ba4aee2e7db7ebe52174cc936a079978daf0c2e73edab230bdeada75e6bec317589ac789e0dc5003b6d092e36f86a4e40298e316b43469030537a495a4e53
|
data/README.md
CHANGED
@@ -21,7 +21,12 @@ $ vault secrets enable kv
|
|
21
21
|
|
22
22
|
To set up a connection between Foreman and Vault first navigate to the "Infrastructure" > "Vault Connections" menu and then hit the button labeled "Create Vault Connection". Now you should see a form. You have to fill in name, url and token (you can receive a token with the `$ vault token create -period=60m` command) and hit the "Submit" button.
|
23
23
|
|
24
|
-
You can now
|
24
|
+
You can now utilize two new macros in your templates:
|
25
|
+
- vault_secret(vault_connection_name, secret_path)
|
26
|
+
- vault_issue_certificate(vault_connection_name, pki_role_path, options...)
|
27
|
+
|
28
|
+
### vault_secret(vault_connection_name, secret_path)
|
29
|
+
To fetch secrets from Vault (you can write secrets with the `$ vault write kv/my_secret foo=bar` command), e.g.
|
25
30
|
|
26
31
|
```
|
27
32
|
<%= vault_secret('MyVault', 'kv/my_secret') %>
|
@@ -33,13 +38,23 @@ As result you should get secret data, e.g.
|
|
33
38
|
{:foo=>"bar"}
|
34
39
|
```
|
35
40
|
|
41
|
+
### 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
|
+
|
44
|
+
|
45
|
+
```
|
46
|
+
<%= vault_issue_certificate('MyVault', 'pkiEngine/issue/testRole', common_name: 'test.mydomain.com', ttl: '10s') %>
|
47
|
+
```
|
48
|
+
|
49
|
+
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)
|
50
|
+
|
36
51
|
## Contributing
|
37
52
|
|
38
53
|
Fork and send a Pull Request. Thanks!
|
39
54
|
|
40
55
|
## Copyright
|
41
56
|
|
42
|
-
Copyright (c) 2018 dmTECH GmbH, [dmtech.de](https://www.dmtech.de/)
|
57
|
+
Copyright (c) 2018-2020 dmTECH GmbH, [dmtech.de](https://www.dmtech.de/)
|
43
58
|
|
44
59
|
This program is free software: you can redistribute it and/or modify
|
45
60
|
it under the terms of the GNU General Public License as published by
|
@@ -52,4 +67,4 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
52
67
|
GNU General Public License for more details.
|
53
68
|
|
54
69
|
You should have received a copy of the GNU General Public License
|
55
|
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
70
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
@@ -5,11 +5,20 @@ module ForemanVault
|
|
5
5
|
def vault_secret(vault_connection_name, secret_path)
|
6
6
|
vault = VaultConnection.find_by!(name: vault_connection_name)
|
7
7
|
raise VaultError.new(N_('Invalid token for %s'), vault.name) unless vault.token_valid?
|
8
|
+
|
8
9
|
vault.fetch_secret(secret_path)
|
9
10
|
rescue ActiveRecord::RecordNotFound => e
|
10
11
|
raise VaultError, e.message
|
11
12
|
end
|
12
13
|
|
14
|
+
def vault_issue_certificate(vault_connection_name, secret_path, *options)
|
15
|
+
vault = VaultConnection.find_by!(name: vault_connection_name)
|
16
|
+
raise VaultError.new(N_('Invalid token for %s'), vault.name) unless vault.token_valid?
|
17
|
+
vault.issue_certificate(secret_path, *options)
|
18
|
+
rescue ActiveRecord::RecordNotFound => e
|
19
|
+
raise VaultError, e.message
|
20
|
+
end
|
21
|
+
|
13
22
|
class VaultError < Foreman::Exception; end
|
14
23
|
end
|
15
24
|
end
|
@@ -13,7 +13,7 @@ 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, to: :client
|
16
|
+
delegate :fetch_expire_time, :fetch_secret, :issue_certificate, to: :client
|
17
17
|
|
18
18
|
def token_valid?
|
19
19
|
vault_error.nil? && expire_time && expire_time > Time.zone.now
|
@@ -38,6 +38,7 @@ class VaultConnection < ApplicationRecord
|
|
38
38
|
self.expire_time = fetch_expire_time
|
39
39
|
rescue StandardError => e
|
40
40
|
errors.add(:base, e.message)
|
41
|
+
Foreman::Logging.exception('Failed to set vault expiry time', e)
|
41
42
|
throw(:abort)
|
42
43
|
end
|
43
44
|
|
@@ -17,6 +17,13 @@ module ForemanVault
|
|
17
17
|
def fetch_secret(secret_path)
|
18
18
|
response = client.logical.read(secret_path)
|
19
19
|
raise NoDataError.new(N_('There is no available data for path: %s'), secret_path) unless response
|
20
|
+
|
21
|
+
response.data
|
22
|
+
end
|
23
|
+
|
24
|
+
def issue_certificate(secret_path, *options)
|
25
|
+
response = client.logical.write(secret_path, *options)
|
26
|
+
raise NoDataError.new(N_('Could not issue certificate: %s'), secret_path) unless response
|
20
27
|
response.data
|
21
28
|
end
|
22
29
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="blank-slate-pf">
|
2
|
+
<div class="blank-slate-pf-icon">
|
3
|
+
<%= icon_text("shield", "", :kind => "fa") %>
|
4
|
+
</div>
|
5
|
+
<h1><%= _('Vault Connections') %></h1>
|
6
|
+
<p>
|
7
|
+
<%= _("HashiCorp Vault is a secrets management solution that brokers access for both humans and machines, through programmatic access, to systems. Secrets can be stored, dynamically generated, and in the case of encryption, keys can be consumed as a service without the need to expose the underlying key materials.") %></br>
|
8
|
+
</p>
|
9
|
+
<div class="blank-slate-pf-main-action">
|
10
|
+
<%= new_link(_("New Vault Connection"), {}, { :class => "btn-lg" }) %>
|
11
|
+
</div>
|
12
|
+
</div>
|
data/lib/foreman_vault/engine.rb
CHANGED
@@ -45,7 +45,7 @@ module ForemanVault
|
|
45
45
|
config.to_prepare do
|
46
46
|
begin
|
47
47
|
Foreman::Renderer::Scope::Base.include(ForemanVault::Macros)
|
48
|
-
Foreman::Renderer.configure { |c| c.allowed_generic_helpers += [:vault_secret] }
|
48
|
+
Foreman::Renderer.configure { |c| c.allowed_generic_helpers += [:vault_secret, :vault_issue_certificate] }
|
49
49
|
rescue StandardError => e
|
50
50
|
Rails.logger.warn "ForemanVault: skipping engine hook (#{e})"
|
51
51
|
end
|
@@ -3,12 +3,12 @@
|
|
3
3
|
FactoryBot.define do
|
4
4
|
factory :vault_connection, class: VaultConnection do
|
5
5
|
sequence(:name) { |n| "VaultServer-#{n}" }
|
6
|
-
url 'http://localhost:8200'
|
7
|
-
token '16aa4f29-035d-b604-f3d3-8cd9a6a6921c'
|
6
|
+
url { 'http://localhost:8200' }
|
7
|
+
token { '16aa4f29-035d-b604-f3d3-8cd9a6a6921c' }
|
8
8
|
expire_time { Time.zone.now + 1.year }
|
9
9
|
|
10
10
|
trait :invalid do
|
11
|
-
expire_time nil
|
11
|
+
expire_time { nil }
|
12
12
|
end
|
13
13
|
|
14
14
|
trait :without_callbacks do
|
@@ -72,7 +72,7 @@ module Api
|
|
72
72
|
assert VaultConnection.exists?(@vault_connection.id)
|
73
73
|
delete :destroy, params: { id: @vault_connection.to_param }
|
74
74
|
assert_response :success
|
75
|
-
|
75
|
+
assert_not VaultConnection.exists?(@vault_connection.id)
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -36,4 +36,27 @@ class VaultClientTest < ActiveSupport::TestCase
|
|
36
36
|
assert_equal @data, @subject.fetch_secret(@secret_path)
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
describe '#fetch_certificate' do
|
41
|
+
setup do
|
42
|
+
@pki_path = '/pkiEngine/issue/testRole'
|
43
|
+
@data = {
|
44
|
+
certificate: 'CERTIFICATE_DATA',
|
45
|
+
expiration: 1_582_116_230,
|
46
|
+
issuing_ca: 'CA_CERTIFICATE_DATA',
|
47
|
+
private_key: 'PRIVATE_KEY_DATA',
|
48
|
+
private_key_type: 'rsa',
|
49
|
+
serial_number: '7e:2d:c8:dd:df:da:fe:1f:39:da:39:23:4f:74:c8:1f:1d:4a:db:a7'
|
50
|
+
}
|
51
|
+
|
52
|
+
response = OpenStruct.new(data: @data)
|
53
|
+
logical = mock.tap { |object| object.expects(:write).once.with(@pki_path).returns(response) }
|
54
|
+
|
55
|
+
@client.expects(:logical).once.returns(logical)
|
56
|
+
end
|
57
|
+
|
58
|
+
test 'should return new certificate' do
|
59
|
+
assert_equal @data, @subject.issue_certificate(@pki_path)
|
60
|
+
end
|
61
|
+
end
|
39
62
|
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.0
|
4
|
+
version: 0.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:
|
11
|
+
date: 2020-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vault
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- app/views/vault_connections/edit.html.erb
|
81
81
|
- app/views/vault_connections/index.html.erb
|
82
82
|
- app/views/vault_connections/new.html.erb
|
83
|
+
- app/views/vault_connections/welcome.html.erb
|
83
84
|
- config/foreman_vault.yaml.example
|
84
85
|
- config/routes.rb
|
85
86
|
- db/migrate/20180725072913_create_vault_connection.foreman_vault.rb
|
@@ -120,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
121
|
version: '0'
|
121
122
|
requirements: []
|
122
123
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.7.
|
124
|
+
rubygems_version: 2.7.6.2
|
124
125
|
signing_key:
|
125
126
|
specification_version: 4
|
126
127
|
summary: Adds support for using credentials from Hashicorp Vault
|