diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2007-03-06 19:03:05 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2007-03-06 19:03:05 +0000 |
| commit | 46d344b9daa24047b60183cc94509d306b6b562a (patch) | |
| tree | 3c11eaad696ba3d6e6dd40bd7b9e7d1a4a71af85 /lib/puppet/network/handler/ca.rb | |
| parent | 68233706a9ff05be8fa8ab3ab7198cd0918517d6 (diff) | |
| download | puppet-46d344b9daa24047b60183cc94509d306b6b562a.tar.gz puppet-46d344b9daa24047b60183cc94509d306b6b562a.tar.xz puppet-46d344b9daa24047b60183cc94509d306b6b562a.zip | |
Merging the webserver_portability branch from version 2182 to version 2258.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2259 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/network/handler/ca.rb')
| -rw-r--r-- | lib/puppet/network/handler/ca.rb | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/puppet/network/handler/ca.rb b/lib/puppet/network/handler/ca.rb new file mode 100644 index 000000000..06e0486bf --- /dev/null +++ b/lib/puppet/network/handler/ca.rb @@ -0,0 +1,152 @@ +require 'openssl' +require 'puppet' +require 'puppet/sslcertificates' +require 'xmlrpc/server' + +# Much of this was taken from QuickCert: +# http://segment7.net/projects/ruby/QuickCert/ + +class Puppet::Network::Handler + class CA < Handler + attr_reader :ca + + @interface = XMLRPC::Service::Interface.new("puppetca") { |iface| + iface.add_method("array getcert(csr)") + } + + def autosign + if defined? @autosign + @autosign + else + Puppet[:autosign] + end + end + + # FIXME autosign? should probably accept both hostnames and IP addresses + def autosign?(hostname) + # simple values are easy + if autosign == true or autosign == false + return autosign + end + + # we only otherwise know how to handle files + unless autosign =~ /^\// + raise Puppet::Error, "Invalid autosign value %s" % + autosign.inspect + end + + unless FileTest.exists?(autosign) + unless defined? @@warnedonautosign + @@warnedonautosign = true + Puppet.info "Autosign is enabled but %s is missing" % autosign + end + return false + end + auth = Puppet::Network::AuthStore.new + File.open(autosign) { |f| + f.each { |line| + next if line =~ /^\s*#/ + next if line =~ /^\s*$/ + auth.allow(line.chomp) + } + } + + # for now, just cheat and pass a fake IP address to allowed? + return auth.allowed?(hostname, "127.1.1.1") + end + + def initialize(hash = {}) + Puppet.config.use(:puppet, :certificates, :ca) + if hash.include? :autosign + @autosign = hash[:autosign] + end + + @ca = Puppet::SSLCertificates::CA.new(hash) + end + + # our client sends us a csr, and we either store it for later signing, + # or we sign it right away + def getcert(csrtext, client = nil, clientip = nil) + csr = OpenSSL::X509::Request.new(csrtext) + + # Use the hostname from the CSR, not from the network. + subject = csr.subject + + nameary = subject.to_a.find { |ary| + ary[0] == "CN" + } + + if nameary.nil? + Puppet.err( + "Invalid certificate request: could not retrieve server name" + ) + return "invalid" + end + + hostname = nameary[1] + + unless @ca + Puppet.notice "Host %s asked for signing from non-CA master" % hostname + return "" + end + + # We used to save the public key, but it's basically unnecessary + # and it mucks with the permissions requirements. + # save_pk(hostname, csr.public_key) + + certfile = File.join(Puppet[:certdir], [hostname, "pem"].join(".")) + + # first check to see if we already have a signed cert for the host + cert, cacert = ca.getclientcert(hostname) + if cert and cacert + Puppet.info "Retrieving existing certificate for %s" % hostname + #Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] + return [cert.to_pem, cacert.to_pem] + elsif @ca + if self.autosign?(hostname) or client.nil? + if client.nil? + Puppet.info "Signing certificate for CA server" + end + # okay, we don't have a signed cert + # if we're a CA and autosign is turned on, then go ahead and sign + # the csr and return the results + Puppet.info "Signing certificate for %s" % hostname + cert, cacert = @ca.sign(csr) + #Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class] + return [cert.to_pem, cacert.to_pem] + else # just write out the csr for later signing + if @ca.getclientcsr(hostname) + Puppet.info "Not replacing existing request from %s" % hostname + else + Puppet.notice "Host %s has a waiting certificate request" % + hostname + @ca.storeclientcsr(csr) + end + return ["", ""] + end + else + raise "huh?" + end + end + + private + + # Save the public key. + def save_pk(hostname, public_key) + pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.')) + + if FileTest.exists?(pkeyfile) + currentkey = File.open(pkeyfile) { |k| k.read } + unless currentkey == public_key.to_s + raise Puppet::Error, "public keys for %s differ" % hostname + end + else + File.open(pkeyfile, "w", 0644) { |f| + f.print public_key.to_s + } + end + end + end +end + +# $Id$ |
