puppet 8.1.0-x86-mingw32 → 8.2.0-x86-mingw32

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +20 -20
  3. data/lib/puppet/defaults.rb +17 -5
  4. data/lib/puppet/http/client.rb +12 -5
  5. data/lib/puppet/http/service/ca.rb +25 -0
  6. data/lib/puppet/node/environment.rb +6 -4
  7. data/lib/puppet/pops/evaluator/deferred_resolver.rb +20 -3
  8. data/lib/puppet/ssl/oids.rb +2 -0
  9. data/lib/puppet/ssl/ssl_provider.rb +1 -1
  10. data/lib/puppet/ssl/state_machine.rb +60 -9
  11. data/lib/puppet/version.rb +1 -1
  12. data/lib/puppet/x509/cert_provider.rb +7 -0
  13. data/locales/puppet.pot +71 -47
  14. data/man/man5/puppet.conf.5 +16 -2
  15. data/man/man8/puppet-agent.8 +1 -1
  16. data/man/man8/puppet-apply.8 +1 -1
  17. data/man/man8/puppet-catalog.8 +1 -1
  18. data/man/man8/puppet-config.8 +1 -1
  19. data/man/man8/puppet-describe.8 +1 -1
  20. data/man/man8/puppet-device.8 +1 -1
  21. data/man/man8/puppet-doc.8 +1 -1
  22. data/man/man8/puppet-epp.8 +1 -1
  23. data/man/man8/puppet-facts.8 +1 -1
  24. data/man/man8/puppet-filebucket.8 +1 -1
  25. data/man/man8/puppet-generate.8 +1 -1
  26. data/man/man8/puppet-help.8 +1 -1
  27. data/man/man8/puppet-lookup.8 +1 -1
  28. data/man/man8/puppet-module.8 +1 -1
  29. data/man/man8/puppet-node.8 +1 -1
  30. data/man/man8/puppet-parser.8 +1 -1
  31. data/man/man8/puppet-plugin.8 +1 -1
  32. data/man/man8/puppet-report.8 +1 -1
  33. data/man/man8/puppet-resource.8 +1 -1
  34. data/man/man8/puppet-script.8 +1 -1
  35. data/man/man8/puppet-ssl.8 +1 -1
  36. data/man/man8/puppet.8 +2 -2
  37. data/spec/fixtures/ssl/127.0.0.1-key.pem +107 -107
  38. data/spec/fixtures/ssl/127.0.0.1.pem +52 -51
  39. data/spec/fixtures/ssl/bad-basic-constraints.pem +56 -56
  40. data/spec/fixtures/ssl/bad-int-basic-constraints.pem +53 -53
  41. data/spec/fixtures/ssl/ca.pem +54 -54
  42. data/spec/fixtures/ssl/crl.pem +26 -26
  43. data/spec/fixtures/ssl/ec-key.pem +11 -11
  44. data/spec/fixtures/ssl/ec.pem +33 -32
  45. data/spec/fixtures/ssl/encrypted-ec-key.pem +12 -12
  46. data/spec/fixtures/ssl/encrypted-key.pem +108 -108
  47. data/spec/fixtures/ssl/intermediate-agent-crl.pem +26 -26
  48. data/spec/fixtures/ssl/intermediate-agent.pem +56 -56
  49. data/spec/fixtures/ssl/intermediate-crl.pem +29 -29
  50. data/spec/fixtures/ssl/intermediate.pem +53 -53
  51. data/spec/fixtures/ssl/oid-key.pem +107 -107
  52. data/spec/fixtures/ssl/oid.pem +51 -50
  53. data/spec/fixtures/ssl/pluto-key.pem +107 -107
  54. data/spec/fixtures/ssl/pluto.pem +52 -51
  55. data/spec/fixtures/ssl/renewed.pem +67 -0
  56. data/spec/fixtures/ssl/request-key.pem +107 -107
  57. data/spec/fixtures/ssl/request.pem +50 -48
  58. data/spec/fixtures/ssl/revoked-key.pem +107 -107
  59. data/spec/fixtures/ssl/revoked.pem +51 -50
  60. data/spec/fixtures/ssl/signed-key.pem +107 -107
  61. data/spec/fixtures/ssl/signed.pem +49 -48
  62. data/spec/fixtures/ssl/tampered-cert.pem +51 -50
  63. data/spec/fixtures/ssl/tampered-csr.pem +50 -48
  64. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +107 -107
  65. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +50 -49
  66. data/spec/fixtures/ssl/unknown-ca-key.pem +107 -107
  67. data/spec/fixtures/ssl/unknown-ca.pem +54 -54
  68. data/spec/integration/application/agent_spec.rb +27 -27
  69. data/spec/integration/application/apply_spec.rb +14 -0
  70. data/spec/integration/http/client_spec.rb +16 -0
  71. data/spec/lib/puppet/test_ca.rb +3 -10
  72. data/spec/unit/defaults_spec.rb +2 -40
  73. data/spec/unit/file_system/path_pattern_spec.rb +15 -0
  74. data/spec/unit/http/service/ca_spec.rb +71 -0
  75. data/spec/unit/ssl/ssl_provider_spec.rb +20 -0
  76. data/spec/unit/ssl/state_machine_spec.rb +75 -3
  77. data/spec/unit/x509/cert_provider_spec.rb +23 -0
  78. data/tasks/generate_cert_fixtures.rake +4 -0
  79. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be8d0f3acbccbdbcc42ccdc852633974adcc94199e3872d7d5a189905af12f71
4
- data.tar.gz: 1186f83bde61e09ef1bbbfca662481e474896fe61550df9bdb9546fac8d9f524
3
+ metadata.gz: cb262f46be9104598978c3941387c9df75d721c635fe403e7c4426efacb87f4f
4
+ data.tar.gz: ae6866634e1e346ef8a28a964cfa1552c02f8afe21ca4894682cc850656afb1c
5
5
  SHA512:
6
- metadata.gz: d1d5badebf5f9352e802c8737be7b8956c8ab0e6f8f4d04c5a27fdb8170de7abed37789db311d45f17fda5e7974280fe099f2d67be98ec6d520435bbcdd59e28
7
- data.tar.gz: 58f214114d5d8d0e7f4bace9a31618a5c9b44da188a4ab8f753295c743287f35c4f28baa82abd8c858a01f0cdb7a175fa019e4b1459bb8e88a1b3d394944f4a9
6
+ metadata.gz: 5b33b9646dd7bafea8dbb994abf35c838fb708ff9032ff6a9da22ef79da52c10460e8387f18b7c32dc7b9ce2fe1820c5d5cde04463665d35e06ecbdee34568ca
7
+ data.tar.gz: d826de6788fbe4fb802c2ff1be076783669a6c257ba2332ceca5d3e2bae64a576a4a5f8bcccab1f23f983b5b0bd4b2624106de27e6f35199d2beff79e5c6e94d
data/Gemfile.lock CHANGED
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: https://github.com/puppetlabs/packaging
3
- revision: 87a3396077f06e2341ad19e6fcd15f7c14ec02f9
3
+ revision: affecba5dfacc5862fc7199895ccf11b69153570
4
4
  branch: 1.0.x
5
5
  specs:
6
6
  packaging (0)
@@ -15,7 +15,7 @@ GIT
15
15
  PATH
16
16
  remote: .
17
17
  specs:
18
- puppet (8.1.0)
18
+ puppet (8.2.0)
19
19
  CFPropertyList (~> 2.2)
20
20
  concurrent-ruby (~> 1.0)
21
21
  deep_merge (~> 1.0)
@@ -31,7 +31,7 @@ GEM
31
31
  remote: https://artifactory.delivery.puppetlabs.net/artifactory/api/gems/rubygems/
32
32
  specs:
33
33
  CFPropertyList (2.3.6)
34
- addressable (2.8.4)
34
+ addressable (2.8.5)
35
35
  public_suffix (>= 2.0.2, < 6.0)
36
36
  apt_stage_artifacts (0.11.0)
37
37
  docopt
@@ -41,25 +41,25 @@ GEM
41
41
  concurrent-ruby (1.2.2)
42
42
  crack (0.4.5)
43
43
  rexml
44
- csv (3.2.6)
44
+ csv (3.2.7)
45
45
  declarative (0.0.20)
46
46
  deep_merge (1.2.2)
47
47
  diff-lcs (1.5.0)
48
- digest-crc (0.6.4)
48
+ digest-crc (0.6.5)
49
49
  rake (>= 12.0.0, < 14.0.0)
50
50
  docopt (0.6.1)
51
51
  erubi (1.12.0)
52
- facter (4.4.0)
52
+ facter (4.4.2)
53
53
  hocon (~> 1.3)
54
54
  thor (>= 1.0.1, < 2.0)
55
- faraday (2.7.6)
55
+ faraday (2.7.10)
56
56
  faraday-net_http (>= 2.0, < 3.1)
57
57
  ruby2_keywords (>= 0.0.4)
58
58
  faraday-net_http (3.0.2)
59
59
  fast_gettext (2.3.0)
60
60
  ffi (1.15.5)
61
61
  forwardable (1.3.3)
62
- gettext (3.4.4)
62
+ gettext (3.4.7)
63
63
  erubi
64
64
  locale (>= 2.0.5)
65
65
  prime
@@ -69,7 +69,7 @@ GEM
69
69
  fast_gettext (~> 2.1)
70
70
  gettext (~> 3.4)
71
71
  locale
72
- google-apis-core (0.11.0)
72
+ google-apis-core (0.11.1)
73
73
  addressable (~> 2.5, >= 2.5.1)
74
74
  googleauth (>= 0.16.2, < 2.a)
75
75
  httpclient (>= 2.8.1, < 3.a)
@@ -96,7 +96,7 @@ GEM
96
96
  google-cloud-core (~> 1.6)
97
97
  googleauth (>= 0.16.2, < 2.a)
98
98
  mini_mime (~> 1.0)
99
- googleauth (1.5.2)
99
+ googleauth (1.7.0)
100
100
  faraday (>= 0.17.3, < 3.a)
101
101
  jwt (>= 1.4, < 3.0)
102
102
  memoist (~> 0.16)
@@ -118,12 +118,12 @@ GEM
118
118
  memoist (0.16.2)
119
119
  memory_profiler (1.0.1)
120
120
  method_source (1.0.0)
121
- mini_mime (1.1.2)
121
+ mini_mime (1.1.5)
122
122
  minitar (0.9)
123
- msgpack (1.7.1)
123
+ msgpack (1.7.2)
124
124
  multi_json (1.15.0)
125
125
  mustache (1.1.1)
126
- optimist (3.0.1)
126
+ optimist (3.1.0)
127
127
  os (1.1.4)
128
128
  parallel (1.23.0)
129
129
  parser (3.2.2.3)
@@ -135,15 +135,15 @@ GEM
135
135
  pry (0.14.2)
136
136
  coderay (~> 1.1)
137
137
  method_source (~> 1.0)
138
- public_suffix (5.0.1)
139
- puppet-resource_api (1.8.14)
138
+ public_suffix (5.0.3)
139
+ puppet-resource_api (1.9.0)
140
140
  hocon (>= 1.0)
141
141
  puppetserver-ca (2.6.0)
142
142
  facter (>= 2.0.1, < 5)
143
143
  racc (1.5.2)
144
144
  rainbow (3.1.1)
145
145
  rake (13.0.6)
146
- rdiscount (2.2.7)
146
+ rdiscount (2.2.7.1)
147
147
  rdoc (6.3.3)
148
148
  regexp_parser (2.8.1)
149
149
  release-metrics (1.1.0)
@@ -154,7 +154,7 @@ GEM
154
154
  trailblazer-option (>= 0.1.1, < 0.2.0)
155
155
  uber (< 0.2.0)
156
156
  retriable (3.1.2)
157
- rexml (3.2.5)
157
+ rexml (3.2.6)
158
158
  ronn (0.7.3)
159
159
  hpricot (>= 0.8.2)
160
160
  mustache (>= 0.7.0)
@@ -171,10 +171,10 @@ GEM
171
171
  rspec-its (1.3.0)
172
172
  rspec-core (>= 3.0.0)
173
173
  rspec-expectations (>= 3.0.0)
174
- rspec-mocks (3.12.5)
174
+ rspec-mocks (3.12.6)
175
175
  diff-lcs (>= 1.2.0, < 2.0)
176
176
  rspec-support (~> 3.12.0)
177
- rspec-support (3.12.0)
177
+ rspec-support (3.12.1)
178
178
  rubocop (1.28.0)
179
179
  parallel (~> 1.10)
180
180
  parser (>= 3.1.0.0)
@@ -204,7 +204,7 @@ GEM
204
204
  trailblazer-option (0.1.2)
205
205
  uber (0.1.0)
206
206
  unicode-display_width (2.4.2)
207
- vcr (6.1.0)
207
+ vcr (6.2.0)
208
208
  webmock (3.18.1)
209
209
  addressable (>= 2.8.0)
210
210
  crack (>= 0.3.2)
@@ -4,11 +4,7 @@ require_relative '../puppet/util/platform'
4
4
  module Puppet
5
5
 
6
6
  def self.default_diffargs
7
- if (Puppet.runtime[:facter].value(:kernel) == "AIX" && Puppet.runtime[:facter].value(:kernelmajversion) == "5300")
8
- ""
9
- else
10
- "-u"
11
- end
7
+ '-u'
12
8
  end
13
9
 
14
10
  def self.default_digest_algorithm
@@ -1248,6 +1244,22 @@ EOT
1248
1244
  unchanged on the server, then the agent run will continue using the
1249
1245
  local CRL it already has.#{AS_DURATION}",
1250
1246
  },
1247
+ :hostcert_renewal_interval => {
1248
+ :default => "30d",
1249
+ :type => :duration,
1250
+ :desc => "How often the Puppet agent refreshes its client certificate.
1251
+ By default the client certificate is refreshed once every 30 days. If
1252
+ a different duration is specified, then the agent will refresh its
1253
+ client certificate whenever it next runs and the elapsed time since the
1254
+ client certificate was last refreshed exceeds the duration.
1255
+
1256
+ In general, the duration should be greater than the `runinterval`.
1257
+ Setting it to 0 will disable automatic renewal.
1258
+
1259
+ If the agent downloads a new certificate, the agent will use it for subsequent
1260
+ network requests. If the refresh request fails, then the agent run will continue using the
1261
+ certificate it already has. #{AS_DURATION}",
1262
+ },
1251
1263
  :keylength => {
1252
1264
  :default => 4096,
1253
1265
  :type => :integer,
@@ -368,6 +368,7 @@ class Puppet::HTTP::Client
368
368
  apply_auth(request, basic_auth) if redirects.zero?
369
369
 
370
370
  # don't call return within the `request` block
371
+ close_and_sleep = nil
371
372
  http.request(request) do |nethttp|
372
373
  response = Puppet::HTTP::ResponseNetHTTP.new(request.uri, nethttp)
373
374
  begin
@@ -381,12 +382,14 @@ class Puppet::HTTP::Client
381
382
  interval = @retry_after_handler.retry_after_interval(request, response, retries)
382
383
  retries += 1
383
384
  if interval
384
- if http.started?
385
- Puppet.debug("Closing connection for #{Puppet::HTTP::Site.from_uri(request.uri)}")
386
- http.finish
385
+ close_and_sleep = proc do
386
+ if http.started?
387
+ Puppet.debug("Closing connection for #{Puppet::HTTP::Site.from_uri(request.uri)}")
388
+ http.finish
389
+ end
390
+ Puppet.warning(_("Sleeping for %{interval} seconds before retrying the request") % { interval: interval })
391
+ ::Kernel.sleep(interval)
387
392
  end
388
- Puppet.warning(_("Sleeping for %{interval} seconds before retrying the request") % { interval: interval })
389
- ::Kernel.sleep(interval)
390
393
  next
391
394
  end
392
395
  end
@@ -405,6 +408,10 @@ class Puppet::HTTP::Client
405
408
 
406
409
  done = true
407
410
  end
411
+ ensure
412
+ # If a server responded with a retry, make sure the connection is closed and then
413
+ # sleep the specified time.
414
+ close_and_sleep.call if close_and_sleep
408
415
  end
409
416
  end
410
417
 
@@ -104,4 +104,29 @@ class Puppet::HTTP::Service::Ca < Puppet::HTTP::Service
104
104
 
105
105
  response
106
106
  end
107
+
108
+ # Submit a POST request to send a certificate renewal request to the server
109
+ #
110
+ # @param [Puppet::SSL::SSLContext] ssl_context
111
+ #
112
+ # @return [Array<Puppet::HTTP::Response, String>] The request response
113
+ #
114
+ # @api public
115
+ def post_certificate_renewal(ssl_context)
116
+ headers = add_puppet_headers(HEADERS)
117
+ headers['Content-Type'] = 'text/plain'
118
+
119
+ response = @client.post(
120
+ with_base_url('/certificate_renewal'),
121
+ '', # Puppet::HTTP::Client.post requires a body, the API endpoint does not
122
+ headers: headers,
123
+ options: {ssl_context: ssl_context}
124
+ )
125
+
126
+ raise ArgumentError.new(_('SSL context must contain a client certificate.')) unless ssl_context.client_cert
127
+
128
+ process_response(response)
129
+
130
+ [response, response.body.to_s]
131
+ end
107
132
  end
@@ -592,10 +592,12 @@ class Puppet::Node::Environment
592
592
  if file == NO_MANIFEST
593
593
  empty_parse_result
594
594
  elsif File.directory?(file)
595
- parse_results = Puppet::FileSystem::PathPattern.absolute(File.join(file, '**/*.pp')).glob.sort.map do | file_to_parse |
596
- parser.file = file_to_parse
597
- parser.parse
598
- end
595
+ # JRuby does not properly perform Dir.glob operations with wildcards, (see PUP-11788 and https://github.com/jruby/jruby/issues/7836).
596
+ # We sort the results because Dir.glob order is inconsistent in Ruby < 3 (see PUP-10115).
597
+ parse_results = Puppet::FileSystem::PathPattern.absolute(File.join(file, '**/*')).glob.select {|globbed_file| globbed_file.end_with?('.pp')}.sort.map do | file_to_parse |
598
+ parser.file = file_to_parse
599
+ parser.parse
600
+ end
599
601
  # Use a parser type specific merger to concatenate the results
600
602
  Puppet::Parser::AST::Hostclass.new('', :code => Puppet::Parser::ParserFactory.code_merger.concatenate(parse_results))
601
603
  else
@@ -10,7 +10,13 @@ class DeferredValue
10
10
  end
11
11
 
12
12
  def resolve
13
- @proc.call
13
+ val = @proc.call
14
+ # Deferred sensitive values will be marked as such in resolve_futures()
15
+ if val.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
16
+ val.unwrap
17
+ else
18
+ val
19
+ end
14
20
  end
15
21
  end
16
22
 
@@ -88,8 +94,12 @@ class DeferredResolver
88
94
  #
89
95
  if resolved.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
90
96
  resolved = resolved.unwrap
91
- unless r.sensitive_parameters.include?(k.to_sym)
92
- r.sensitive_parameters = (r.sensitive_parameters + [k.to_sym]).freeze
97
+ mark_sensitive_parameters(r, k)
98
+ # If the value is a DeferredValue and it has an argument of type PSensitiveType, mark it as sensitive
99
+ # The DeferredValue.resolve method will unwrap it during catalog application
100
+ elsif resolved.is_a?(Puppet::Pops::Evaluator::DeferredValue)
101
+ if v.arguments.any? {|arg| arg.is_a?(Puppet::Pops::Types::PSensitiveType)}
102
+ mark_sensitive_parameters(r, k)
93
103
  end
94
104
  end
95
105
  overrides[ k ] = resolved
@@ -98,6 +108,13 @@ class DeferredResolver
98
108
  end
99
109
  end
100
110
 
111
+ def mark_sensitive_parameters(r, k)
112
+ unless r.sensitive_parameters.include?(k.to_sym)
113
+ r.sensitive_parameters = (r.sensitive_parameters + [k.to_sym]).freeze
114
+ end
115
+ end
116
+ private :mark_sensitive_parameters
117
+
101
118
  def resolve(x)
102
119
  if x.class == @deferred_class
103
120
  resolve_future(x)
@@ -71,7 +71,9 @@ module Puppet::SSL::Oids
71
71
  ["1.3.6.1.4.1.34380.1.3", 'ppAuthCertExt', 'Puppet Certificate Authorization Extension'],
72
72
 
73
73
  ["1.3.6.1.4.1.34380.1.3.1", 'pp_authorization', 'Certificate Extension Authorization'],
74
+ ["1.3.6.1.4.1.34380.1.3.2", 'pp_auth_auto_renew', 'Auto-Renew Certificate Attribute'],
74
75
  ["1.3.6.1.4.1.34380.1.3.13", 'pp_auth_role', 'Puppet Node Role Name for Authorization'],
76
+ ["1.3.6.1.4.1.34380.1.3.39", 'pp_cli_auth', 'Puppetserver CA CLI Authorization'],
75
77
  ]
76
78
 
77
79
  @did_register_puppet_oids = false
@@ -225,7 +225,7 @@ class Puppet::SSL::SSLProvider
225
225
  ssl_context.crls.each do |crl|
226
226
  oid_values = Hash[crl.extensions.map { |ext| [ext.oid, ext.value] }]
227
227
  crlNumber = oid_values['crlNumber'] || 'unknown'
228
- authKeyId = (oid_values['authorityKeyIdentifier'] || 'unknown').chomp!
228
+ authKeyId = (oid_values['authorityKeyIdentifier'] || 'unknown').chomp
229
229
  Puppet.debug("Using CRL '#{crl.issuer.to_utf8}' authorityKeyIdentifier '#{authKeyId}' crlNumber '#{crlNumber }'")
230
230
  end
231
231
  end
@@ -59,9 +59,6 @@ class Puppet::SSL::StateMachine
59
59
  now = Time.now
60
60
  last_update = @cert_provider.ca_last_update
61
61
  if needs_refresh?(now, last_update)
62
- # set last updated time first, then make a best effort to refresh
63
- @cert_provider.ca_last_update = now
64
-
65
62
  # If we refresh the CA, then we need to force the CRL to be refreshed too,
66
63
  # since if there is a new CA in the chain, then we need its CRL to check
67
64
  # the full chain for revocation status.
@@ -114,7 +111,12 @@ class Puppet::SSL::StateMachine
114
111
  Puppet.info(_("Refreshing CA certificate"))
115
112
 
116
113
  # return the next_ctx containing the updated ca
117
- [download_ca(ssl_ctx, last_update), true]
114
+ next_ctx = [download_ca(ssl_ctx, last_update), true]
115
+
116
+ # After a successful refresh, update ca_last_update
117
+ @cert_provider.ca_last_update = Time.now
118
+
119
+ next_ctx
118
120
  rescue Puppet::HTTP::ResponseError => e
119
121
  if e.response.code == 304
120
122
  Puppet.info(_("CA certificate is unmodified, using existing CA certificate"))
@@ -171,8 +173,6 @@ class Puppet::SSL::StateMachine
171
173
  now = Time.now
172
174
  last_update = @cert_provider.crl_last_update
173
175
  if needs_refresh?(now, last_update)
174
- # set last updated time first, then make a best effort to refresh
175
- @cert_provider.crl_last_update = now
176
176
  next_ctx = refresh_crl(next_ctx, last_update)
177
177
  end
178
178
  else
@@ -209,7 +209,12 @@ class Puppet::SSL::StateMachine
209
209
  Puppet.info(_("Refreshing CRL"))
210
210
 
211
211
  # return the next_ctx containing the updated crl
212
- download_crl(ssl_ctx, last_update)
212
+ next_ctx = download_crl(ssl_ctx, last_update)
213
+
214
+ # After a successful refresh, update crl_last_update
215
+ @cert_provider.crl_last_update = Time.now
216
+
217
+ next_ctx
213
218
  rescue Puppet::HTTP::ResponseError => e
214
219
  if e.response.code == 304
215
220
  Puppet.info(_("CRL is unmodified, using existing CRL"))
@@ -257,7 +262,11 @@ class Puppet::SSL::StateMachine
257
262
  next_ctx = @ssl_provider.create_context(
258
263
  cacerts: @ssl_context.cacerts, crls: @ssl_context.crls, private_key: key, client_cert: cert
259
264
  )
260
- return Done.new(@machine, next_ctx)
265
+ if needs_refresh?(cert)
266
+ return NeedRenewedCert.new(@machine, next_ctx, key)
267
+ else
268
+ return Done.new(@machine, next_ctx)
269
+ end
261
270
  end
262
271
  else
263
272
  if Puppet[:key_type] == 'ec'
@@ -273,6 +282,15 @@ class Puppet::SSL::StateMachine
273
282
 
274
283
  NeedSubmitCSR.new(@machine, @ssl_context, key)
275
284
  end
285
+
286
+ private
287
+
288
+ def needs_refresh?(cert)
289
+ cert_ttl = Puppet[:hostcert_renewal_interval]
290
+ return false unless cert_ttl
291
+
292
+ Time.now.to_i >= (cert.not_after.to_i - cert_ttl)
293
+ end
276
294
  end
277
295
 
278
296
  # Base class for states with a private key.
@@ -344,6 +362,39 @@ class Puppet::SSL::StateMachine
344
362
  end
345
363
  end
346
364
 
365
+ # Class to renew a client/host certificate automatically.
366
+ #
367
+ class NeedRenewedCert < KeySSLState
368
+ def next_state
369
+ Puppet.debug(_("Renewing client certificate"))
370
+
371
+ route = @machine.session.route_to(:ca, ssl_context: @ssl_context)
372
+ cert = OpenSSL::X509::Certificate.new(
373
+ route.post_certificate_renewal(@ssl_context)[1]
374
+ )
375
+
376
+ # verify client cert before saving
377
+ next_ctx = @ssl_provider.create_context(
378
+ cacerts: @ssl_context.cacerts, crls: @ssl_context.crls, private_key: @private_key, client_cert: cert
379
+ )
380
+ @cert_provider.save_client_cert(Puppet[:certname], cert)
381
+
382
+ Puppet.info(_("Renewed client certificate: %{cert_digest}, not before '%{not_before}', not after '%{not_after}'") % { cert_digest: @machine.digest_as_hex(cert.to_pem), not_before: cert.not_before, not_after: cert.not_after })
383
+
384
+ Done.new(@machine, next_ctx)
385
+ rescue Puppet::HTTP::ResponseError => e
386
+ if e.response.code == 404
387
+ Puppet.info(_("Certificate autorenewal has not been enabled on the server."))
388
+ else
389
+ Puppet.warning(_("Failed to automatically renew certificate: %{code} %{reason}") % { code: e.response.code, reason: e.response.reason })
390
+ end
391
+ Done.new(@machine, @ssl_context)
392
+ rescue => e
393
+ Puppet.warning(_("Unable to automatically renew certificate: %{message}") % { message: e })
394
+ Done.new(@machine, @ssl_context)
395
+ end
396
+ end
397
+
347
398
  # We cannot make progress, so wait if allowed to do so, or exit.
348
399
  #
349
400
  class Wait < SSLState
@@ -495,7 +546,7 @@ class Puppet::SSL::StateMachine
495
546
  final_state.ssl_context
496
547
  end
497
548
 
498
- # Run the state machine for CA certs and CRLs.
549
+ # Run the state machine for client certs.
499
550
  #
500
551
  # @return [Puppet::SSL::SSLContext] initialized SSLContext
501
552
  # @raise [Puppet::Error] If we fail to generate an SSLContext
@@ -7,7 +7,7 @@
7
7
  # Raketasks and such to set the version based on the output of `git describe`
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '8.1.0'
10
+ PUPPETVERSION = '8.2.0'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -311,6 +311,13 @@ class Puppet::X509::CertProvider
311
311
  options[:extension_requests] = csr_attributes.extension_requests
312
312
  end
313
313
 
314
+ # Adds auto-renew attribute to CSR if the agent supports auto-renewal of
315
+ # certificates
316
+ if Puppet[:hostcert_renewal_interval] && Puppet[:hostcert_renewal_interval] > 0
317
+ options[:csr_attributes] ||= {}
318
+ options[:csr_attributes].merge!({'1.3.6.1.4.1.34380.1.3.2' => 'true'})
319
+ end
320
+
314
321
  csr = Puppet::SSL::CertificateRequest.new(name)
315
322
  csr.generate(private_key, options)
316
323
  end