class Puppet::SSL::StateMachine

This class implements a state machine for bootstrapping a host's CA and CRL bundles, private key and signed client certificate. Each state has a frozen SSLContext that it uses to make network connections. If a state makes progress bootstrapping the host, then the state will generate a new frozen SSLContext and pass that to the next state. For example, the NeedCACerts state will load or download a CA bundle, and generate a new SSLContext containing those CA certs. This way we're sure about which SSLContext is being used during any phase of the bootstrapping process.

@api private

Attributes

ca_fingerprint[R]
cert_provider[R]
digest[R]
session[RW]
ssl_provider[R]
wait_deadline[R]
waitforcert[R]
waitforlock[R]
waitlock_deadline[R]

Public Class Methods

new(waitforcert: Puppet[:waitforcert], maxwaitforcert: Puppet[:maxwaitforcert], waitforlock: Puppet[:waitforlock], maxwaitforlock: Puppet[:maxwaitforlock], onetime: Puppet[:onetime], cert_provider: Puppet::X509::CertProvider.new, ssl_provider: Puppet::SSL::SSLProvider.new, lockfile: Puppet::Util::Pidlock.new(Puppet[:ssl_lockfile]), digest: 'SHA256', ca_fingerprint: Puppet[:ca_fingerprint]) click to toggle source

Construct a state machine to manage the SSL initialization process. By default, if the state machine encounters an exception, it will log the exception and wait for `waitforcert` seconds and retry, restarting from the beginning of the state machine.

However, if `onetime` is true, then the state machine will raise the first error it encounters, instead of waiting. Otherwise, if `waitforcert` is 0, then then state machine will exit instead of wait.

@param waitforcert [Integer] how many seconds to wait between attempts @param maxwaitforcert [Integer] maximum amount of seconds to wait for the

server to sign the certificate request

@param waitforlock [Integer] how many seconds to wait between attempts for

acquiring the ssl lock

@param maxwaitforlock [Integer] maximum amount of seconds to wait for an

already running process to release the ssl lock

@param onetime [Boolean] whether to run onetime @param lockfile [Puppet::Util::Pidlock] lockfile to protect against

concurrent modification by multiple processes

@param cert_provider [Puppet::X509::CertProvider] cert provider to use

to load and save X509 objects.

@param ssl_provider [Puppet::SSL::SSLProvider] ssl provider to use

to construct ssl contexts.

@param digest [String] digest algorithm to use for certificate fingerprinting @param ca_fingerprint [String] optional fingerprint to verify the

downloaded CA bundle
    # File lib/puppet/ssl/state_machine.rb
381 def initialize(waitforcert: Puppet[:waitforcert],
382                maxwaitforcert: Puppet[:maxwaitforcert],
383                waitforlock: Puppet[:waitforlock],
384                maxwaitforlock: Puppet[:maxwaitforlock],
385                onetime: Puppet[:onetime],
386                cert_provider: Puppet::X509::CertProvider.new,
387                ssl_provider: Puppet::SSL::SSLProvider.new,
388                lockfile: Puppet::Util::Pidlock.new(Puppet[:ssl_lockfile]),
389                digest: 'SHA256',
390                ca_fingerprint: Puppet[:ca_fingerprint])
391   @waitforcert = waitforcert
392   @wait_deadline = Time.now.to_i + maxwaitforcert
393   @waitforlock = waitforlock
394   @waitlock_deadline = Time.now.to_i + maxwaitforlock
395   @onetime = onetime
396   @cert_provider = cert_provider
397   @ssl_provider = ssl_provider
398   @lockfile = lockfile
399   @digest = digest
400   @ca_fingerprint = ca_fingerprint
401   @session = Puppet.runtime[:http].create_session
402 end

Public Instance Methods

ensure_ca_certificates() click to toggle source

Run the state machine for CA certs and CRLs.

@return [Puppet::SSL::SSLContext] initialized SSLContext @raise [Puppet::Error] If we fail to generate an SSLContext @api private

    # File lib/puppet/ssl/state_machine.rb
409 def ensure_ca_certificates
410   final_state = run_machine(NeedLock.new(self), NeedKey)
411   final_state.ssl_context
412 end
ensure_client_certificate() click to toggle source

Run the state machine for CA certs and CRLs.

@return [Puppet::SSL::SSLContext] initialized SSLContext @raise [Puppet::Error] If we fail to generate an SSLContext @api private

    # File lib/puppet/ssl/state_machine.rb
419 def ensure_client_certificate
420   final_state = run_machine(NeedLock.new(self), Done)
421   ssl_context = final_state.ssl_context
422 
423   if Puppet::Util::Log.sendlevel?(:debug)
424     chain = ssl_context.client_chain
425     # print from root to client
426     chain.reverse.each_with_index do |cert, i|
427       digest = Puppet::SSL::Digest.new(@digest, cert.to_der)
428       if i == chain.length - 1
429         Puppet.debug(_("Verified client certificate '%{subject}' fingerprint %{digest}") % {subject: cert.subject.to_utf8, digest: digest})
430       else
431         Puppet.debug(_("Verified CA certificate '%{subject}' fingerprint %{digest}") % {subject: cert.subject.to_utf8, digest: digest})
432       end
433     end
434   end
435 
436   ssl_context
437 end
lock() click to toggle source
    # File lib/puppet/ssl/state_machine.rb
439 def lock
440   @lockfile.lock
441 end
unlock() click to toggle source
    # File lib/puppet/ssl/state_machine.rb
443 def unlock
444   @lockfile.unlock
445 end

Private Instance Methods

run_machine(state, stop) click to toggle source
    # File lib/puppet/ssl/state_machine.rb
449 def run_machine(state, stop)
450   loop do
451     state = run_step(state)
452 
453     case state
454     when stop
455       break
456     when LockFailure
457       raise Puppet::Error, state.message
458     when Error
459       if @onetime
460         Puppet.log_exception(state.error)
461         raise state.error
462       end
463     else
464       # fall through
465     end
466   end
467 
468   state
469 ensure
470   @lockfile.unlock if @lockfile.locked?
471 end
run_step(state) click to toggle source
    # File lib/puppet/ssl/state_machine.rb
473 def run_step(state)
474   state.next_state
475 rescue => e
476   state.to_error(e.message, e)
477 end