~nvalcarcel/ubuntu/lucid/puppet/fix-546677

« back to all changes in this revision

Viewing changes to bin/puppetca

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2009-12-23 00:48:10 UTC
  • mfrom: (1.1.10 upstream) (3.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091223004810-3i4oryds922g5n59
Tags: 0.25.1-3ubuntu1
* Merge from debian testing.  Remaining changes:
  - debian/rules:
    + Don't start puppet when first installing puppet.
  - debian/puppet.conf, lib/puppet/defaults.rb:
    + Move templates to /etc/puppet
  - lib/puppet/defaults.rb:
    + Fix /var/lib/puppet/state ownership.
  - man/man8/puppet.conf.8: 
    + Fix broken URL in manpage.
  - debian/control:
    + Update maintainer accordint to spec.
    + Puppetmaster Recommends -> Suggests
    + Created puppet-testsuite as a seperate. Allow the users to run puppet's 
      testsuite.
  - tests/Rakefile: Fix rakefile so that the testsuite can acutally be ran.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env ruby
2
 
 
3
 
#
4
 
# = Synopsis
5
 
#
6
 
# Stand-alone certificate authority.  Capable of generating certificates
7
 
# but mostly meant for signing certificate requests from puppet clients.
8
 
#
9
 
# = Usage
10
 
#
11
 
#   puppetca [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
12
 
#               [-g|--generate] [-l|--list] [-s|--sign] [-r|--revoke]
13
 
#               [-p|--print] [-c|--clean] [--verify] [host]
14
 
#
15
 
# = Description
16
 
#
17
 
# Because the puppetmasterd daemon defaults to not signing client certificate
18
 
# requests, this script is available for signing outstanding requests.  It
19
 
# can be used to list outstanding requests and then either sign them individually
20
 
# or sign all of them.
21
 
#
22
 
# = Options
23
 
#
24
 
# Note that any configuration parameter that's valid in the configuration file
25
 
# is also a valid long argument.  For example, 'ssldir' is a valid configuration
26
 
# parameter, so you can specify '--ssldir <directory>' as an argument.
27
 
#
28
 
# See the configuration file documentation at
29
 
# http://reductivelabs.com/projects/puppet/reference/configref.html for
30
 
# the full list of acceptable parameters. A commented list of all
31
 
# configuration options can also be generated by running puppetca with
32
 
# '--genconfig'.
33
 
#
34
 
# all::
35
 
#   Operate on all items.  Currently only makes sense with '--sign',
36
 
#   '--clean', or '--list'.
37
 
#
38
 
# clean::
39
 
#    Remove all files related to a host from puppetca's storage. This is 
40
 
#    useful when rebuilding hosts, since new certificate signing requests
41
 
#    will only be honored if puppetca does not have a copy of a signed
42
 
#    certificate for that host. The certificate of the host remains valid.
43
 
#    If '--all' is specified then all host certificates, both signed and
44
 
#    unsigned, will be removed.
45
 
#
46
 
# debug::
47
 
#   Enable full debugging.
48
 
#
49
 
# generate::
50
 
#   Generate a certificate for a named client.  A certificate/keypair will be
51
 
#   generated for each client named on the command line.
52
 
#
53
 
# help::
54
 
#   Print this help message
55
 
#
56
 
# list::
57
 
#   List outstanding certificate requests.  If '--all' is specified, 
58
 
#   signed certificates are also listed, prefixed by '+'.
59
 
#
60
 
# print::
61
 
#   Print the full-text version of a host's certificate.
62
 
#
63
 
# revoke::
64
 
#   Revoke the certificate of a client. The certificate can be specified
65
 
#   either by its serial number, given as a decimal number or a hexadecimal
66
 
#   number prefixed by '0x', or by its hostname. The certificate is revoked
67
 
#   by adding it to the Certificate Revocation List given by the 'cacrl'
68
 
#   config parameter. Note that the puppetmasterd needs to be restarted
69
 
#   after revoking certificates.
70
 
#
71
 
# sign::
72
 
#   Sign an outstanding certificate request.  Unless '--all' is specified,
73
 
#   hosts must be listed after all flags.
74
 
#
75
 
# verbose::
76
 
#   Enable verbosity.
77
 
#
78
 
# version::
79
 
#   Print the puppet version number and exit.
80
 
#
81
 
# verify::
82
 
#   Verify the named certificate against the local CA certificate.
83
 
#
84
 
# = Example
85
 
#
86
 
#   $ puppetca -l
87
 
#   culain.madstop.com
88
 
#   $ puppetca -s culain.madstop.com
89
 
#
90
 
# = Author
91
 
#
92
 
# Luke Kanies
93
 
#
94
 
# = Copyright
95
 
#
96
 
# Copyright (c) 2005 Reductive Labs, LLC
97
 
# Licensed under the GNU Public License
98
 
 
99
 
require 'puppet'
100
 
require 'puppet/sslcertificates'
101
 
require 'getoptlong'
102
 
 
103
 
options = [
104
 
    [ "--all",      "-a",  GetoptLong::NO_ARGUMENT ],
105
 
    [ "--clean",    "-c",  GetoptLong::NO_ARGUMENT ],
106
 
    [ "--debug",    "-d",  GetoptLong::NO_ARGUMENT ],
107
 
    [ "--generate", "-g",  GetoptLong::NO_ARGUMENT ],
108
 
    [ "--help",     "-h",  GetoptLong::NO_ARGUMENT ],
109
 
    [ "--list",     "-l",  GetoptLong::NO_ARGUMENT ],
110
 
    [ "--print",    "-p",  GetoptLong::NO_ARGUMENT ],
111
 
    [ "--revoke",   "-r",  GetoptLong::NO_ARGUMENT ],
112
 
    [ "--sign",     "-s",  GetoptLong::NO_ARGUMENT ],
113
 
    [ "--verify",          GetoptLong::NO_ARGUMENT ],
114
 
        [ "--version",  "-V",  GetoptLong::NO_ARGUMENT ],
115
 
    [ "--verbose",  "-v",  GetoptLong::NO_ARGUMENT ]
116
 
]
117
 
 
118
 
# Add all of the config parameters as valid options.
119
 
Puppet.settings.addargs(options)
120
 
 
121
 
result = GetoptLong.new(*options)
122
 
 
123
 
mode = nil
124
 
all = false
125
 
generate = nil
126
 
 
127
 
modes = [:clean, :list, :revoke, :generate, :sign, :print, :verify]
128
 
 
129
 
begin
130
 
    result.each { |opt,arg|
131
 
        case opt
132
 
            when "--all"
133
 
                all = true
134
 
            when "--debug"
135
 
                Puppet::Util::Log.level = :debug
136
 
            when "--generate"
137
 
                generate = arg
138
 
                mode = :generate
139
 
            when "--help"
140
 
                if Puppet.features.usage?
141
 
                    RDoc::usage && exit
142
 
                else
143
 
                    puts "No help available unless you have RDoc::usage installed"
144
 
                    exit
145
 
                end
146
 
            when "--list"
147
 
                mode = :list
148
 
            when "--revoke"
149
 
                mode = :revoke
150
 
            when "--sign"
151
 
                mode = :sign
152
 
            when "--version"
153
 
                puts "%s" % Puppet.version
154
 
                exit
155
 
            when "--verbose"
156
 
                Puppet::Util::Log.level = :info
157
 
            else
158
 
                tmp = opt.sub("--", '').to_sym
159
 
                if modes.include?(tmp)
160
 
                    mode = tmp
161
 
                else
162
 
                    Puppet.settings.handlearg(opt, arg)
163
 
                end
164
 
        end
165
 
    }
166
 
rescue GetoptLong::InvalidOption => detail
167
 
    $stderr.puts "Try '#{$0} --help'"
168
 
    exit(1)
169
 
end
170
 
 
171
 
# Now parse the config
172
 
Puppet.parse_config
173
 
 
174
 
if Puppet.settings.print_configs?
175
 
    exit(Puppet.settings.print_configs ? 0 : 1)
176
 
end
177
 
 
178
 
begin
179
 
    ca = Puppet::SSLCertificates::CA.new()
180
 
rescue => detail
181
 
    if Puppet[:debug]
182
 
        puts detail.backtrace
183
 
    end
184
 
    puts detail.to_s
185
 
    exit(23)
186
 
end
187
 
 
188
 
unless mode
189
 
    $stderr.puts "You must specify a mode; see the output from --help"
190
 
    exit(12)
191
 
end
192
 
 
193
 
if [:verify, :print, :generate, :clean, :revoke, :list].include?(mode)
194
 
    hosts = ARGV.collect { |h| h.downcase }
195
 
end
196
 
 
197
 
if [:sign, :list].include?(mode)
198
 
    waiting = ca.list
199
 
    unless waiting.length > 0 or (mode == :list and all)
200
 
        puts "No certificates to sign"
201
 
        if ARGV.length > 0
202
 
            exit(17)
203
 
        else
204
 
            exit(0)
205
 
        end
206
 
    end
207
 
end
208
 
 
209
 
case mode
210
 
when :list
211
 
    waiting = ca.list
212
 
    if waiting.length > 0
213
 
        puts waiting.join("\n")
214
 
    end
215
 
    if all
216
 
        puts ca.list_signed.collect { |cert | cert.sub(/^/,"+ ") }.join("\n")
217
 
    end
218
 
when :clean
219
 
    if hosts.empty? and all == false
220
 
        $stderr.puts "You must specify one or more hosts to clean or --all to clean all host certificates"
221
 
        exit(24)
222
 
    end
223
 
 
224
 
    cleaned = false
225
 
 
226
 
    if all
227
 
        certs = ca.list
228
 
        certs |= ca.list_signed
229
 
            if certs.empty?
230
 
                $stderr.puts "No certificates to clean"
231
 
                exit(24)
232
 
            end
233
 
            certs.each do |c|
234
 
                ca.clean(c)
235
 
            end
236
 
        cleaned = true
237
 
    else
238
 
        hosts.each do |host|
239
 
          
240
 
            unless cert = ca.getclientcert(host)[0] || ca.getclientcsr(host)
241
 
                $stderr.puts "Could not find client certificate or request for %s" % host
242
 
                next
243
 
            end           
244
 
            
245
 
            ca.clean(host)
246
 
            cleaned = true
247
 
        end
248
 
    end
249
 
 
250
 
    unless cleaned
251
 
        exit(27)
252
 
    end
253
 
when :sign
254
 
    to_sign = ARGV.collect { |h| h.downcase }
255
 
    unless to_sign.length > 0 or all
256
 
        $stderr.puts(
257
 
            "You must specify one or more hosts to sign certificates for or --all to sign all certificates"
258
 
        )
259
 
        exit(24)
260
 
    end
261
 
 
262
 
    unless all
263
 
        to_sign.each { |host|
264
 
            unless waiting.include?(host)
265
 
                $stderr.puts "No waiting request for %s" % host
266
 
            end
267
 
        }
268
 
        waiting = waiting.find_all { |host|
269
 
            to_sign.include?(host)
270
 
        }
271
 
    end
272
 
 
273
 
    waiting.each { |host|
274
 
        begin
275
 
            csr = ca.getclientcsr(host)
276
 
        rescue => detail
277
 
            $stderr.puts "Could not retrieve request for %s: %s" % [host, detail]
278
 
        end
279
 
 
280
 
        begin
281
 
            ca.sign(csr)
282
 
            $stderr.puts "Signed %s" % host
283
 
        rescue => detail
284
 
            $stderr.puts "Could not sign request for %s: %s" % [host, detail]
285
 
        end
286
 
 
287
 
        begin
288
 
            ca.removeclientcsr(host)
289
 
        rescue => detail
290
 
            $stderr.puts "Could not remove request for %s: %s" % [host, detail]
291
 
        end
292
 
    }
293
 
when :generate
294
 
    # we need to generate a certificate for a host
295
 
    hosts.each { |host|
296
 
        puts "Generating certificate for %s" % host
297
 
        cert = Puppet::SSLCertificates::Certificate.new(
298
 
            :name => host
299
 
        )
300
 
        cert.mkcsr
301
 
        signedcert, cacert = ca.sign(cert.csr)
302
 
 
303
 
        cert.cert = signedcert
304
 
        cert.cacert = cacert
305
 
        cert.write
306
 
    }
307
 
when :print
308
 
    hosts.each { |h|
309
 
        cert = ca.getclientcert(h)[0]
310
 
        puts cert.to_text
311
 
    }
312
 
when :revoke
313
 
    hosts.each { |h|
314
 
        serial = nil
315
 
        if h =~ /^0x[0-9a-f]+$/
316
 
            serial = h.to_i(16)
317
 
        elsif h =~ /^[0-9]+$/
318
 
            serial = h.to_i
319
 
        else
320
 
            cert = ca.getclientcert(h)[0]
321
 
            if cert.nil?
322
 
                $stderr.puts "Could not find client certificate for %s" % h
323
 
            else
324
 
                serial = cert.serial
325
 
            end
326
 
        end
327
 
        unless serial.nil?
328
 
            ca.revoke(serial)
329
 
            puts "Revoked certificate with serial #{serial}"
330
 
        end
331
 
    }
332
 
when :verify
333
 
    unless ssl = %x{which openssl}.chomp
334
 
        raise "Can't verify certificates without the openssl binary and could not find one"
335
 
    end
336
 
    success = true
337
 
 
338
 
    cacert = Puppet[:localcacert]
339
 
 
340
 
    hosts.each do |host|
341
 
        print "%s: " % host
342
 
        file = ca.host2certfile(host)
343
 
        unless FileTest.exist?(file)
344
 
            puts "no certificate found"
345
 
            success = false
346
 
            next
347
 
        end
348
 
 
349
 
 
350
 
        command = %{#{ssl} verify -CAfile #{cacert} #{file}}
351
 
        output = %x{#{command}}
352
 
        if $? == 0
353
 
            puts "valid"
354
 
        else
355
 
            puts output
356
 
            success = false
357
 
        end
358
 
    end
359
 
else
360
 
    $stderr.puts "Invalid mode %s" % mode
361
 
    exit(42)
362
 
end
363