beaker-pe 2.0.2 → 2.0.3

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
  SHA1:
3
- metadata.gz: 4669811fd96282e6cbb309d4d65eb083e25e5222
4
- data.tar.gz: f28009cebec926e2ade3db68ce801ab958208718
3
+ metadata.gz: 472cb8527da6bbb6256c8342fff325b91dfe0d62
4
+ data.tar.gz: 75b005236142feec1df7954cac688d4d4f9f613c
5
5
  SHA512:
6
- metadata.gz: d96ae7fc50c9a581781519459735ed8923a843b110f1ad0d9827c8e46b617c333287ad7353dbb915ebf7c12bb4f5d351e73cd8ed21d583b6097db1b8e6e47e88
7
- data.tar.gz: 25a4f33451f1faa88aa410c209980ffa607c77f5fba71df18b504b0acc8b3b42be8f83221fae6f7eca17b44f95395fb965bcc2a79c9c5b01569b68d152e73be6
6
+ metadata.gz: 24d74792e19f75a3d33f30de4644878dcc742a00b872775c8e30965a891e86641a89fff1a106cdf0a6b8fd9260dfb886890c013ac908f55e609d709419d5e554
7
+ data.tar.gz: 05daf324e0665af413f85c35dbefc81e2cc1e310bfb734328f93adb02ba4298993f4c41843a299e41200f36040efa8b9dd6e6c1d82319c99110337b79ca73a8b
data/Gemfile CHANGED
@@ -17,9 +17,7 @@ group :acceptance_testing do
17
17
  gem "beaker-vmpooler", *location_for(ENV['BEAKER_VMPOOLER_VERSION'] || '~> 1.3')
18
18
  end
19
19
 
20
- if ENV['GEM_SOURCE'] =~ /artifactory\.delivery\.puppetlabs\.net/
21
- gem "scooter", *location_for(ENV['SCOOTER_VERSION'] || '~> 3.0')
22
- end
20
+ gem "scooter", *location_for(ENV['SCOOTER_VERSION'] || '~> 4.3')
23
21
 
24
22
  gem 'deep_merge'
25
23
 
data/lib/beaker-pe.rb CHANGED
@@ -5,6 +5,7 @@ require 'stringify-hash'
5
5
  require 'beaker-pe/version'
6
6
  require 'beaker-pe/install/pe_defaults'
7
7
  require 'beaker-pe/install/pe_utils'
8
+ require 'beaker-pe/install/ca_utils'
8
9
  require 'beaker-pe/options/pe_version_scraper'
9
10
  require 'beaker-pe/pe-client-tools/config_file_helper'
10
11
  require 'beaker-pe/pe-client-tools/install_helper'
@@ -16,6 +17,7 @@ module Beaker
16
17
  include Beaker::DSL::InstallUtils::PEDefaults
17
18
  include Beaker::DSL::InstallUtils::PEUtils
18
19
  include Beaker::DSL::InstallUtils::PEClientTools
20
+ include Beaker::DSL::InstallUtils::CAUtils
19
21
  include Beaker::Options::PEVersionScraper
20
22
  include Beaker::DSL::PEClientTools::ConfigFileHelper
21
23
  include Beaker::DSL::PEClientTools::ExecutableHelper
@@ -0,0 +1,192 @@
1
+ #Much of this is taken from PuppetSpec:SSL
2
+ require "openssl"
3
+
4
+ module Beaker
5
+ module DSL
6
+ module InstallUtils
7
+ module CAUtils
8
+ PRIVATE_KEY_LENGTH = 2048
9
+ FIVE_YEARS = 5 * 365 * 24 * 60 * 60
10
+ CA_EXTENSIONS = [
11
+ ["basicConstraints", "CA:TRUE", true],
12
+ ["keyUsage", "keyCertSign, cRLSign", true],
13
+ ["subjectKeyIdentifier", "hash", false],
14
+ ["authorityKeyIdentifier", "keyid:always", false]
15
+ ]
16
+ NODE_EXTENSIONS = [
17
+ ["keyUsage", "digitalSignature", true],
18
+ ["subjectKeyIdentifier", "hash", false]
19
+ ]
20
+ DEFAULT_SIGNING_DIGEST = OpenSSL::Digest::SHA256.new
21
+ DEFAULT_REVOCATION_REASON = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE
22
+ ROOT_CA_NAME = "/CN=root-ca"
23
+ INT_CA_NAME = "/CN=intermediate-ca"
24
+ EXPLANATORY_TEXT = <<-EOT
25
+ # Root Issuer: #{ROOT_CA_NAME}
26
+ # Intermediate Issuer: #{INT_CA_NAME}
27
+ EOT
28
+
29
+ # Generate CA bundle with root and intermediate certs, as well as CRL chain and private key for
30
+ # the intermediate CA, pushed to the host for use during PE install with pe_install::signing_ca
31
+ #
32
+ # @param [Host] host The host to create CA bundle files on. Defaults to global 'master' object.
33
+ # @param [String] targetdir Location to save files on host, to be referenced in pe.conf for install.
34
+ # @return [Hash] File names => where they were put on the host
35
+ def generate_ca_bundle_on(host = master, targetdir = '/tmp/ca_bundle')
36
+ files = {}
37
+ pki = create_chained_pki
38
+ on(host, "mkdir -p #{targetdir}", :acceptable_exit_codes => [0])
39
+ pki.each do |name,cert|
40
+ create_remote_file(host, "#{targetdir}/#{name}", cert.to_s, :acceptable_exit_codes => [0])
41
+ files["#{name}".to_sym] = "#{targetdir}/#{name}"
42
+ end
43
+ files
44
+ end
45
+
46
+ def create_private_key(length = PRIVATE_KEY_LENGTH)
47
+ OpenSSL::PKey::RSA.new(length)
48
+ end
49
+
50
+ def self_signed_ca(key, name)
51
+ cert = OpenSSL::X509::Certificate.new
52
+
53
+ cert.public_key = key.public_key
54
+ cert.subject = OpenSSL::X509::Name.parse(name)
55
+ cert.issuer = cert.subject
56
+ cert.version = 2
57
+ cert.serial = rand(2**128)
58
+
59
+ not_before = just_now
60
+ cert.not_before = not_before
61
+ cert.not_after = not_before + FIVE_YEARS
62
+
63
+ ext_factory = extension_factory_for(cert, cert)
64
+ CA_EXTENSIONS.each do |ext|
65
+ extension = ext_factory.create_extension(*ext)
66
+ cert.add_extension(extension)
67
+ end
68
+
69
+ cert.sign(key, DEFAULT_SIGNING_DIGEST)
70
+
71
+ cert
72
+ end
73
+
74
+ def create_csr(key, name)
75
+ csr = OpenSSL::X509::Request.new
76
+
77
+ csr.public_key = key.public_key
78
+ csr.subject = OpenSSL::X509::Name.parse(name)
79
+ csr.version = 2
80
+ csr.sign(key, DEFAULT_SIGNING_DIGEST)
81
+
82
+ csr
83
+ end
84
+
85
+ def sign(ca_key, ca_cert, csr, extensions = NODE_EXTENSIONS)
86
+ cert = OpenSSL::X509::Certificate.new
87
+
88
+ cert.public_key = csr.public_key
89
+ cert.subject = csr.subject
90
+ cert.issuer = ca_cert.subject
91
+ cert.version = 2
92
+ cert.serial = rand(2**128)
93
+
94
+ not_before = just_now
95
+ cert.not_before = not_before
96
+ cert.not_after = not_before + FIVE_YEARS
97
+
98
+ ext_factory = extension_factory_for(ca_cert, cert)
99
+ extensions.each do |ext|
100
+ extension = ext_factory.create_extension(*ext)
101
+ cert.add_extension(extension)
102
+ end
103
+
104
+ cert.sign(ca_key, DEFAULT_SIGNING_DIGEST)
105
+
106
+ cert
107
+ end
108
+
109
+ def create_crl_for(ca_cert, ca_key)
110
+ crl = OpenSSL::X509::CRL.new
111
+ crl.version = 1
112
+ crl.issuer = ca_cert.subject
113
+
114
+ ef = extension_factory_for(ca_cert)
115
+ crl.add_extension(
116
+ ef.create_extension(["authorityKeyIdentifier", "keyid:always", false]))
117
+ crl.add_extension(
118
+ OpenSSL::X509::Extension.new("crlNumber", OpenSSL::ASN1::Integer(0)))
119
+
120
+ not_before = just_now
121
+ crl.last_update = not_before
122
+ crl.next_update = not_before + FIVE_YEARS
123
+ crl.sign(ca_key, DEFAULT_SIGNING_DIGEST)
124
+
125
+ crl
126
+ end
127
+
128
+ def revoke(serial, crl, ca_key)
129
+ revoked = OpenSSL::X509::Revoked.new
130
+ revoked.serial = serial
131
+ revoked.time = Time.now
132
+ revoked.add_extension(
133
+ OpenSSL::X509::Extension.new("CRLReason",
134
+ OpenSSL::ASN1::Enumerated(DEFAULT_REVOCATION_REASON)))
135
+
136
+ crl.add_revoked(revoked)
137
+ extensions = crl.extensions.group_by{|e| e.oid == 'crlNumber' }
138
+ crl_number = extensions[true].first
139
+ unchanged_exts = extensions[false]
140
+
141
+ next_crl_number = crl_number.value.to_i + 1
142
+ new_crl_number_ext = OpenSSL::X509::Extension.new("crlNumber",
143
+ OpenSSL::ASN1::Integer(next_crl_number))
144
+
145
+ crl.extensions = unchanged_exts + [new_crl_number_ext]
146
+ crl.sign(ca_key, DEFAULT_SIGNING_DIGEST)
147
+
148
+ crl
149
+ end
150
+
151
+ def create_chained_pki
152
+ root_key = create_private_key
153
+ root_cert = self_signed_ca(root_key, ROOT_CA_NAME)
154
+ root_crl = create_crl_for(root_cert, root_key)
155
+
156
+ int_key = create_private_key
157
+ int_csr = create_csr(int_key, INT_CA_NAME)
158
+ int_cert = sign(root_key, root_cert, int_csr, CA_EXTENSIONS)
159
+ int_crl = create_crl_for(int_cert, int_key)
160
+
161
+ int_ca_bundle = bundle(int_cert, root_cert)
162
+ int_crl_chain = bundle(int_crl, root_crl)
163
+
164
+ {
165
+ :root_cert => root_cert,
166
+ :int_cert => int_cert,
167
+ :int_ca_bundle => int_ca_bundle,
168
+ :int_key => int_key,
169
+ :int_crl_chain => int_crl_chain,
170
+ }
171
+ end
172
+
173
+ def just_now
174
+ Time.now - 1
175
+ end
176
+
177
+ def extension_factory_for(ca, cert = nil)
178
+ ef = OpenSSL::X509::ExtensionFactory.new
179
+ ef.issuer_certificate = ca
180
+ ef.subject_certificate = cert if cert
181
+
182
+ ef
183
+ end
184
+
185
+ def bundle(*items)
186
+ items.map {|i| EXPLANATORY_TEXT + i.to_pem }.join("\n")
187
+ end
188
+
189
+ end
190
+ end
191
+ end
192
+ end
@@ -3,7 +3,7 @@ module Beaker
3
3
  module PE
4
4
 
5
5
  module Version
6
- STRING = '2.0.2'
6
+ STRING = '2.0.3'
7
7
  end
8
8
 
9
9
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ include Beaker::DSL::InstallUtils::CAUtils
3
+
4
+ describe Beaker::DSL::InstallUtils::CAUtils do
5
+ let(:dummy_pki) {
6
+ {
7
+ :root_cert => 'dummy_root_cert',
8
+ :int_cert => 'dummy_int_cert',
9
+ :int_ca_bundle => 'dummy_int_bundle',
10
+ :int_key => 'dummy_int_key',
11
+ :int_crl_chain => 'dummy_int_crl_chain',
12
+ }
13
+ }
14
+
15
+ before(:each) do
16
+ allow(subject).to receive(:create_chained_pki).and_return(dummy_pki)
17
+ end
18
+
19
+ describe 'generate_ca_bundle_on' do
20
+ let(:host) { make_host( 'unixhost', { :platform => 'linux'})}
21
+ let(:bundledir) { '/tmp/ca_bundle' }
22
+ let(:expected) {
23
+ {
24
+ :root_cert => "#{bundledir}/root_cert",
25
+ :int_cert => "#{bundledir}/int_cert",
26
+ :int_ca_bundle => "#{bundledir}/int_ca_bundle",
27
+ :int_key => "#{bundledir}/int_key",
28
+ :int_crl_chain => "#{bundledir}/int_crl_chain",
29
+ }
30
+ }
31
+
32
+ it "generates certs on host" do
33
+ expect(subject).to receive(:on).with(host, "mkdir -p #{bundledir}", :acceptable_exit_codes => [0])
34
+ expect(subject).to receive(:create_remote_file).with(host,"#{bundledir}/root_cert", "dummy_root_cert", :acceptable_exit_codes => [0])
35
+ expect(subject).to receive(:create_remote_file).with(host,"#{bundledir}/int_cert", "dummy_int_cert", :acceptable_exit_codes => [0])
36
+ expect(subject).to receive(:create_remote_file).with(host,"#{bundledir}/int_ca_bundle", "dummy_int_bundle", :acceptable_exit_codes => [0])
37
+ expect(subject).to receive(:create_remote_file).with(host,"#{bundledir}/int_key", "dummy_int_key", :acceptable_exit_codes => [0])
38
+ expect(subject).to receive(:create_remote_file).with(host,"#{bundledir}/int_crl_chain", "dummy_int_crl_chain", :acceptable_exit_codes => [0])
39
+ expect( subject.generate_ca_bundle_on(host,"#{bundledir}") ).to eq(expected)
40
+ end
41
+ end
42
+ end
@@ -64,25 +64,66 @@ describe MixedWithExecutableHelper do
64
64
 
65
65
  context 'puppet access login with lifetime parameter' do
66
66
  let(:logger) {Beaker::Logger.new}
67
- let(:test_host) {Beaker::Host.create('my_super_host',
68
- {:roles => ['master', 'agent'],
69
- :platform => 'linux',
70
- :type => 'pe'},
71
- make_opts)}
72
- let(:username) {'T'}
73
- let(:password) {'Swift'}
74
- let(:credentials) {{:login => username, :password => password}}
75
- let(:test_dispatcher) {Scooter::HttpDispatchers::ConsoleDispatcher.new('my_super_host', credentials)}
67
+ let(:test_host) {
68
+ make_host('my_super_host', {
69
+ :roles => ['master', 'agent'],
70
+ :platform => 'linux',
71
+ :type => 'pe'
72
+ }
73
+ )
74
+ }
75
+ let(:credentials) {
76
+ mock = Object.new
77
+ allow(mock).to receive(:login).and_return('T')
78
+ allow(mock).to receive(:password).and_return('Swift')
79
+ mock
80
+ }
81
+ let(:test_dispatcher) {
82
+ mock = Object.new
83
+ allow(mock).to receive(:credentials).and_return(credentials)
84
+ mock
85
+ }
76
86
 
77
87
  before do
78
88
  allow(logger).to receive(:debug) { true }
79
- expect(test_dispatcher).to be_kind_of(Scooter::HttpDispatchers::ConsoleDispatcher)
80
89
  expect(test_host).to be_kind_of(Beaker::Host)
81
- expect(test_host).to receive(:exec)
82
90
  end
83
91
 
84
- it 'accepts correct value' do
85
- expect{subject.login_with_puppet_access_on(test_host, test_dispatcher, {:lifetime => '5d'})}.not_to raise_error
92
+ it 'passes the lifetime value to :puppet_access_on on linux' do
93
+ lifetime_value = '5d'
94
+
95
+ expect(subject).to receive(:puppet_access_on).with(
96
+ test_host,
97
+ "login",
98
+ "--lifetime #{lifetime_value}",
99
+ anything
100
+ )
101
+
102
+ expect{
103
+ subject.login_with_puppet_access_on(
104
+ test_host,
105
+ test_dispatcher,
106
+ {:lifetime => lifetime_value}
107
+ )
108
+ }.not_to raise_error
109
+ end
110
+
111
+ it 'passes the lifetime value to the passed dispatcher on windows' do
112
+ test_host[:platform] = "win-stuff"
113
+ allow(subject).to receive(:create_remote_file)
114
+ lifetime_value = '6d'
115
+
116
+ expect(test_dispatcher).to receive(
117
+ :acquire_token_with_credentials
118
+ ).with(lifetime_value)
119
+
120
+ expect{
121
+ subject.login_with_puppet_access_on(
122
+ test_host,
123
+ test_dispatcher,
124
+ {:lifetime => lifetime_value}
125
+ )
126
+ }.not_to raise_error
86
127
  end
87
128
  end
88
129
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beaker-pe
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppetlabs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-12 00:00:00.000000000 Z
11
+ date: 2018-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -253,6 +253,7 @@ files:
253
253
  - bin/beaker-template
254
254
  - docs/how_to/install_puppet_enterprise.md
255
255
  - lib/beaker-pe.rb
256
+ - lib/beaker-pe/install/ca_utils.rb
256
257
  - lib/beaker-pe/install/feature_flags.rb
257
258
  - lib/beaker-pe/install/pe_defaults.rb
258
259
  - lib/beaker-pe/install/pe_utils.rb
@@ -262,6 +263,7 @@ files:
262
263
  - lib/beaker-pe/pe-client-tools/install_helper.rb
263
264
  - lib/beaker-pe/version.rb
264
265
  - spec/beaker-pe/helpers_spec.rb
266
+ - spec/beaker-pe/install/ca_utils_spec.rb
265
267
  - spec/beaker-pe/install/feature_flags_spec.rb
266
268
  - spec/beaker-pe/install/pe_defaults_spec.rb
267
269
  - spec/beaker-pe/install/pe_utils_spec.rb