Skip to content

Commit 5486105

Browse files
committed
Get certificate status from primary
When running peadm::subplans::modify_certificate also get status of certificate from the perspective of the primary to detect if the certificate has been revoked. Introduces new task, peadm::cert_valid_status which checks different failure scenarios when validating certificates.
1 parent d9df038 commit 5486105

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

plans/subplans/modify_certificate.pp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
# Figure out some information from the existing certificate
2121
$certdata = run_task('peadm::cert_data', $target).first.value
2222
$certname = $certdata['certname']
23+
24+
25+
2326
$target_is_primary = ($certname == $primary_certname)
2427

2528
# These vars represent what the extensions currently are, vs. what they should be
@@ -34,7 +37,6 @@
3437
($desired_alt_names == $existing_alt_names) and
3538
($desired_exts.all |$key,$val| { $existing_exts[$key] == $val }) and
3639
!($remove_extensions.any |$key| { $key in $existing_exts.keys }) and
37-
!$certdata['certificate-revoked'] and
3840
!$force_regenerate)
3941
{
4042
out::message("${certname} already has requested modifications; certificate will not be re-issued")
@@ -66,9 +68,11 @@
6668
# fail the plan unless it's a known circumstance in which it's okay to proceed.
6769
# Scenario 1: the primary's cert can't be cleaned because it's already revoked.
6870
# Scenario 2: the primary's cert can't be cleaned because it's been deleted.
71+
# Scenario 3: a component's cert can't be cleaned because it was previously by some other function.
6972
unless ($target_is_primary and
7073
($ca_clean_result[merged_output] =~ /certificate revoked/ or
71-
$ca_clean_result[merged_output] =~ /Could not find 'hostcert'/))
74+
$ca_clean_result[merged_output] =~ /Could not find 'hostcert'/ or
75+
$ca_clean_result[merged_output] =~ /Could not find files to clean/))
7276
{
7377
fail_plan($ca_clean_result)
7478
}

plans/subplans/prepare_agent.pp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,35 @@
3636
run_command('/opt/puppetlabs/bin/puppet config delete --section agent server_list', $agent_target)
3737
}
3838

39+
# Obtain data about certificate from primary
40+
$certstatus = run_task('peadm::cert_valid_status', $primary_target,
41+
certname => $agent_target.peadm::certname()).first.value
42+
43+
if ($certstatus['certificate-status'] == 'invalid') {
44+
$force_regenerate = true
45+
$skip_csr = true
46+
} else {
47+
$force_regenerate = false
48+
$skip_csr = false
49+
50+
}
51+
3952
# Ensures scenarios where agent was pre-installed but never on-boarding and
4053
# when agent was absent but their was an existing signed certificate with the
4154
# same name as the one being provisioned.
4255
#
4356
# If necessary, manually submit a CSR
4457
# ignoring errors to simplify logic
45-
run_task('peadm::submit_csr', $agent_target, {'_catch_errors' => true})
58+
unless $skip_csr {
59+
run_task('peadm::submit_csr', $agent_target, {'_catch_errors' => true})
4660

47-
# On primary, if necessary, sign the certificate request
48-
run_task('peadm::sign_csr', $primary_target, { 'certnames' => [$agent_target.peadm::certname()] } )
61+
# On primary, if necessary, sign the certificate request
62+
run_task('peadm::sign_csr', $primary_target, { 'certnames' => [$agent_target.peadm::certname()] } )
63+
}
4964

5065
run_plan('peadm::modify_certificate', $agent_target,
51-
primary_host => $primary_target.peadm::certname(),
52-
add_extensions => $certificate_extensions
66+
primary_host => $primary_target.peadm::certname(),
67+
add_extensions => $certificate_extensions,
68+
force_regenerate => $force_regenerate
5369
)
5470
}

tasks/cert_valid_status.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"description": "Check primary for valid state of a certificate",
3+
"parameters": {
4+
"certname": {
5+
"type": "String",
6+
"description": "The certifcate name to check validation of"
7+
}
8+
},
9+
"input_method": "stdin",
10+
"implementations": [
11+
{"name": "cert_valid_status.rb"}
12+
]
13+
}

tasks/cert_valid_status.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/opt/puppetlabs/puppet/bin/ruby
2+
# frozen_string_literal: true
3+
4+
require 'puppet'
5+
require 'json'
6+
7+
$params = JSON.parse(STDIN.read)
8+
9+
Puppet.initialize_settings
10+
11+
Puppet.settings.use(:agent, :server, :master, :main)
12+
13+
begin
14+
cert_provider = Puppet::X509::CertProvider.new
15+
ssl_provider = Puppet::SSL::SSLProvider.new
16+
password = cert_provider.load_private_key_password
17+
ssl_context = ssl_provider.load_context(certname: $params['certname'], password: password)
18+
rescue Puppet::SSL::CertVerifyError => e
19+
status = { 'certificate-status' => 'invalid', 'reason' => e.message }
20+
rescue Puppet::Error => e
21+
status = { 'certificate-status' => 'unknown', 'reason' => e.message }
22+
else
23+
cert = ssl_context.client_chain.first
24+
status = { 'certificate-status' => 'valid', 'reason' => "Expires - #{cert.not_after}" }
25+
end
26+
27+
result = status
28+
29+
# Put the result to stdout
30+
puts result.to_json

0 commit comments

Comments
 (0)