Puppet Plan: peadm::subplans::modify_cert_extensions

Defined in:
plans/subplans/modify_cert_extensions.pp

Overview

Parameters:

  • targets (Peadm::SingleTargetSpec)
  • primary_host (TargetSpec)
  • primary_certname (String)
  • add (Hash) (defaults to: { })
  • remove (Array) (defaults to: [ ])


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'plans/subplans/modify_cert_extensions.pp', line 2

plan peadm::subplans::modify_cert_extensions (
  Peadm::SingleTargetSpec $targets,
  TargetSpec              $primary_host,
  String                  $primary_certname,
  Hash                    $add = { },
  Array                   $remove = [ ],
) {
  $target = get_target($targets)
  $primary_target = get_target($primary_host)

  # This plan doesn't work to reissue the master cert over the orchestrator due
  # to pe-puppetserver needing to restart
  if ($primary_target == $target) {
    $primary_target.peadm::fail_on_transport('pcp')
  }

  # Figure out some information from the existing certificate
  $certdata = run_task('peadm::cert_data', $target).first.value
  $certname = $certdata['certname']
  $target_is_primary = ($certname == $primary_certname)

  # These vars represent what the extensions currently are, vs. what they should be
  $existing_exts = $certdata['extensions'].filter |$k,$v| { $k =~ /^1\.3\.6\.1\.4\.1\.34380\.1(?!\.3\.39)/ }
  $desired_exts = $existing_exts.filter |$k,$v| { !($k in $remove) } + $add

  # If the existing certificate meets all the requirements, there's no need
  # to regenerate it. Skip it and move on to the next.
  if ($certdata['certificate-exists']
      and ($desired_exts.all |$key,$val| { $existing_exts[$key] == $val })
      and !($remove.any |$key| { $key in $existing_exts.keys })) {
    out::message("${certname} already has requested extensions; certificate will not be re-issued")
    return('Skipped')
  }

  # Everything starts the same; we always stop the agent and revoke the
  # existing cert. We use `run_command` in case the master is 2019.x but
  # the agent is only 2018.x. In that scenario `run_task(service, ...)`
  # doesn't work.
  $was_running = run_command('systemctl is-active puppet.service', $target, _catch_errors => true)[0].ok
  if ($was_running) { run_command('systemctl stop puppet.service', $target) }

  # Make sure the csr_attributes.yaml file on the node matches
  run_plan('peadm::util::insert_csr_extension_requests', $target,
    extension_requests => $desired_exts,
    merge              => false,
  )

  $ca_clean_result = run_command(@("HEREDOC"/L), $primary_target, _catch_errors =>  true).first
    /opt/puppetlabs/bin/puppetserver ca clean --certname ${certname}
    |-HEREDOC

  unless $ca_clean_result.ok {
    # fail the plan unless it's a known circumstance in which it's okay to proceed.
    # Scenario 1: the primary's cert can't be cleaned because it's already revoked.
    # Scenario 2: the primary's cert can't be cleaned because it's been deleted.
    unless ($target_is_primary and (
              $ca_clean_result[merged_output] =~ /certificate revoked/ or
              $ca_clean_result[merged_output] =~ /Could not find 'hostcert'/)) {
      fail_plan($ca_clean_result)
    }
  }

  # Then things get different for clients vs. primary...
  unless ($target_is_primary) {
    # CLIENT cert regeneration
    run_task('peadm::ssl_clean', $target, certname => $certname)
    run_task('peadm::submit_csr', $target)
    run_task('peadm::sign_csr', $primary_target, certnames => [$certname])

    # Use a command instead of a task so that this works for Puppet 5 agents
    # w/ PCP transport. If using a task, we run into problems downloading
    # the task file at this point, because there is no longer a cert file
    # present on the agent.
    run_command(@("HEREDOC"/L), $target)
      /opt/puppetlabs/bin/puppet ssl download_cert --certname ${certname} || \
      /opt/puppetlabs/bin/puppet certificate find --ca-location remote ${certname}
      |-HEREDOC
  }
  else {
    # PRIMARY cert regeneration
    $alt_names = $certdata['dns-alt-names'].empty ? {
      true  => $certdata['certname'],
      false => $certdata['dns-alt-names'].join(','),
    }

    # The docs are broken, and the process is unclean. Sadface.
    run_task('service', $target, {action => 'stop', name => 'pe-puppetserver'})
    run_command(@("HEREDOC"/L), $target)
      rm -f \
        /etc/puppetlabs/puppet/ssl/certs/${certname}.pem \
        /etc/puppetlabs/puppet/ssl/private_keys/${certname}.pem \
        /etc/puppetlabs/puppet/ssl/public_keys/${certname}.pem \
        /etc/puppetlabs/puppet/ssl/certificate_requests/${certname}.pem \
        /etc/puppetlabs/puppet/ssl/ca/signed/${certname}.pem \
      |-HEREDOC
    run_command(@("HEREDOC"/L), $target)
      /opt/puppetlabs/bin/puppetserver ca generate \
        --certname ${certname} \
        --subject-alt-names ${alt_names} \
        --ca-client
      |-HEREDOC
    run_task('service', $target, {action => 'start', name => 'pe-puppetserver'})
  }

  # Fire puppet back up when done
  if ($was_running) { run_command('systemctl start puppet.service', $target) }

  # Get PuppetDB trusted fact information back up to date
  run_command('/opt/puppetlabs/bin/puppet facts upload', $target)
}