summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorBrice Figureau <brice-puppet@daysofwonder.com>2009-12-29 15:27:54 +0100
committerJames Turnbull <james@lovedthanlost.net>2010-01-19 08:37:23 +1100
commit3e9677f00a09d0249713ed2fa503e42b07f6d978 (patch)
tree0b99bb4cd9039bb220ee75f2520b37920a6b7628 /lib/puppet
parent91c44b439794a87111ab1a0726a2ad08981c839e (diff)
downloadpuppet-3e9677f00a09d0249713ed2fa503e42b07f6d978.tar.gz
puppet-3e9677f00a09d0249713ed2fa503e42b07f6d978.tar.xz
puppet-3e9677f00a09d0249713ed2fa503e42b07f6d978.zip
Feature #2839 - fingerprint certificate
This patch adds several things: * certificate fingerprinting in --list mode * a puppetca action called "--fingerprint" to display fingerprints of given certificates (or all including CSR) * a --fingerprint puppetd option to display client certificates * each time a CSR is generated, its fingerprint is displayed in the log It is also possible to use --digest in puppetca and puppetd to specify a specific digest algorithm. Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/application/puppetca.rb8
-rw-r--r--lib/puppet/application/puppetd.rb33
-rw-r--r--lib/puppet/ssl/base.rb17
-rw-r--r--lib/puppet/ssl/certificate_authority.rb9
-rw-r--r--lib/puppet/ssl/certificate_authority/interface.rb28
-rw-r--r--lib/puppet/ssl/certificate_request.rb2
6 files changed, 78 insertions, 19 deletions
diff --git a/lib/puppet/application/puppetca.rb b/lib/puppet/application/puppetca.rb
index adc1a6ff5..7362f2a18 100644
--- a/lib/puppet/application/puppetca.rb
+++ b/lib/puppet/application/puppetca.rb
@@ -6,7 +6,7 @@ Puppet::Application.new(:puppetca) do
should_parse_config
- attr_accessor :mode, :all, :ca
+ attr_accessor :mode, :all, :ca, :digest
def find_mode(opt)
modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS
@@ -22,6 +22,10 @@ Puppet::Application.new(:puppetca) do
@all = true
end
+ option("--digest DIGEST") do |arg|
+ @digest = arg
+ end
+
option("--debug", "-d") do |arg|
Puppet::Util::Log.level = :debug
end
@@ -44,7 +48,7 @@ Puppet::Application.new(:puppetca) do
end
begin
@ca.apply(:revoke, :to => hosts) if @mode == :destroy
- @ca.apply(@mode, :to => hosts)
+ @ca.apply(@mode, :to => hosts, :digest => @digest)
rescue => detail
puts detail.backtrace if Puppet[:trace]
puts detail.to_s
diff --git a/lib/puppet/application/puppetd.rb b/lib/puppet/application/puppetd.rb
index c99b9eaff..ed2c450ee 100644
--- a/lib/puppet/application/puppetd.rb
+++ b/lib/puppet/application/puppetd.rb
@@ -9,7 +9,7 @@ Puppet::Application.new(:puppetd) do
should_parse_config
- attr_accessor :explicit_waitforcert, :args, :agent, :daemon
+ attr_accessor :explicit_waitforcert, :args, :agent, :daemon, :host
preinit do
# Do an initial trap, so that cancels don't get a stack trace.
@@ -30,7 +30,9 @@ Puppet::Application.new(:puppetd) do
:disable => false,
:client => true,
:fqdn => nil,
- :serve => []
+ :serve => [],
+ :digest => :MD5,
+ :fingerprint => false,
}.each do |opt,val|
options[opt] = val
end
@@ -49,6 +51,9 @@ Puppet::Application.new(:puppetd) do
option("--test","-t")
option("--verbose","-v")
+ option("--fingerprint")
+ option("--digest DIGEST")
+
option("--serve HANDLER", "-s") do |arg|
if Puppet::Network::Handler.handler(arg)
options[:serve] << arg.to_sym
@@ -92,10 +97,20 @@ Puppet::Application.new(:puppetd) do
end
dispatch do
+ return :fingerprint if options[:fingerprint]
return :onetime if options[:onetime]
return :main
end
+ command(:fingerprint) do
+ unless cert = host.certificate || host.certificate_request
+ $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued"
+ exit(1)
+ return
+ end
+ Puppet.notice cert.fingerprint(options[:digest])
+ end
+
command(:onetime) do
unless options[:client]
$stderr.puts "onetime is specified but there is no client"
@@ -220,10 +235,10 @@ Puppet::Application.new(:puppetd) do
Puppet.settings.use :main, :puppetd, :ssl
- # We need to specify a ca location for things to work, but
- # until the REST cert transfers are working, it needs to
- # be local.
- Puppet::SSL::Host.ca_location = :remote
+ # We need to specify a ca location for things to work
+ # in fingerprint mode we just need access to the local files and
+ # we don't need a ca.
+ Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote
Puppet::Transaction::Report.terminus_class = :rest
@@ -246,8 +261,10 @@ Puppet::Application.new(:puppetd) do
@daemon.daemonize
end
- host = Puppet::SSL::Host.new
- cert = host.wait_for_cert(options[:waitforcert])
+ @host = Puppet::SSL::Host.new
+ unless options[:fingerprint]
+ cert = @host.wait_for_cert(options[:waitforcert])
+ end
@objects = []
diff --git a/lib/puppet/ssl/base.rb b/lib/puppet/ssl/base.rb
index d67861f4b..6c74b7565 100644
--- a/lib/puppet/ssl/base.rb
+++ b/lib/puppet/ssl/base.rb
@@ -54,6 +54,23 @@ class Puppet::SSL::Base
content.to_text
end
+ def fingerprint(md = :MD5)
+ require 'openssl/digest'
+
+ # ruby 1.8.x openssl digest constants are string
+ # but in 1.9.x they are symbols
+ mds = md.to_s.upcase
+ if OpenSSL::Digest.constants.include?(mds)
+ md = mds
+ elsif OpenSSL::Digest.constants.include?(mds.to_sym)
+ md = mds.to_sym
+ else
+ raise ArgumentError, "#{md} is not a valid digest algorithm for fingerprinting certificate #{name}"
+ end
+
+ OpenSSL::Digest.hexdigest(md, content.to_der).scan(/../).join(':').upcase
+ end
+
private
def wrapped_class
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
index 8e4fd7a08..9fe67cc8a 100644
--- a/lib/puppet/ssl/certificate_authority.rb
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -53,7 +53,7 @@ class Puppet::SSL::CertificateAuthority
unless options[:to]
raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all"
end
- applier = Interface.new(method, options[:to])
+ applier = Interface.new(method, options)
applier.apply(self)
end
@@ -291,6 +291,13 @@ class Puppet::SSL::CertificateAuthority
end
end
+ def fingerprint(name, md = :MD5)
+ unless cert = Puppet::SSL::Certificate.find(name) || Puppet::SSL::CertificateRequest.find(name)
+ raise ArgumentError, "Could not find a certificate or csr for %s" % name
+ end
+ cert.fingerprint(md)
+ end
+
# List the waiting certificate requests.
def waiting?
Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name }
diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb
index 3f91434e3..d2dc7b9b5 100644
--- a/lib/puppet/ssl/certificate_authority/interface.rb
+++ b/lib/puppet/ssl/certificate_authority/interface.rb
@@ -2,11 +2,11 @@
# on the CA. It's only used by the 'puppetca' executable, and its
# job is to provide a CLI-like interface to the CA class.
class Puppet::SSL::CertificateAuthority::Interface
- INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify]
+ INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
class InterfaceError < ArgumentError; end
- attr_reader :method, :subjects
+ attr_reader :method, :subjects, :digest
# Actually perform the work.
def apply(ca)
@@ -38,9 +38,10 @@ class Puppet::SSL::CertificateAuthority::Interface
end
end
- def initialize(method, subjects)
+ def initialize(method, options)
self.method = method
- self.subjects = subjects
+ self.subjects = options[:to]
+ @digest = options[:digest] || :MD5
end
# List the hosts.
@@ -67,11 +68,11 @@ class Puppet::SSL::CertificateAuthority::Interface
invalid = details.to_s
end
if not invalid and signed.include?(host)
- puts "+ " + host
+ puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
elsif invalid
- puts "- " + host + " (" + invalid + ")"
+ puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
else
- puts host
+ puts "#{host} (#{ca.fingerprint(host, @digest)})"
end
end
end
@@ -84,7 +85,7 @@ class Puppet::SSL::CertificateAuthority::Interface
# Print certificate information.
def print(ca)
- (subjects == :all ? ca.list : subjects).each do |host|
+ (subjects == :all ? ca.list : subjects).each do |host|
if value = ca.print(host)
puts value
else
@@ -93,6 +94,17 @@ class Puppet::SSL::CertificateAuthority::Interface
end
end
+ # Print certificate information.
+ def fingerprint(ca)
+ (subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
+ if value = ca.fingerprint(host, @digest)
+ puts "#{host} #{value}"
+ else
+ Puppet.err "Could not find certificate for %s" % host
+ end
+ end
+ end
+
# Sign a given certificate.
def sign(ca)
list = subjects == :all ? ca.waiting? : subjects
diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb
index 4008ababe..f18fe4a16 100644
--- a/lib/puppet/ssl/certificate_request.rb
+++ b/lib/puppet/ssl/certificate_request.rb
@@ -43,6 +43,8 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for %s on the server" % name unless csr.verify(key.public_key)
@content = csr
+ Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
+ @content
end
def save(args = {})