diff options
-rwxr-xr-x | bin/puppetca | 49 | ||||
-rwxr-xr-x | lib/puppet/sslcertificates.rb | 1 | ||||
-rw-r--r-- | lib/puppet/sslcertificates/ca.rb | 1 | ||||
-rw-r--r-- | lib/puppet/sslcertificates/inventory.rb | 49 | ||||
-rwxr-xr-x | test/executables/puppetca.rb | 23 |
5 files changed, 114 insertions, 9 deletions
diff --git a/bin/puppetca b/bin/puppetca index f725e4a8f..d694ba294 100755 --- a/bin/puppetca +++ b/bin/puppetca @@ -46,6 +46,14 @@ # list:: # List outstanding certificate requests. # +# revoke:: +# Revoke the certificate of a client. The certificate can be specified +# either by its serial number, given as a decimal number or a hexadecimal +# number prefixed by '0x', or by its hostname. The certificate is revoked +# by adding it to the Certificate Revocation List given by the 'cacrl' +# config parameter. Note that the puppetmasterd needs to be restarted +# after revoking certificates. +# # sign:: # Sign an outstanding certificate request. Unless '--all' is specified, # hosts must be listed after all flags. @@ -81,14 +89,15 @@ rescue LoadError end options = [ - [ "--all", "-a", GetoptLong::NO_ARGUMENT ], - [ "--clean", "-c", GetoptLong::NO_ARGUMENT ], - [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], - [ "--generate", "-g", GetoptLong::NO_ARGUMENT ], - [ "--help", "-h", GetoptLong::NO_ARGUMENT ], - [ "--list", "-l", GetoptLong::NO_ARGUMENT ], - [ "--sign", "-s", GetoptLong::NO_ARGUMENT ], - [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ] + [ "--all", "-a", GetoptLong::NO_ARGUMENT ], + [ "--clean", "-c", GetoptLong::NO_ARGUMENT ], + [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], + [ "--generate", "-g", GetoptLong::NO_ARGUMENT ], + [ "--help", "-h", GetoptLong::NO_ARGUMENT ], + [ "--list", "-l", GetoptLong::NO_ARGUMENT ], + [ "--revoke", "-r", GetoptLong::NO_ARGUMENT ], + [ "--sign", "-s", GetoptLong::NO_ARGUMENT ], + [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ] ] # Add all of the config parameters as valid options. @@ -121,6 +130,8 @@ begin end when "--list" mode = :list + when "--revoke" + mode = :revoke when "--sign" mode = :sign when "--verbose" @@ -160,7 +171,7 @@ unless mode exit(12) end -if mode == :generate or mode == :clean +if mode == :generate or mode == :clean or mode == :revoke hosts = ARGV else hosts = ca.list @@ -230,6 +241,26 @@ when :generate cert.cacert = cacert cert.write } +when :revoke + hosts.each { |h| + serial = nil + if h =~ /^0x[0-9a-f]+$/ + serial = h.to_i(16) + elsif h =~ /^[0-9]+$/ + serial = h.to_i + else + cert = ca.getclientcert(h)[0] + if cert.nil? + $stderr.puts "Could not find client certificate for %s" % h + else + serial = cert.serial + end + end + unless serial.nil? + ca.revoke(serial) + puts "Revoked certificate with serial #{serial}" + end + } else $stderr.puts "Invalid mode %s" % mode exit(42) diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index a003c6551..4df8df71e 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -154,6 +154,7 @@ module Puppet::SSLCertificates return hashpath end require 'puppet/sslcertificates/certificate' + require 'puppet/sslcertificates/inventory' require 'puppet/sslcertificates/ca' end diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 89b7b183c..1574a6e73 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -346,6 +346,7 @@ class Puppet::SSLCertificates::CA [certfile, host] end + Puppet::SSLCertificates::Inventory::add(cert) Puppet.config.writesub(:signeddir, certfile) do |f| f.print cert.to_pem end diff --git a/lib/puppet/sslcertificates/inventory.rb b/lib/puppet/sslcertificates/inventory.rb new file mode 100644 index 000000000..f3f790906 --- /dev/null +++ b/lib/puppet/sslcertificates/inventory.rb @@ -0,0 +1,49 @@ +# A module for keeping track of all the certificates issued by the CA, ever +# Maintains the file "$cadir/inventory.txt" +module Puppet::SSLCertificates + module Inventory + + # Add CERT to the inventory of issued certs in '$cadir/inventory.txt' + # If no inventory exists yet, build an inventory and list all the + # certificates that have been signed so far + def Inventory.add(cert) + f = open + format(f, cert) + f.close() + end + + def Inventory.filename + File::join(Puppet[:cadir], "inventory.txt") + end + + private + def Inventory.open + if File::exist?(filename) + File::open(filename, "a") + else + init + end + end + + def Inventory.init + if File::exist?(filename) + raise Puppet::Error, + "Inventory file #{filename} already exists" + end + inv = File.open(filename, "w") + inv.puts "# Inventory of signed certificates" + Dir.glob(File::join(Puppet[:signeddir], "*.pem")) do |f| + format(inv, OpenSSL::X509::Certificate.new(File::read(f))) + end + return inv + end + + def Inventory.format(f, cert) + iso = '%Y-%m-%dT%H:%M:%S%Z' + f.puts "0x%04x %s %s %s" % [cert.serial, + cert.not_before.strftime(iso), + cert.not_after.strftime(iso), + cert.subject] + end + end +end diff --git a/test/executables/puppetca.rb b/test/executables/puppetca.rb index b722c963f..71764ebd2 100755 --- a/test/executables/puppetca.rb +++ b/test/executables/puppetca.rb @@ -84,6 +84,29 @@ class TestPuppetCA < Test::Unit::TestCase assert_equal($?,0) assert_equal(["No certificates to sign"], output) end + + def test_revocation + ca = Puppet::SSLCertificates::CA.new() + host1 = gen_cert(ca, "host1.example.com") + host2 = gen_cert(ca, "host2.example.com") + host3 = gen_cert(ca, "host3.example.com") + runca("-r host1.example.com") + runca("-r #{host2.serial}") + runca("-r 0x#{host3.serial.to_s(16)}") + runca("-r 0xff") + + # Recreate CA to force reading of CRL + ca = Puppet::SSLCertificates::CA.new() + crl = ca.crl + revoked = crl.revoked.collect { |r| r.serial } + exp = [host1.serial, host2.serial, host3.serial, 255] + assert_equal(exp, revoked) + end + + def gen_cert(ca, host) + runca("-g #{host}") + ca.getclientcert(host)[0] + end end # $Id$ |