bolt 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +5 -2
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +5 -8
- data/lib/bolt/applicator.rb +11 -8
- data/lib/bolt/boltdir.rb +13 -5
- data/lib/bolt/catalog.rb +22 -47
- data/lib/bolt/config.rb +1 -26
- data/lib/bolt/executor.rb +1 -1
- data/lib/bolt/outputter.rb +0 -9
- data/lib/bolt/outputter/human.rb +29 -14
- data/lib/bolt/outputter/json.rb +12 -1
- data/lib/bolt/pal.rb +12 -10
- data/lib/bolt/target.rb +0 -6
- data/lib/bolt/task.rb +53 -10
- data/lib/bolt/transport/base.rb +1 -6
- data/lib/bolt/transport/local.rb +11 -13
- data/lib/bolt/transport/local/shell.rb +2 -2
- data/lib/bolt/transport/ssh.rb +16 -11
- data/lib/bolt/transport/winrm.rb +8 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_ext/schemas/task.json +12 -5
- data/libexec/apply_catalog.rb +3 -1
- data/libexec/bolt_catalog +4 -0
- data/vendored/puppet/lib/puppet.rb +2 -1
- data/vendored/puppet/lib/puppet/application/agent.rb +2 -6
- data/vendored/puppet/lib/puppet/application/apply.rb +100 -60
- data/vendored/puppet/lib/puppet/application/cert.rb +26 -291
- data/vendored/puppet/lib/puppet/application/device.rb +0 -5
- data/vendored/puppet/lib/puppet/application/lookup.rb +1 -1
- data/vendored/puppet/lib/puppet/application/ssl.rb +133 -0
- data/vendored/puppet/lib/puppet/application_support.rb +1 -2
- data/vendored/puppet/lib/puppet/configurer.rb +34 -50
- data/vendored/puppet/lib/puppet/configurer/downloader.rb +1 -1
- data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +1 -1
- data/vendored/puppet/lib/puppet/daemon.rb +1 -1
- data/vendored/puppet/lib/puppet/defaults.rb +40 -117
- data/vendored/puppet/lib/puppet/face/epp.rb +2 -2
- data/vendored/puppet/lib/puppet/face/help.rb +21 -7
- data/vendored/puppet/lib/puppet/face/node/clean.rb +14 -10
- data/vendored/puppet/lib/puppet/feature/base.rb +7 -23
- data/vendored/puppet/lib/puppet/feature/eventlog.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/base.rb +2 -2
- data/vendored/puppet/lib/puppet/file_serving/fileset.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/metadata.rb +2 -2
- data/vendored/puppet/lib/puppet/functions.rb +133 -0
- data/vendored/puppet/lib/puppet/functions/eyaml_lookup_key.rb +4 -5
- data/vendored/puppet/lib/puppet/functions/filter.rb +7 -6
- data/vendored/puppet/lib/puppet/functions/new.rb +37 -53
- data/vendored/puppet/lib/puppet/functions/warning.rb +1 -1
- data/vendored/puppet/lib/puppet/functions/yaml_data.rb +4 -5
- data/vendored/puppet/lib/puppet/gettext/config.rb +1 -1
- data/vendored/puppet/lib/puppet/graph.rb +0 -2
- data/vendored/puppet/lib/puppet/indirector/catalog/json.rb +14 -3
- data/vendored/puppet/lib/puppet/indirector/catalog/yaml.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/file.rb +0 -1
- data/vendored/puppet/lib/puppet/indirector/facts/yaml.rb +4 -2
- data/vendored/puppet/lib/puppet/indirector/key/file.rb +1 -6
- data/vendored/puppet/lib/puppet/indirector/node/exec.rb +1 -3
- data/vendored/puppet/lib/puppet/indirector/node/yaml.rb +0 -6
- data/vendored/puppet/lib/puppet/indirector/request.rb +1 -1
- data/vendored/puppet/lib/puppet/indirector/ssl_file.rb +3 -44
- data/vendored/puppet/lib/puppet/indirector/yaml.rb +4 -4
- data/vendored/puppet/lib/puppet/info_service/task_information_service.rb +7 -3
- data/vendored/puppet/lib/puppet/loaders.rb +1 -0
- data/vendored/puppet/lib/puppet/module/task.rb +198 -29
- data/vendored/puppet/lib/puppet/module_tool/applications/unpacker.rb +1 -1
- data/vendored/puppet/lib/puppet/network/format_support.rb +13 -8
- data/vendored/puppet/lib/puppet/network/formats.rb +93 -2
- data/vendored/puppet/lib/puppet/network/http/api/indirected_routes.rb +10 -3
- data/vendored/puppet/lib/puppet/node/facts.rb +11 -1
- data/vendored/puppet/lib/puppet/parser/catalog_compiler.rb +56 -0
- data/vendored/puppet/lib/puppet/parser/compiler.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions/filter.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/generate.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/sprintf.rb +12 -1
- data/vendored/puppet/lib/puppet/parser/functions/tagged.rb +1 -4
- data/vendored/puppet/lib/puppet/parser/scope.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/script_compiler.rb +7 -2
- data/vendored/puppet/lib/puppet/pops/evaluator/deferred_resolver.rb +5 -3
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_converter.rb +23 -4
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
- data/vendored/puppet/lib/puppet/pops/functions/dispatch.rb +4 -0
- data/vendored/puppet/lib/puppet/pops/issues.rb +8 -0
- data/vendored/puppet/lib/puppet/pops/loader/loader.rb +2 -2
- data/vendored/puppet/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/vendored/puppet/lib/puppet/pops/loader/module_loaders.rb +30 -9
- data/vendored/puppet/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
- data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +0 -1
- data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +13 -70
- data/vendored/puppet/lib/puppet/pops/loaders.rb +19 -29
- data/vendored/puppet/lib/puppet/pops/lookup/hiera_config.rb +1 -1
- data/vendored/puppet/lib/puppet/pops/model/model_label_provider.rb +4 -1
- data/vendored/puppet/lib/puppet/pops/pcore.rb +10 -33
- data/vendored/puppet/lib/puppet/pops/serialization.rb +2 -0
- data/vendored/puppet/lib/puppet/pops/serialization/from_data_converter.rb +2 -1
- data/vendored/puppet/lib/puppet/pops/serialization/to_data_converter.rb +11 -3
- data/vendored/puppet/lib/puppet/pops/serialization/to_stringified_converter.rb +226 -0
- data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +3 -0
- data/vendored/puppet/lib/puppet/pops/validation/checker4_0.rb +97 -47
- data/vendored/puppet/lib/puppet/pops/validation/validator_factory_4_0.rb +7 -8
- data/vendored/puppet/lib/puppet/property/keyvalue.rb +70 -8
- data/vendored/puppet/lib/puppet/provider/aix_object.rb +483 -0
- data/vendored/puppet/lib/puppet/provider/file/windows.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/group/aix.rb +51 -112
- data/vendored/puppet/lib/puppet/provider/package/gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/pip.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/puppet_gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/rpm.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/windows/package.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/zypper.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/systemd.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/windows.rb +37 -40
- data/vendored/puppet/lib/puppet/provider/user/aix.rb +142 -254
- data/vendored/puppet/lib/puppet/resource.rb +20 -3
- data/vendored/puppet/lib/puppet/resource/catalog.rb +2 -12
- data/vendored/puppet/lib/puppet/rest/routes.rb +97 -34
- data/vendored/puppet/lib/puppet/settings.rb +1 -1
- data/vendored/puppet/lib/puppet/settings/file_setting.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/base.rb +1 -9
- data/vendored/puppet/lib/puppet/ssl/certificate_request.rb +1 -13
- data/vendored/puppet/lib/puppet/ssl/certificate_request_attributes.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/host.rb +114 -232
- data/vendored/puppet/lib/puppet/ssl/key.rb +1 -5
- data/vendored/puppet/lib/puppet/ssl/oids.rb +1 -1
- data/vendored/puppet/lib/puppet/test/test_helper.rb +0 -4
- data/vendored/puppet/lib/puppet/transaction/event.rb +3 -7
- data/vendored/puppet/lib/puppet/transaction/persistence.rb +1 -1
- data/vendored/puppet/lib/puppet/type/exec.rb +18 -16
- data/vendored/puppet/lib/puppet/type/file.rb +3 -3
- data/vendored/puppet/lib/puppet/type/file/source.rb +20 -7
- data/vendored/puppet/lib/puppet/type/group.rb +3 -5
- data/vendored/puppet/lib/puppet/type/notify.rb +1 -1
- data/vendored/puppet/lib/puppet/type/package.rb +2 -5
- data/vendored/puppet/lib/puppet/type/schedule.rb +1 -1
- data/vendored/puppet/lib/puppet/type/service.rb +3 -6
- data/vendored/puppet/lib/puppet/type/tidy.rb +1 -1
- data/vendored/puppet/lib/puppet/type/user.rb +13 -20
- data/vendored/puppet/lib/puppet/util.rb +8 -9
- data/vendored/puppet/lib/puppet/util/execution.rb +3 -3
- data/vendored/puppet/lib/puppet/util/feature.rb +61 -39
- data/vendored/puppet/lib/puppet/util/log/destinations.rb +1 -1
- data/vendored/puppet/lib/puppet/util/rdoc.rb +1 -1
- data/vendored/puppet/lib/puppet/util/run_mode.rb +1 -1
- data/vendored/puppet/lib/puppet/util/storage.rb +1 -1
- data/vendored/puppet/lib/puppet/util/suidmanager.rb +7 -5
- data/vendored/puppet/lib/puppet/util/tag_set.rb +1 -1
- data/vendored/puppet/lib/puppet/util/tagging.rb +1 -1
- data/vendored/puppet/lib/puppet/util/windows.rb +18 -2
- data/vendored/puppet/lib/puppet/util/windows/adsi.rb +154 -205
- data/vendored/puppet/lib/puppet/util/windows/service.rb +770 -0
- data/vendored/puppet/lib/puppet/util/yaml.rb +41 -5
- data/vendored/puppet/lib/puppet/version.rb +1 -1
- data/vendored/puppet/lib/puppet_pal.rb +280 -24
- metadata +8 -38
- data/lib/bolt/catalog/compiler.rb +0 -48
- data/lib/bolt/catalog/loaders.rb +0 -19
- data/vendored/puppet/lib/puppet/application/ca.rb +0 -11
- data/vendored/puppet/lib/puppet/application/certificate.rb +0 -17
- data/vendored/puppet/lib/puppet/application/certificate_request.rb +0 -7
- data/vendored/puppet/lib/puppet/application/certificate_revocation_list.rb +0 -7
- data/vendored/puppet/lib/puppet/face/ca.rb +0 -266
- data/vendored/puppet/lib/puppet/face/certificate.rb +0 -167
- data/vendored/puppet/lib/puppet/face/certificate_request.rb +0 -56
- data/vendored/puppet/lib/puppet/face/certificate_revocation_list.rb +0 -56
- data/vendored/puppet/lib/puppet/graph/random_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/graph/title_hash_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/ca.rb +0 -9
- data/vendored/puppet/lib/puppet/indirector/certificate/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/ca.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/file.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/certificate_status.rb +0 -4
- data/vendored/puppet/lib/puppet/indirector/certificate_status/file.rb +0 -91
- data/vendored/puppet/lib/puppet/indirector/certificate_status/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/key/ca.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/key/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/ldap.rb +0 -86
- data/vendored/puppet/lib/puppet/indirector/node/ldap.rb +0 -275
- data/vendored/puppet/lib/puppet/provider/aixobject.rb +0 -392
- data/vendored/puppet/lib/puppet/provider/cron/crontab.rb +0 -297
- data/vendored/puppet/lib/puppet/ssl/certificate_authority.rb +0 -475
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/autosign_command.rb +0 -45
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/interface.rb +0 -324
- data/vendored/puppet/lib/puppet/ssl/certificate_factory.rb +0 -219
- data/vendored/puppet/lib/puppet/ssl/certificate_revocation_list.rb +0 -111
- data/vendored/puppet/lib/puppet/ssl/inventory.rb +0 -55
- data/vendored/puppet/lib/puppet/type/cron.rb +0 -480
@@ -12,7 +12,7 @@ class Puppet::Resource
|
|
12
12
|
|
13
13
|
include Enumerable
|
14
14
|
attr_accessor :file, :line, :catalog, :exported, :virtual, :strict
|
15
|
-
attr_reader :type, :title, :parameters
|
15
|
+
attr_reader :type, :title, :parameters
|
16
16
|
|
17
17
|
# @!attribute [rw] sensitive_parameters
|
18
18
|
# @api private
|
@@ -76,6 +76,13 @@ class Puppet::Resource
|
|
76
76
|
"#{@type}[#{@title}]#{to_hash.inspect}"
|
77
77
|
end
|
78
78
|
|
79
|
+
# Produces a Data compliant hash of the resource.
|
80
|
+
# The result depends on the --rich_data setting, and the context value
|
81
|
+
# for Puppet.lookup(:stringify_rich), that if it is `true` will use the
|
82
|
+
# ToStringifiedConverter to produce the value per parameter.
|
83
|
+
# (Note that the ToStringifiedConverter output is lossy and should not
|
84
|
+
# be used when producing a catalog serialization).
|
85
|
+
#
|
79
86
|
def to_data_hash
|
80
87
|
data = {
|
81
88
|
'type' => type,
|
@@ -89,17 +96,27 @@ class Puppet::Resource
|
|
89
96
|
|
90
97
|
data['exported'] ||= false
|
91
98
|
|
99
|
+
# To get stringified parameter values the flag :stringify_rich can be set
|
100
|
+
# in the puppet context.
|
101
|
+
#
|
102
|
+
stringify = Puppet.lookup(:stringify_rich) { false }
|
103
|
+
converter = stringify ? Puppet::Pops::Serialization::ToStringifiedConverter.new : nil
|
104
|
+
|
92
105
|
params = {}
|
93
106
|
self.to_hash.each_pair do |param, value|
|
94
107
|
# Don't duplicate the title as the namevar
|
95
108
|
unless param == namevar && value == title
|
96
|
-
|
109
|
+
if stringify
|
110
|
+
params[param.to_s] = converter.convert(value)
|
111
|
+
else
|
112
|
+
params[param.to_s] = Puppet::Resource.value_to_json_data(value)
|
113
|
+
end
|
97
114
|
end
|
98
115
|
end
|
99
116
|
|
100
117
|
unless params.empty?
|
101
118
|
data['parameters'] = Puppet::Pops::Serialization::ToDataConverter.convert(params, {
|
102
|
-
:rich_data =>
|
119
|
+
:rich_data => Puppet.lookup(:rich_data),
|
103
120
|
:symbol_as_string => true,
|
104
121
|
:local_reference => false,
|
105
122
|
:type_by_reference => true,
|
@@ -377,8 +377,7 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
|
|
377
377
|
result = @resource_table[title_key]
|
378
378
|
if result.nil?
|
379
379
|
# an instance has to be created in order to construct the unique key used when
|
380
|
-
# searching for aliases, or
|
381
|
-
# which case it is needed by the CapabilityFinder.
|
380
|
+
# searching for aliases, or nothing is found as it is needed by the CapabilityFinder.
|
382
381
|
res = Puppet::Resource.new(type, title, { :environment => @environment_instance })
|
383
382
|
|
384
383
|
# Must check with uniqueness key because of aliases or if resource transforms title in title
|
@@ -582,16 +581,7 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
|
|
582
581
|
private
|
583
582
|
|
584
583
|
def prioritizer
|
585
|
-
@prioritizer
|
586
|
-
when "title-hash"
|
587
|
-
Puppet::Graph::TitleHashPrioritizer.new
|
588
|
-
when "manifest"
|
589
|
-
Puppet::Graph::SequentialPrioritizer.new
|
590
|
-
when "random"
|
591
|
-
Puppet::Graph::RandomPrioritizer.new
|
592
|
-
else
|
593
|
-
raise Puppet::DevError, _("Unknown ordering type %{ordering}") % { ordering: Puppet[:ordering] }
|
594
|
-
end
|
584
|
+
@prioritizer = Puppet::Graph::SequentialPrioritizer.new
|
595
585
|
end
|
596
586
|
|
597
587
|
def create_transaction(options)
|
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'puppet/rest/route'
|
2
|
+
require 'puppet/network/http_pool'
|
3
|
+
require 'puppet/network/http/compression'
|
2
4
|
|
3
5
|
module Puppet::Rest
|
4
6
|
module Routes
|
5
7
|
|
8
|
+
extend Puppet::Network::HTTP::Compression.module
|
9
|
+
|
6
10
|
ACCEPT_ENCODING = 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3'
|
7
11
|
|
8
12
|
def self.ca
|
@@ -12,79 +16,138 @@ module Puppet::Rest
|
|
12
16
|
srv_service: :ca)
|
13
17
|
end
|
14
18
|
|
15
|
-
# Make an HTTP request to fetch the named certificate
|
16
|
-
# HTTP client.
|
17
|
-
# @param [Puppet::Rest::Client] client the HTTP client to use to make the request
|
19
|
+
# Make an HTTP request to fetch the named certificate
|
18
20
|
# @param [String] name the name of the certificate to fetch
|
21
|
+
# @param [Puppet::Rest::SSLContext] ssl_context the ssl content to use when making the request
|
19
22
|
# @raise [Puppet::Rest::ResponseError] if the response status is not OK
|
20
23
|
# @return [String] the PEM-encoded certificate or certificate bundle
|
21
|
-
def self.get_certificate(
|
22
|
-
ca.with_base_url(
|
24
|
+
def self.get_certificate(name, ssl_context)
|
25
|
+
ca.with_base_url(Puppet::Network::Resolver.new) do |url|
|
23
26
|
header = { 'Accept' => 'text/plain', 'Accept-Encoding' => ACCEPT_ENCODING }
|
24
|
-
body = ''
|
25
27
|
url.path += "certificate/#{name}"
|
26
|
-
|
27
|
-
|
28
|
+
|
29
|
+
use_ssl = url.is_a? URI::HTTPS
|
30
|
+
|
31
|
+
# Deeper levels of the code assume that if we have any number of
|
32
|
+
# certificate related files, we have all of the certificate related
|
33
|
+
# files. This assumption caused us to download the certificate twice.
|
34
|
+
# We have to hard code `verify_mode=false` so we don't attempt to
|
35
|
+
# download the certificate so that we can download the certificate.
|
36
|
+
#
|
37
|
+
# This is related to PUP-9094. We won't have so many issues with this
|
38
|
+
# once we are using the httpclient gem to handle this work. We were
|
39
|
+
# unable to get this work completed in time for Puppet 6.0.0, so we had
|
40
|
+
# to switch back to using Puppet::Network::HttpPool, which has
|
41
|
+
# unfortunate limitations (i.e., an all or nothing approach to cert
|
42
|
+
# verification).
|
43
|
+
verify_mode = false
|
44
|
+
|
45
|
+
client = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl, verify_mode)
|
46
|
+
|
47
|
+
response = client.get(url.request_uri, header)
|
48
|
+
unless response.code.to_i == 200
|
49
|
+
raise Puppet::Rest::ResponseError.new(response.message, response)
|
28
50
|
end
|
51
|
+
|
29
52
|
Puppet.info _("Downloaded certificate for %{name} from %{server}") % { name: name, server: ca.server }
|
30
|
-
|
53
|
+
|
54
|
+
uncompress_body(response)
|
31
55
|
end
|
32
56
|
end
|
33
57
|
|
34
|
-
# Make an HTTP request to fetch the named crl
|
35
|
-
# HTTP client. Accepts a block to stream responses to disk.
|
36
|
-
# @param [Puppet::Rest::Client] client the HTTP client to use to make the request
|
58
|
+
# Make an HTTP request to fetch the named crl
|
37
59
|
# @param [String] name the crl to fetch
|
60
|
+
# @param [Puppet::Rest::SSLContext] ssl_context the ssl content to use when making the request
|
38
61
|
# @raise [Puppet::Rest::ResponseError] if the response status is not OK
|
39
|
-
# @return
|
40
|
-
def self.get_crls(
|
41
|
-
ca.with_base_url(
|
62
|
+
# @return [String] the PEM-encoded crl
|
63
|
+
def self.get_crls(name, ssl_context)
|
64
|
+
ca.with_base_url(Puppet::Network::Resolver.new) do |url|
|
42
65
|
header = { 'Accept' => 'text/plain', 'Accept-Encoding' => ACCEPT_ENCODING }
|
43
66
|
url.path += "certificate_revocation_list/#{name}"
|
44
|
-
|
45
|
-
|
67
|
+
|
68
|
+
use_ssl = url.is_a? URI::HTTPS
|
69
|
+
|
70
|
+
# Deeper levels of the code assume that if we have any number of
|
71
|
+
# certificate related files, we have all of the certificate related
|
72
|
+
# files. Unfortunately, this causes us to get stuck in an infinite loop,
|
73
|
+
# so we have to hard code `verify_mode=false` so we don't attempt to use
|
74
|
+
# files that do not exist yet in order to download those files.
|
75
|
+
#
|
76
|
+
# This is related to PUP-9094. We won't have so many issues with this
|
77
|
+
# once we are using the httpclient gem to handle this work. We were
|
78
|
+
# unable to get this work completed in time for Puppet 6.0.0, so we had
|
79
|
+
# to switch back to using Puppet::Network::HttpPool, which has
|
80
|
+
# unfortunate limitations (i.e., an all or nothing approach to cert
|
81
|
+
# verification).
|
82
|
+
verify_mode = false
|
83
|
+
|
84
|
+
client = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl, verify_mode)
|
85
|
+
|
86
|
+
response = client.get(url.request_uri, header)
|
87
|
+
unless response.code.to_i == 200
|
88
|
+
raise Puppet::Rest::ResponseError.new(response.message, response)
|
46
89
|
end
|
90
|
+
|
47
91
|
Puppet.debug _("Downloaded certificate revocation list for %{name} from %{server}") % { name: name, server: ca.server }
|
92
|
+
|
93
|
+
uncompress_body(response)
|
48
94
|
end
|
49
95
|
end
|
50
96
|
|
51
|
-
# Make an HTTP request to send the named CSR
|
52
|
-
# HTTP client.
|
53
|
-
# @param [Puppet::Rest::Client] client the HTTP client to use to make the request
|
97
|
+
# Make an HTTP request to send the named CSR
|
54
98
|
# @param [String] csr_pem the contents of the CSR to sent to the CA
|
55
99
|
# @param [String] name the name of the host whose CSR is being submitted
|
100
|
+
# @param [Puppet::Rest::SSLContext] ssl_context the ssl content to use when making the request
|
56
101
|
# @rasies [Puppet::Rest::ResponseError] if the response status is not OK
|
57
|
-
def self.put_certificate_request(
|
58
|
-
ca.with_base_url(
|
102
|
+
def self.put_certificate_request(csr_pem, name, ssl_context)
|
103
|
+
ca.with_base_url(Puppet::Network::Resolver.new) do |url|
|
59
104
|
header = { 'Accept' => 'text/plain',
|
60
105
|
'Accept-Encoding' => ACCEPT_ENCODING,
|
61
106
|
'Content-Type' => 'text/plain' }
|
62
107
|
url.path += "certificate_request/#{name}"
|
63
|
-
|
64
|
-
|
108
|
+
|
109
|
+
use_ssl = url.is_a? URI::HTTPS
|
110
|
+
|
111
|
+
# See notes above as to why verify_mode is hardcoded to false
|
112
|
+
verify_mode = false
|
113
|
+
|
114
|
+
client = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl, verify_mode)
|
115
|
+
|
116
|
+
response = client.put(url.request_uri, csr_pem, header)
|
117
|
+
if response.code.to_i == 200
|
65
118
|
Puppet.debug "Submitted certificate request to server."
|
66
119
|
else
|
67
|
-
raise response.
|
120
|
+
raise Puppet::Rest::ResponseError.new(response.message, response)
|
68
121
|
end
|
69
122
|
end
|
70
123
|
end
|
71
124
|
|
72
|
-
# Make an HTTP request to get the named CSR
|
73
|
-
# HTTP client.
|
74
|
-
# @param [Puppet::Rest::Client] client the HTTP client to use to make the request
|
125
|
+
# Make an HTTP request to get the named CSR
|
75
126
|
# @param [String] name the name of the host whose CSR is being queried
|
127
|
+
# @param [Puppet::Rest::SSLContext] ssl_context the ssl content to use when making the request
|
76
128
|
# @rasies [Puppet::Rest::ResponseError] if the response status is not OK
|
77
129
|
# @return [String] the PEM encoded certificate request
|
78
|
-
def self.get_certificate_request(
|
79
|
-
ca.with_base_url(
|
130
|
+
def self.get_certificate_request(name, ssl_context)
|
131
|
+
ca.with_base_url(Puppet::Network::Resolver.new) do |url|
|
80
132
|
header = { 'Accept' => 'text/plain', 'Accept-Encoding' => ACCEPT_ENCODING }
|
81
|
-
body = ''
|
82
133
|
url.path += "certificate_request/#{name}"
|
83
|
-
|
84
|
-
|
134
|
+
|
135
|
+
use_ssl = url.is_a? URI::HTTPS
|
136
|
+
|
137
|
+
# See notes above as to why verify_mode is hardcoded to false
|
138
|
+
verify_mode = false
|
139
|
+
|
140
|
+
client = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl, verify_mode)
|
141
|
+
|
142
|
+
|
143
|
+
response = client.get(url.request_uri, header)
|
144
|
+
unless response.code.to_i == 200
|
145
|
+
raise Puppet::Rest::ResponseError.new(response.message, response)
|
85
146
|
end
|
147
|
+
|
86
148
|
Puppet.debug _("Downloaded existing certificate request for %{name} from %{server}") % { name: name, server: ca.server }
|
87
|
-
|
149
|
+
|
150
|
+
uncompress_body(response)
|
88
151
|
end
|
89
152
|
end
|
90
153
|
end
|
@@ -1197,7 +1197,7 @@ Generated on #{Time.now}.
|
|
1197
1197
|
|
1198
1198
|
def add_user_resources(catalog, sections)
|
1199
1199
|
return unless Puppet.features.root?
|
1200
|
-
return if Puppet.
|
1200
|
+
return if Puppet::Util::Platform.windows?
|
1201
1201
|
return unless self[:mkusers]
|
1202
1202
|
|
1203
1203
|
@config.each do |name, setting|
|
@@ -156,7 +156,7 @@ class Puppet::Settings::FileSetting < Puppet::Settings::StringSetting
|
|
156
156
|
end
|
157
157
|
|
158
158
|
# REMIND fails on Windows because chown/chgrp functionality not supported yet
|
159
|
-
if Puppet.features.root? and !Puppet.
|
159
|
+
if Puppet.features.root? and !Puppet::Util::Platform.windows?
|
160
160
|
resource[:owner] = self.owner if self.owner
|
161
161
|
resource[:group] = self.group if self.group
|
162
162
|
end
|
@@ -34,11 +34,6 @@ class Puppet::SSL::Base
|
|
34
34
|
|
35
35
|
attr_accessor :name, :content
|
36
36
|
|
37
|
-
# Is this file for the CA?
|
38
|
-
def ca?
|
39
|
-
name == Puppet::SSL::Host.ca_name
|
40
|
-
end
|
41
|
-
|
42
37
|
def generate
|
43
38
|
raise Puppet::DevError, _("%{class_name} did not override 'generate'") % { class_name: self.class }
|
44
39
|
end
|
@@ -86,18 +81,15 @@ class Puppet::SSL::Base
|
|
86
81
|
|
87
82
|
# Read content from disk appropriately.
|
88
83
|
def read(path)
|
89
|
-
# applies to Puppet::SSL::Certificate, Puppet::SSL::CertificateRequest
|
84
|
+
# applies to Puppet::SSL::Certificate, Puppet::SSL::CertificateRequest
|
90
85
|
# Puppet::SSL::Key uses this, but also provides its own override
|
91
86
|
# nothing derives from Puppet::SSL::Certificate, but it is called by a number of other SSL Indirectors:
|
92
|
-
# Puppet::SSL::Certificate::DisabledCa (:find, :save, :destroy)
|
93
87
|
# Puppet::Indirector::CertificateStatus::File (.indirection.find)
|
94
88
|
# Puppet::Network::HTTP::WEBrick (.indirection.find)
|
95
89
|
# Puppet::Network::HTTP::RackREST (.from_instance)
|
96
90
|
# Puppet::Network::HTTP::WEBrickREST (.from_instance)
|
97
|
-
# Puppet::SSL::CertificateAuthority (.new, .indirection.find, .indirection.save)
|
98
91
|
# Puppet::SSL::Host (.indirection.find)
|
99
92
|
# Puppet::SSL::Inventory (.indirection.search, implements its own add / rebuild / serials with encoding UTF8)
|
100
|
-
# Puppet::SSL::CertificateAuthority::Interface (.indirection.find)
|
101
93
|
# Puppet::SSL::Validator::DefaultValidator (.from_instance) / Puppet::SSL::Validator::NoValidator does nothing
|
102
94
|
@content = wrapped_class.new(Puppet::FileSystem.read(path, :encoding => Encoding::ASCII))
|
103
95
|
end
|
@@ -30,19 +30,7 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
|
|
30
30
|
|
31
31
|
extend Puppet::Indirector
|
32
32
|
|
33
|
-
|
34
|
-
module AutoSigner
|
35
|
-
def save(instance, key = nil)
|
36
|
-
super
|
37
|
-
|
38
|
-
# Try to autosign the CSR.
|
39
|
-
if ca = Puppet::SSL::CertificateAuthority.instance
|
40
|
-
ca.autosign(instance)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
indirects :certificate_request, :terminus_class => :file, :extend => AutoSigner, :doc => <<DOC
|
33
|
+
indirects :certificate_request, :terminus_class => :file, :doc => <<DOC
|
46
34
|
This indirection wraps an `OpenSSL::X509::Request` object, representing a certificate signing request (CSR).
|
47
35
|
The indirection key is the certificate CN (generally a hostname).
|
48
36
|
DOC
|
@@ -21,7 +21,7 @@ class Puppet::SSL::CertificateRequestAttributes
|
|
21
21
|
def load
|
22
22
|
Puppet.info(_("csr_attributes file loading from %{path}") % { path: path })
|
23
23
|
if Puppet::FileSystem.exist?(path)
|
24
|
-
hash = Puppet::Util::Yaml.
|
24
|
+
hash = Puppet::Util::Yaml.safe_load_file(path, [Symbol]) || {}
|
25
25
|
if ! hash.is_a?(Hash)
|
26
26
|
raise Puppet::Error, _("invalid CSR attributes, expected instance of Hash, received instance of %{klass}") % { klass: hash.class }
|
27
27
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
-
require 'puppet/indirector'
|
2
1
|
require 'puppet/ssl'
|
3
2
|
require 'puppet/ssl/key'
|
4
3
|
require 'puppet/ssl/certificate'
|
5
4
|
require 'puppet/ssl/certificate_request'
|
6
|
-
require 'puppet/ssl/certificate_revocation_list'
|
7
5
|
require 'puppet/ssl/certificate_request_attributes'
|
8
6
|
require 'puppet/rest/errors'
|
9
7
|
require 'puppet/rest/routes'
|
@@ -24,22 +22,11 @@ class Puppet::SSL::Host
|
|
24
22
|
CA_NAME = Puppet::SSL::CA_NAME
|
25
23
|
Certificate = Puppet::SSL::Certificate
|
26
24
|
CertificateRequest = Puppet::SSL::CertificateRequest
|
27
|
-
CertificateRevocationList = Puppet::SSL::CertificateRevocationList
|
28
|
-
|
29
|
-
extend Puppet::Indirector
|
30
|
-
indirects :certificate_status, :terminus_class => :file, :doc => <<DOC
|
31
|
-
This indirection represents the host that ties a key, certificate, and certificate request together.
|
32
|
-
The indirection key is the certificate CN (generally a hostname).
|
33
|
-
DOC
|
34
25
|
|
35
26
|
attr_reader :name, :crl_path
|
36
|
-
attr_accessor :ca
|
37
27
|
|
38
28
|
attr_writer :key, :certificate, :certificate_request, :crl_usage
|
39
29
|
|
40
|
-
# This accessor is used in instances for indirector requests to hold desired state
|
41
|
-
attr_accessor :desired_state
|
42
|
-
|
43
30
|
def self.localhost
|
44
31
|
return @localhost if @localhost
|
45
32
|
@localhost = new
|
@@ -52,28 +39,10 @@ DOC
|
|
52
39
|
@localhost = nil
|
53
40
|
end
|
54
41
|
|
55
|
-
# This is the constant that people will use to mark that a given host is
|
56
|
-
# a certificate authority.
|
57
|
-
def self.ca_name
|
58
|
-
CA_NAME
|
59
|
-
end
|
60
|
-
|
61
|
-
class << self
|
62
|
-
attr_reader :ca_location
|
63
|
-
end
|
64
|
-
|
65
42
|
# Configure how our various classes interact with their various terminuses.
|
66
43
|
def self.configure_indirection(terminus, cache = nil)
|
67
44
|
Certificate.indirection.terminus_class = terminus
|
68
45
|
CertificateRequest.indirection.terminus_class = terminus
|
69
|
-
CertificateRevocationList.indirection.terminus_class = terminus
|
70
|
-
|
71
|
-
host_map = {:ca => :file, :disabled_ca => nil, :file => nil, :rest => :rest}
|
72
|
-
if term = host_map[terminus]
|
73
|
-
self.indirection.terminus_class = term
|
74
|
-
else
|
75
|
-
self.indirection.reset_terminus_class
|
76
|
-
end
|
77
46
|
|
78
47
|
if cache
|
79
48
|
# This is weird; we don't actually cache our keys, we
|
@@ -87,7 +56,6 @@ DOC
|
|
87
56
|
if cache
|
88
57
|
Certificate.indirection.cache_class = cache
|
89
58
|
CertificateRequest.indirection.cache_class = cache
|
90
|
-
CertificateRevocationList.indirection.cache_class = cache
|
91
59
|
else
|
92
60
|
# Make sure we have no cache configured. puppet master
|
93
61
|
# switches the configurations around a bit, so it's important
|
@@ -95,39 +63,9 @@ DOC
|
|
95
63
|
# time.
|
96
64
|
Certificate.indirection.cache_class = nil
|
97
65
|
CertificateRequest.indirection.cache_class = nil
|
98
|
-
CertificateRevocationList.indirection.cache_class = nil
|
99
66
|
end
|
100
67
|
end
|
101
68
|
|
102
|
-
CA_MODES = {
|
103
|
-
# Our ca is local, so we use it as the ultimate source of information
|
104
|
-
# And we cache files locally.
|
105
|
-
:local => [:ca, :file],
|
106
|
-
# We're a remote CA client.
|
107
|
-
:remote => [:rest, :file],
|
108
|
-
# We are the CA, so we don't have read/write access to the normal certificates.
|
109
|
-
:only => [:ca],
|
110
|
-
# We have no CA, so we just look in the local file store.
|
111
|
-
:none => [:disabled_ca]
|
112
|
-
}
|
113
|
-
|
114
|
-
# Specify how we expect to interact with our certificate authority.
|
115
|
-
def self.ca_location=(mode)
|
116
|
-
modes = CA_MODES.collect { |m, vals| m.to_s }.join(", ")
|
117
|
-
raise ArgumentError, _("CA Mode can only be one of: %{modes}") % { modes: modes } unless CA_MODES.include?(mode)
|
118
|
-
|
119
|
-
@ca_location = mode
|
120
|
-
|
121
|
-
configure_indirection(*CA_MODES[@ca_location])
|
122
|
-
end
|
123
|
-
|
124
|
-
# Puppet::SSL::Host is actually indirected now so the original implementation
|
125
|
-
# has been moved into the certificate_status indirector. This method is in-use
|
126
|
-
# in `puppet cert -c <certname>`.
|
127
|
-
def self.destroy(name)
|
128
|
-
indirection.destroy(name)
|
129
|
-
end
|
130
|
-
|
131
69
|
def self.from_data_hash(data)
|
132
70
|
instance = new(data["name"])
|
133
71
|
if data["desired_state"]
|
@@ -136,18 +74,6 @@ DOC
|
|
136
74
|
instance
|
137
75
|
end
|
138
76
|
|
139
|
-
# Puppet::SSL::Host is actually indirected now so the original implementation
|
140
|
-
# has been moved into the certificate_status indirector. This method does not
|
141
|
-
# appear to be in use in `puppet cert -l`.
|
142
|
-
def self.search(options = {})
|
143
|
-
indirection.search("*", options)
|
144
|
-
end
|
145
|
-
|
146
|
-
# Is this a ca host, meaning that all of its files go in the CA location?
|
147
|
-
def ca?
|
148
|
-
ca
|
149
|
-
end
|
150
|
-
|
151
77
|
def key
|
152
78
|
@key ||= Key.indirection.find(name)
|
153
79
|
end
|
@@ -175,8 +101,6 @@ DOC
|
|
175
101
|
# ...add our configured dns_alt_names
|
176
102
|
if Puppet[:dns_alt_names] and Puppet[:dns_alt_names] != ''
|
177
103
|
options[:dns_alt_names] ||= Puppet[:dns_alt_names]
|
178
|
-
elsif Puppet::SSL::CertificateAuthority.ca? and fqdn = Facter.value(:fqdn) and domain = Facter.value(:domain)
|
179
|
-
options[:dns_alt_names] = "puppet, #{fqdn}, puppet.#{domain}"
|
180
104
|
end
|
181
105
|
end
|
182
106
|
|
@@ -190,6 +114,7 @@ DOC
|
|
190
114
|
@certificate_request.generate(key.content, options)
|
191
115
|
begin
|
192
116
|
submit_certificate_request(@certificate_request)
|
117
|
+
save_certificate_request(@certificate_request)
|
193
118
|
rescue
|
194
119
|
@certificate_request = nil
|
195
120
|
raise
|
@@ -208,23 +133,28 @@ DOC
|
|
208
133
|
|
209
134
|
# get the CA cert first, since it's required for the normal cert
|
210
135
|
# to be of any use. If we can't get it, quit.
|
211
|
-
if !
|
136
|
+
if !ensure_ca_certificate
|
212
137
|
return nil
|
213
138
|
end
|
214
139
|
|
215
|
-
|
216
|
-
return nil unless
|
140
|
+
cert = get_host_certificate
|
141
|
+
return nil unless cert
|
217
142
|
|
218
|
-
validate_certificate_with_key
|
143
|
+
validate_certificate_with_key(cert)
|
144
|
+
@certificate = cert
|
219
145
|
end
|
220
146
|
@certificate
|
221
147
|
end
|
222
148
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
149
|
+
# Validate that our private key matches the specified certificate.
|
150
|
+
#
|
151
|
+
# @param [Puppet::SSL::Certificate] cert the certificate to check
|
152
|
+
# @raises [Puppet::Error] if the private key does not match
|
153
|
+
def validate_certificate_with_key(cert)
|
154
|
+
raise Puppet::Error, _("No certificate to validate.") unless cert
|
155
|
+
raise Puppet::Error, _("No private key with which to validate certificate with fingerprint: %{fingerprint}") % { fingerprint: cert.fingerprint } unless key
|
156
|
+
unless cert.content.check_private_key(key.content)
|
157
|
+
raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: cert.fingerprint, cert_name: Puppet[:certname], ssl_dir: Puppet[:ssldir], cert_dir: Puppet[:certdir].gsub('/', '\\') }
|
228
158
|
The certificate retrieved from the master does not match the agent's private key. Did you forget to run as root?
|
229
159
|
Certificate fingerprint: %{fingerprint}
|
230
160
|
To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certificate.
|
@@ -238,6 +168,15 @@ ERROR_STRING
|
|
238
168
|
end
|
239
169
|
end
|
240
170
|
|
171
|
+
def download_host_certificate
|
172
|
+
cert = download_certificate_from_ca(name)
|
173
|
+
return nil unless cert
|
174
|
+
|
175
|
+
validate_certificate_with_key(cert)
|
176
|
+
save_host_certificate(cert)
|
177
|
+
cert
|
178
|
+
end
|
179
|
+
|
241
180
|
# Search for an existing CSR for this host either cached on
|
242
181
|
# disk or stored by the CA. Returns nil if no request exists.
|
243
182
|
# @return [Puppet::SSL::CertificateRequest, nil]
|
@@ -245,10 +184,8 @@ ERROR_STRING
|
|
245
184
|
unless @certificate_request
|
246
185
|
if csr = load_certificate_request_from_file
|
247
186
|
@certificate_request = csr
|
248
|
-
elsif
|
249
|
-
|
250
|
-
@certificate_request = csr
|
251
|
-
end
|
187
|
+
elsif csr = download_csr_from_ca
|
188
|
+
@certificate_request = csr
|
252
189
|
end
|
253
190
|
end
|
254
191
|
@certificate_request
|
@@ -262,10 +199,62 @@ ERROR_STRING
|
|
262
199
|
|
263
200
|
# if CSR downloaded from master, but the local keypair was just generated and
|
264
201
|
# does not match the public key in the CSR, fail hard
|
265
|
-
if
|
266
|
-
|
202
|
+
validate_csr_with_key(existing_request, key) if existing_request
|
203
|
+
|
204
|
+
generate_certificate_request unless existing_request
|
205
|
+
end
|
267
206
|
|
268
|
-
|
207
|
+
# Generate a keypair, generate a CSR, and submit it. If a local key pair
|
208
|
+
# already exists it will be used to generate the CSR. If a local CSR already
|
209
|
+
# exists and matches the key then the existing CSR will be submitted. If the
|
210
|
+
# CSR and key do not match an exception will be raised.
|
211
|
+
#
|
212
|
+
# @return [Puppet::SSL::CertificateRequest, nil]
|
213
|
+
def submit_request
|
214
|
+
generate_key unless key
|
215
|
+
|
216
|
+
csr = load_certificate_request_from_file
|
217
|
+
if csr
|
218
|
+
if key.content.public_key.to_s != csr.content.public_key.to_s
|
219
|
+
Puppet.warning("The local CSR does not match the agent's public key. Generating a new CSR.")
|
220
|
+
|
221
|
+
request_path = certificate_request_location(name)
|
222
|
+
Puppet::FileSystem.unlink(request_path)
|
223
|
+
csr = nil
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
if csr
|
228
|
+
validate_csr_with_key(csr, key)
|
229
|
+
submit_certificate_request(csr)
|
230
|
+
@certificate_request = csr
|
231
|
+
else
|
232
|
+
generate_certificate_request
|
233
|
+
end
|
234
|
+
|
235
|
+
@certificate_request
|
236
|
+
end
|
237
|
+
|
238
|
+
def validate_local_csr_with_key(csr, key)
|
239
|
+
if key.content.public_key.to_s != csr.content.public_key.to_s
|
240
|
+
raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text, cert_name: Puppet[:certname], ssl_dir: Puppet[:ssldir], cert_dir: Puppet[:certdir].gsub('/', '\\') }
|
241
|
+
The local CSR does not match the agent's public key.
|
242
|
+
CSR fingerprint: %{fingerprint}
|
243
|
+
CSR public key: %{csr_public_key}
|
244
|
+
Agent public key: %{agent_public_key}
|
245
|
+
To fix this, remove the CSR from the agent and then start a puppet run, which will automatically regenerate a CSR.
|
246
|
+
On the agent:
|
247
|
+
1a. On most platforms: find %{ssl_dir} -name %{cert_name}.pem -delete
|
248
|
+
1b. On Windows: del "%{cert_dir}\\%{cert_name}.pem" /f
|
249
|
+
2. puppet agent -t
|
250
|
+
ERROR_STRING
|
251
|
+
end
|
252
|
+
end
|
253
|
+
private :validate_local_csr_with_key
|
254
|
+
|
255
|
+
def validate_csr_with_key(csr, key)
|
256
|
+
if key.content.public_key.to_s != csr.content.public_key.to_s
|
257
|
+
raise Puppet::Error, _(<<ERROR_STRING) % { fingerprint: csr.fingerprint, csr_public_key: csr.content.public_key.to_text, agent_public_key: key.content.public_key.to_text, cert_name: Puppet[:certname], ssl_dir: Puppet[:ssldir], cert_dir: Puppet[:certdir].gsub('/', '\\') }
|
269
258
|
The CSR retrieved from the master does not match the agent's public key.
|
270
259
|
CSR fingerprint: %{fingerprint}
|
271
260
|
CSR public key: %{csr_public_key}
|
@@ -279,21 +268,13 @@ On the agent:
|
|
279
268
|
2. puppet agent -t
|
280
269
|
ERROR_STRING
|
281
270
|
end
|
282
|
-
generate_certificate_request unless existing_request
|
283
|
-
|
284
|
-
# If we can get a CA instance, then we're a valid CA, and we
|
285
|
-
# should use it to sign our request; else, just try to read
|
286
|
-
# the cert.
|
287
|
-
if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
|
288
|
-
ca.sign(self.name, {allow_dns_alt_names: true})
|
289
|
-
end
|
290
271
|
end
|
272
|
+
private :validate_csr_with_key
|
291
273
|
|
292
274
|
def initialize(name = nil)
|
293
275
|
@name = (name || Puppet[:certname]).downcase
|
294
276
|
Puppet::SSL::Base.validate_certname(@name)
|
295
277
|
@key = @certificate = @certificate_request = nil
|
296
|
-
@ca = (name == self.class.ca_name)
|
297
278
|
@crl_usage = Puppet.settings[:certificate_revocation]
|
298
279
|
@crl_path = Puppet.settings[:hostcrl]
|
299
280
|
end
|
@@ -320,49 +301,6 @@ ERROR_STRING
|
|
320
301
|
@ssl_store
|
321
302
|
end
|
322
303
|
|
323
|
-
def to_data_hash
|
324
|
-
my_cert = Puppet::SSL::Certificate.indirection.find(name)
|
325
|
-
result = { 'name' => name }
|
326
|
-
|
327
|
-
my_state = state
|
328
|
-
|
329
|
-
result['state'] = my_state
|
330
|
-
result['desired_state'] = desired_state if desired_state
|
331
|
-
|
332
|
-
thing_to_use = (my_state == 'requested') ? certificate_request : my_cert
|
333
|
-
|
334
|
-
# this is for backwards-compatibility
|
335
|
-
# we should deprecate it and transition people to using
|
336
|
-
# json[:fingerprints][:default]
|
337
|
-
# It appears that we have no internal consumers of this api
|
338
|
-
# --jeffweiss 30 aug 2012
|
339
|
-
result['fingerprint'] = thing_to_use.fingerprint
|
340
|
-
|
341
|
-
# The above fingerprint doesn't tell us what message digest algorithm was used
|
342
|
-
# No problem, except that the default is changing between 2.7 and 3.0. Also, as
|
343
|
-
# we move to FIPS 140-2 compliance, MD5 is no longer allowed (and, gasp, will
|
344
|
-
# segfault in rubies older than 1.9.3)
|
345
|
-
# So, when we add the newer fingerprints, we're explicit about the hashing
|
346
|
-
# algorithm used.
|
347
|
-
# --jeffweiss 31 july 2012
|
348
|
-
result['fingerprints'] = {}
|
349
|
-
result['fingerprints']['default'] = thing_to_use.fingerprint
|
350
|
-
|
351
|
-
suitable_message_digest_algorithms.each do |md|
|
352
|
-
result['fingerprints'][md.to_s] = thing_to_use.fingerprint md
|
353
|
-
end
|
354
|
-
result['dns_alt_names'] = thing_to_use.subject_alt_names
|
355
|
-
|
356
|
-
result
|
357
|
-
end
|
358
|
-
|
359
|
-
# eventually we'll probably want to move this somewhere else or make it
|
360
|
-
# configurable
|
361
|
-
# --jeffweiss 29 aug 2012
|
362
|
-
def suitable_message_digest_algorithms
|
363
|
-
[:SHA1, :SHA224, :SHA256, :SHA384, :SHA512]
|
364
|
-
end
|
365
|
-
|
366
304
|
# Attempt to retrieve a cert, if we don't already have one.
|
367
305
|
def wait_for_cert(time)
|
368
306
|
begin
|
@@ -396,28 +334,21 @@ ERROR_STRING
|
|
396
334
|
end
|
397
335
|
end
|
398
336
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
return 'signed'
|
407
|
-
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError
|
408
|
-
return 'revoked'
|
337
|
+
# Saves the given certificate to disc, at a location determined by this
|
338
|
+
# host's configuration.
|
339
|
+
# @param [Puppet::SSL::Certificate] cert the cert to save
|
340
|
+
def save_host_certificate(cert)
|
341
|
+
file_path = certificate_location(name)
|
342
|
+
Puppet::Util.replace_file(file_path, 0644) do |f|
|
343
|
+
f.write(cert.to_s)
|
409
344
|
end
|
410
345
|
end
|
411
346
|
|
412
347
|
private
|
413
348
|
|
414
|
-
# Load a previously generated CSR
|
349
|
+
# Load a previously generated CSR from disk
|
415
350
|
# @return [Puppet::SSL::CertificateRequest, nil]
|
416
351
|
def load_certificate_request_from_file
|
417
|
-
if Puppet::SSL::CertificateRequest.indirection.terminus_class == :memory
|
418
|
-
return Puppet::SSL::CertificateRequest.indirection.find(cert_name)
|
419
|
-
end
|
420
|
-
|
421
352
|
request_path = certificate_request_location(name)
|
422
353
|
if Puppet::FileSystem.exist?(request_path)
|
423
354
|
Puppet::SSL::CertificateRequest.from_s(Puppet::FileSystem.read(request_path))
|
@@ -432,38 +363,28 @@ ERROR_STRING
|
|
432
363
|
def download_csr_from_ca
|
433
364
|
begin
|
434
365
|
body = Puppet::Rest::Routes.get_certificate_request(
|
435
|
-
|
436
|
-
name)
|
366
|
+
name, Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, ssl_store))
|
437
367
|
begin
|
438
368
|
Puppet::SSL::CertificateRequest.from_s(body)
|
439
369
|
rescue OpenSSL::X509::RequestError => e
|
440
370
|
raise Puppet::Error, _("Response from the CA did not contain a valid certificate request: %{message}") % { message: e.message }
|
441
371
|
end
|
442
372
|
rescue Puppet::Rest::ResponseError => e
|
443
|
-
if e.response.
|
373
|
+
if e.response.code.to_i == 404
|
444
374
|
nil
|
445
375
|
else
|
446
376
|
raise Puppet::Error, _('Could not download certificate request: %{message}') % { message: e.message }
|
447
377
|
end
|
448
378
|
end
|
449
379
|
end
|
450
|
-
# Submit the CSR to the CA
|
451
|
-
# via the indirector (needed for both memory and CA terminii). This also
|
452
|
-
# caches a copy of the CSR on disk.
|
380
|
+
# Submit the CSR to the CA via an HTTP PUT request.
|
453
381
|
# @param [Puppet::SSL::CertificateRequest] csr the request to submit
|
454
382
|
def submit_certificate_request(csr)
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
return
|
459
|
-
end
|
460
|
-
|
461
|
-
if Puppet::SSL::Host.ca_location == :remote
|
462
|
-
Puppet::Rest::Routes.put_certificate_request(
|
463
|
-
http_client(Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, ssl_store)),
|
464
|
-
csr.render, name)
|
465
|
-
end
|
383
|
+
Puppet::Rest::Routes.put_certificate_request(
|
384
|
+
csr.render, name, Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, ssl_store))
|
385
|
+
end
|
466
386
|
|
387
|
+
def save_certificate_request(csr)
|
467
388
|
Puppet::Util.replace_file(certificate_request_location(name), 0644) do |file|
|
468
389
|
file.write(csr.render)
|
469
390
|
end
|
@@ -495,16 +416,13 @@ ERROR_STRING
|
|
495
416
|
|
496
417
|
# Ensures that the CA certificate is available for either generating or
|
497
418
|
# validating the host's cert.
|
498
|
-
# It will first check
|
499
|
-
# then check on disk, and finally try to download it.
|
419
|
+
# It will first check on disk, then try to download it.
|
500
420
|
# @raise [Puppet::Error] if text form of found certificate bundle is invalid
|
501
421
|
# and cannot be loaded into cert objects
|
502
422
|
# @return [Boolean] true if the CA certificate was found, false otherwise
|
503
423
|
def ensure_ca_certificate
|
504
424
|
file_path = certificate_location(CA_NAME)
|
505
|
-
if
|
506
|
-
true
|
507
|
-
elsif Puppet::FileSystem.exist?(file_path)
|
425
|
+
if Puppet::FileSystem.exist?(file_path)
|
508
426
|
begin
|
509
427
|
# This load ensures that the file contents is a valid cert bundle.
|
510
428
|
# If the text is malformed, load_certificate_bundle will raise.
|
@@ -522,6 +440,7 @@ ERROR_STRING
|
|
522
440
|
end
|
523
441
|
end
|
524
442
|
end
|
443
|
+
public :ensure_ca_certificate
|
525
444
|
|
526
445
|
# Creates an arry of SSL Certificate objects from a PEM-encoding string
|
527
446
|
# of one or more certs.
|
@@ -556,13 +475,11 @@ ERROR_STRING
|
|
556
475
|
# @return nil
|
557
476
|
def download_and_save_crl_bundle(store=nil)
|
558
477
|
begin
|
559
|
-
# If no SSL store was
|
478
|
+
# If no SSL store was supplied, use this host's SSL store
|
560
479
|
store ||= ssl_store
|
561
|
-
client = http_client(Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, store))
|
562
480
|
Puppet::Util.replace_file(crl_path, 0644) do |file|
|
563
|
-
Puppet::Rest::Routes.get_crls(
|
564
|
-
|
565
|
-
end
|
481
|
+
result = Puppet::Rest::Routes.get_crls(CA_NAME, Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, store))
|
482
|
+
file.write(result)
|
566
483
|
end
|
567
484
|
rescue Puppet::Rest::ResponseError => e
|
568
485
|
raise Puppet::Error, _('Could not download CRLs: %{message}') % { message: e.message }
|
@@ -574,12 +491,11 @@ ERROR_STRING
|
|
574
491
|
# bundle
|
575
492
|
# @return [[OpenSSL::X509::Certificate]] the certs loaded from the response
|
576
493
|
def download_ca_certificate_bundle
|
577
|
-
return nil if Puppet::SSL::Host.ca_location != :remote
|
578
|
-
|
579
494
|
begin
|
580
495
|
cert_bundle = Puppet::Rest::Routes.get_certificate(
|
581
|
-
|
582
|
-
|
496
|
+
CA_NAME,
|
497
|
+
Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_NONE)
|
498
|
+
)
|
583
499
|
# This load ensures that the response body is a valid cert bundle.
|
584
500
|
# If the text is malformed, load_certificate_bundle will raise.
|
585
501
|
begin
|
@@ -606,9 +522,7 @@ ERROR_STRING
|
|
606
522
|
# no certificate could be found.
|
607
523
|
# @return [Puppet::SSL::Certificate, nil]
|
608
524
|
def get_host_certificate
|
609
|
-
if cert =
|
610
|
-
return cert
|
611
|
-
elsif cert = check_for_certificate_on_disk(name)
|
525
|
+
if cert = check_for_certificate_on_disk(name)
|
612
526
|
return cert
|
613
527
|
elsif cert = download_certificate_from_ca(name)
|
614
528
|
save_host_certificate(cert)
|
@@ -618,17 +532,6 @@ ERROR_STRING
|
|
618
532
|
end
|
619
533
|
end
|
620
534
|
|
621
|
-
# Checks the certificate indirection for a cert stored in memory.
|
622
|
-
# Only relevant if the memory terminus is in use, and currently
|
623
|
-
# only used in testing.
|
624
|
-
# @param [String] name the name of the cert to look for
|
625
|
-
# @return [Puppet::SSL::Certificate, nil]
|
626
|
-
def check_for_certificate_in_memory(cert_name)
|
627
|
-
if Puppet::SSL::Certificate.indirection.terminus_class == :memory
|
628
|
-
return Puppet::SSL::Certificate.indirection.find(cert_name)
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
535
|
# Checks for the requested certificate on disc, at a location
|
633
536
|
# determined by this host's configuration.
|
634
537
|
# @name [String] name the name of the cert to look for
|
@@ -645,6 +548,7 @@ ERROR_STRING
|
|
645
548
|
end
|
646
549
|
end
|
647
550
|
end
|
551
|
+
public :check_for_certificate_on_disk
|
648
552
|
|
649
553
|
# Attempts to download this host's certificate from the CA server.
|
650
554
|
# Returns nil if the CA does not yet have a signed cert for this host.
|
@@ -653,19 +557,18 @@ ERROR_STRING
|
|
653
557
|
# certificate
|
654
558
|
# @return [Puppet::SSL::Certificate, nil]
|
655
559
|
def download_certificate_from_ca(cert_name)
|
656
|
-
return nil if Puppet::SSL::Host.ca_location != :remote
|
657
|
-
|
658
560
|
begin
|
659
561
|
cert = Puppet::Rest::Routes.get_certificate(
|
660
|
-
|
661
|
-
|
562
|
+
cert_name,
|
563
|
+
Puppet::Rest::SSLContext.new(OpenSSL::SSL::VERIFY_PEER, ssl_store)
|
564
|
+
)
|
662
565
|
begin
|
663
566
|
Puppet::SSL::Certificate.from_s(cert)
|
664
567
|
rescue OpenSSL::X509::CertificateError
|
665
568
|
raise Puppet::Error, _("Response from the CA did not contain a valid certificate for %{cert_name}.") % { cert_name: cert_name }
|
666
569
|
end
|
667
570
|
rescue Puppet::Rest::ResponseError => e
|
668
|
-
if e.response.
|
571
|
+
if e.response.code.to_i == 404
|
669
572
|
Puppet.debug _("No certificate for %{cert_name} on CA") % { cert_name: cert_name }
|
670
573
|
nil
|
671
574
|
else
|
@@ -674,38 +577,19 @@ ERROR_STRING
|
|
674
577
|
end
|
675
578
|
end
|
676
579
|
|
677
|
-
# Saves the given certificate to disc, at a location determined by this
|
678
|
-
# host's configuration.
|
679
|
-
# @param [Puppet::SSL::Certificate] cert the cert to save
|
680
|
-
def save_host_certificate(cert)
|
681
|
-
file_path = certificate_location(name)
|
682
|
-
Puppet::Util.replace_file(file_path, 0644) do |f|
|
683
|
-
f.write(cert.to_s)
|
684
|
-
end
|
685
|
-
end
|
686
|
-
|
687
580
|
# Returns the file path for the named certificate, based on this host's
|
688
581
|
# configuration.
|
689
582
|
# @param [String] name the name of the cert to find
|
690
583
|
# @return [String] file path to the cert's location
|
691
584
|
def certificate_location(cert_name)
|
692
|
-
|
693
|
-
cert_name == CA_NAME ? Puppet[:cacert] : File.join(Puppet[:signeddir], "#{cert_name}.pem")
|
694
|
-
else
|
695
|
-
cert_name == CA_NAME ? Puppet[:localcacert] : File.join(Puppet[:certdir], "#{cert_name}.pem")
|
696
|
-
end
|
585
|
+
cert_name == CA_NAME ? Puppet[:localcacert] : File.join(Puppet[:certdir], "#{cert_name}.pem")
|
697
586
|
end
|
698
587
|
|
699
588
|
# Returns the file path for the named CSR, based on this host's configuration.
|
700
589
|
# @param [String] name the name of the CSR to find
|
701
590
|
# @return [String] file path to the CSR's location
|
702
591
|
def certificate_request_location(cert_name)
|
703
|
-
|
704
|
-
Puppet::SSL::Host.ca_location == :local
|
705
|
-
File.join(Puppet[:csrdir], "#{cert_name}.pem")
|
706
|
-
else
|
707
|
-
File.join(Puppet[:requestdir], "#{cert_name}.pem")
|
708
|
-
end
|
592
|
+
File.join(Puppet[:requestdir], "#{cert_name}.pem")
|
709
593
|
end
|
710
594
|
|
711
595
|
# @param [OpenSSL::X509::PURPOSE_*] constant defining the kinds of certs
|
@@ -740,5 +624,3 @@ ERROR_STRING
|
|
740
624
|
store
|
741
625
|
end
|
742
626
|
end
|
743
|
-
|
744
|
-
require 'puppet/ssl/certificate_authority'
|