diff options
| author | Luke Kanies <luke@madstop.com> | 2005-08-23 16:55:24 +0000 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2005-08-23 16:55:24 +0000 |
| commit | f68fe0045d3519d545d8e63b7ee470ece74fcc3f (patch) | |
| tree | b945d424aa203553d44e82c220724eb374074c47 /lib/puppet/server/ca.rb | |
| parent | 129dad73edf2307a36f88c563a347417f75bcc12 (diff) | |
| download | puppet-f68fe0045d3519d545d8e63b7ee470ece74fcc3f.tar.gz puppet-f68fe0045d3519d545d8e63b7ee470ece74fcc3f.tar.xz puppet-f68fe0045d3519d545d8e63b7ee470ece74fcc3f.zip | |
moving all server handlers into a specific server subdirectory
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@579 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/server/ca.rb')
| -rw-r--r-- | lib/puppet/server/ca.rb | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/lib/puppet/server/ca.rb b/lib/puppet/server/ca.rb new file mode 100644 index 000000000..65074c3f6 --- /dev/null +++ b/lib/puppet/server/ca.rb @@ -0,0 +1,159 @@ +require 'openssl' +require 'puppet' +require 'puppet/sslcertificates' +require 'xmlrpc/server' + +# Much of this was taken from QuickCert: +# http://segment7.net/projects/ruby/QuickCert/ + +module Puppet +class Server + class CAError < Puppet::Error; end + class CA + attr_reader :ca + + def self.interface + XMLRPC::Service::Interface.new("puppetca") { |iface| + iface.add_method("array getcert(csr)") + } + end + + Puppet::Server.addhandler(:CA, self) + + def autosign?(hostname) + # simple values are easy + asign = Puppet[:autosign] + if asign == true or asign == false + return asign + end + + # we only otherwise know how to handle files + unless asign =~ /^\// + raise Puppet::Error, "Invalid autosign value %s" % + asign + end + + unless FileTest.exists?(asign) + Puppet.warning "Autosign is enabled but %s is missing" % asign + return false + end + File.open(asign) { |f| + f.each { |line| + line.chomp! + if line =~ /^[.\w-]+$/ and line == hostname + Puppet.info "%s exactly matched %s" % [hostname, line] + return true + else + begin + rx = Regexp.new(line) + rescue => detail + Puppet.err( + "Could not create regexp out of autosign line %s: %s" % + [line, detail] + ) + next + end + + if hostname =~ rx + Puppet.info "%s matched %s" % [hostname, line] + return true + end + end + } + } + + return false + end + + def initialize(hash = {}) + @ca = Puppet::SSLCertificates::CA.new() + end + + # our client sends us a csr, and we either store it for later signing, + # or we sign it right away + def getcert(csrtext, request = nil) + # okay, i need to retrieve the hostname from the csr, and then + # verify that i get the same hostname through reverse lookup or + # something + + Puppet.info "Someone's trying for a cert" + csr = OpenSSL::X509::Request.new(csrtext) + + subject = csr.subject + + nameary = subject.to_a.find { |ary| + ary[0] == "CN" + } + + if nameary.nil? + Puppet.err "Invalid certificate request" + return "invalid" + end + + hostname = nameary[1] + + unless @ca + Puppet.notice "Host %s asked for signing from non-CA master" % hostname + return "" + end + + # okay, we're now going to store the public key if we don't already + # have it + public_key = csr.public_key + unless FileTest.directory?(Puppet[:publickeydir]) + Puppet.recmkdir(Puppet[:publickeydir]) + end + 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 + unless FileTest.directory?(Puppet[:certdir]) + Puppet.recmkdir(Puppet[:certdir], 0770) + end + certfile = File.join(Puppet[:certdir], [hostname, "pem"].join(".")) + + #puts hostname + #puts certfile + + unless FileTest.directory?(Puppet[:csrdir]) + Puppet.recmkdir(Puppet[:csrdir], 0770) + end + # 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) + # 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.info "Storing certificate request for %s" % hostname + @ca.storeclientcsr(csr) + end + return ["", ""] + end + else + raise "huh?" + end + end + end +end +end |
