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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ae077f554e08226360e85ff0f76687f9c54e312b78bedc70efef11bc7e8f334
4
- data.tar.gz: dc35f0f802d0596c0f826d4220eb86006b3f58dec734d9cfd95871f26d002b6f
3
+ metadata.gz: 340e62f20ed55a76d6d22ef7e5bf7b3b58a8197a42224019e48384fd10e8b090
4
+ data.tar.gz: 5f5d0490d9d4ea43d46653abba3120b8a4e1eb08da85ff1927d1364fe7ab2de3
5
5
  SHA512:
6
- metadata.gz: fcd8996dc26ffd1f5eb6f66b34aedd7859cfb866a8dc3a84b5043293fafc78475845e92b19e0e2742f0bdabd8dd6b0af6086521e35f82734fedbdb8c12f14583
7
- data.tar.gz: e99e99aa6338c7d2438f1f4e9a49039161bdb40e9034e53b4d60a8e59a6971f8f001b812796dfd928e3f038ddb08e0d0434679eee8513cb44a3bd2e1bc03484f
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 use `vault_secret(vault_connection_name, secret_path)` macro in your templates to fetch secrets from Vault (you can write secrets with the `$ vault write kv/my_secret foo=bar` command), e.g.
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>
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanVault
4
- VERSION = '0.0.1'
4
+ VERSION = '0.1.0'
5
5
  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
- refute VaultConnection.exists?(@vault_connection.id)
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.1
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: 2019-01-21 00:00:00.000000000 Z
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.3
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