1
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
require 'puppet/face'
Puppet::Face.define(:ca, '0.1.0') do
copyright "Puppet Labs", 2011
license "Apache 2 license; see COPYING"
summary "Local Puppet Certificate Authority management."
description <<-TEXT
This provides local management of the Puppet Certificate Authority.
You can use this subcommand to sign outstanding certificate requests, list
and manage local certificates, and inspect the state of the CA.
TEXT
action :list do
summary "List certificates and/or certificate requests."
description <<-TEXT
This will list the current certificates and certificate signing requests
in the Puppet CA. You will also get the fingerprint, and any certificate
verification failure reported.
TEXT
option "--[no-]all" do
summary "Include all certificates and requests."
end
option "--[no-]pending" do
summary "Include pending certificate signing requests."
end
option "--[no-]signed" do
summary "Include signed certificates."
end
option "--subject PATTERN" do
summary "Only list if the subject matches PATTERN."
description <<-TEXT
Only include certificates or requests where subject matches PATTERN.
PATTERN is interpreted as a regular expression, allowing complex
filtering of the content.
TEXT
end
when_invoked do |options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
pattern = options[:subject].nil? ? nil :
Regexp.new(options[:subject], Regexp::IGNORECASE)
pending = options[:pending].nil? ? options[:all] : options[:pending]
signed = options[:signed].nil? ? options[:all] : options[:signed]
# By default we list pending, so if nothing at all was requested...
unless pending or signed then pending = true end
hosts = []
pending and hosts += ca.waiting?
signed and hosts += ca.list
pattern and hosts = hosts.select {|hostname| pattern.match hostname }
hosts.sort.map {|host| Puppet::SSL::Host.new(host) }
end
when_rendering :console do |hosts|
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
length = hosts.map{|x| x.name.length }.max + 1
hosts.map do |host|
name = host.name.ljust(length)
if host.certificate_request then
" #{name} (#{host.certificate_request.fingerprint})"
else
begin
ca.verify(host.certificate)
"+ #{name} (#{host.certificate.fingerprint})"
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
"- #{name} (#{host.certificate.fingerprint}) (#{e.to_s})"
end
end
end.join("\n")
end
end
action :destroy do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
ca.destroy host
end
end
action :revoke do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.revoke host
rescue ArgumentError => e
# This is a bit naff, but it makes the behaviour consistent with the
# destroy action. The underlying tools could be nicer for that sort
# of thing; they have fairly inconsistent reporting of failures.
raise unless e.to_s =~ /Could not find a serial number for /
"Nothing was revoked"
end
end
end
action :generate do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.generate host
rescue RuntimeError => e
if e.to_s =~ /already has a requested certificate/
"#{host} already has a certificate request; use sign instead"
else
raise
end
rescue ArgumentError => e
if e.to_s =~ /A Certificate already exists for /
"#{host} already has a certificate"
else
raise
end
end
end
end
action :sign do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.sign host
rescue ArgumentError => e
if e.to_s =~ /Could not find certificate request/
e.to_s
else
raise
end
end
end
end
action :print do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
ca.print host
end
end
action :fingerprint do
option "--digest ALGORITHM" do
summary "The hash algorithm to use when displaying the fingerprint"
end
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
# I want the default from the CA, not to duplicate it, but passing
# 'nil' explicitly means that we don't get that. This works...
if options.has_key? :digest
ca.fingerprint host, options[:digest]
else
ca.fingerprint host
end
rescue ArgumentError => e
raise unless e.to_s =~ /Could not find a certificate or csr for/
nil
end
end
end
action :verify do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.verify host
{ :host => host, :valid => true }
rescue ArgumentError => e
raise unless e.to_s =~ /Could not find a certificate for/
{ :host => host, :valid => false, :error => e.to_s }
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
{ :host => host, :valid => false, :error => e.to_s }
end
end
when_rendering :console do |value|
if value[:valid]
nil
else
"Could not verify #{value[:host]}: #{value[:error]}"
end
end
end
end
|