diff options
Diffstat (limited to 'lib/puppet')
-rw-r--r-- | lib/puppet/client.rb | 120 | ||||
-rwxr-xr-x | lib/puppet/daemon.rb | 132 | ||||
-rwxr-xr-x | lib/puppet/sslcertificates.rb | 100 |
3 files changed, 229 insertions, 123 deletions
diff --git a/lib/puppet/client.rb b/lib/puppet/client.rb index 39c3aa65b..4b2c57232 100644 --- a/lib/puppet/client.rb +++ b/lib/puppet/client.rb @@ -32,21 +32,40 @@ module Puppet class NetworkClient < XMLRPC::Client #include Puppet::Daemon - @@methods = [ :getconfig, :getcert ] - - @@methods.each { |method| - self.send(:define_method,method) { |*args| - begin - call("puppetmaster.%s" % method.to_s,*args) - rescue XMLRPC::FaultException => detail - Puppet.err "XML Could not call %s: %s" % - [method, detail.faultString] - raise NetworkClientError.new, - "XMLRPC Error: %s" % detail.faultString - rescue => detail - Puppet.err "Could not call %s: %s" % [method, detail.inspect] - raise NetworkClientError.new(detail.to_s) - end + @@methods = { + "puppetmaster" => [ :getconfig ], + "puppetca" => [ :getcert ] + } + + @@methods.each { |namespace, methods| + methods.each { |method| + self.send(:define_method,method) { |*args| + Puppet.info "peer cert is %s" % @http.peer_cert + #Puppet.info "cert is %s" % @http.cert + begin + call("%s.%s" % [namespace, method.to_s],*args) + rescue XMLRPC::FaultException => detail + Puppet.err "XML Could not call %s.%s: %s" % + [namespace, method, detail.faultString] + raise NetworkClientError.new, + "XMLRPC Error: %s" % detail.faultString + rescue => detail + Puppet.err "Could not call %s.%s: %s" % + [namespace, method, detail.inspect] + raise NetworkClientError.new(detail.to_s) + end + } + } + } + + [:key, :cert, :ca_file].each { |method| + setmethod = method.to_s + "=" + #self.send(:define_method, method) { + # @http.send(method) + #} + self.send(:define_method, setmethod) { |*args| + Puppet.debug "Setting %s" % method + @http.send(setmethod, *args) } } @@ -54,6 +73,7 @@ module Puppet hash[:Path] ||= "/RPC2" hash[:Server] ||= "localhost" hash[:Port] ||= Puppet[:masterport] + super( hash[:Server], hash[:Path], @@ -62,7 +82,29 @@ module Puppet nil, # proxy_port nil, # user nil, # password - true) # use_ssl + true # use_ssl + ) + + if hash[:Certificate] + Puppet.info "adding cert to @http" + @http.cert = hash[:Certificate] + end + + if hash[:Key] + @http.key = hash[:Key] + end + + if hash[:CAFile] + @http.ca_file = hash[:CAFile] + store = OpenSSL::X509::Store.new + cacert = OpenSSL::X509::Certificate.new( + File.read(hash[:CAFile]) + ) + store.add_cert(cacert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + @http.cert_store = store + @http.verify_mode = OpenSSL::SSL::VERIFY_NONE + end # from here, i need to add the key, cert, and ca cert # and reorgize how i start the client @@ -88,6 +130,14 @@ module Puppet # to whom do we connect? @server = nil @nil = nil + @secureinit = hash[:NoSecureInit] || true + + if hash.include?(:FQDN) + @fqdn = hash[:FQDN] + else + self.fqdn + end + if hash.include?(:Server) case hash[:Server] when String: @@ -102,6 +152,13 @@ module Puppet args[arg] = hash[arg] end } + + if self.readcert + args[:Certificate] = @cert + args[:Key] = @key + args[:CAFile] = @cacertfile + end + @driver = Puppet::NetworkClient.new(args) @local = false when Puppet::Master: @@ -114,14 +171,6 @@ module Puppet else raise ClientError.new("Must pass :Server to client") end - - if hash.include?(:FQDN) - @fqdn = hash[:FQDN] - else - self.fqdn - end - - @secureinit = hash[:NoSecureInit] || true end def getconfig @@ -202,11 +251,11 @@ module Puppet end end - container = tree.to_type + container = @objects.to_type #if @local - # container = tree.to_type + # container = @objects.to_type #else - # container = Marshal::load(tree).to_type + # container = Marshal::load(@objects).to_type #end # this is a gross hack... but i don't see a good way around it @@ -231,6 +280,23 @@ module Puppet return transaction #self.shutdown end + + def initcerts + unless self.readcert + unless self.requestcert + return nil + end + end + + unless @driver + return true + end + + Puppet.info "setting cert and key and such" + @driver.cert = @cert + @driver.key = @key + @driver.ca_file = @cacertfile + end end #--------------------------------------------------------------- end diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb index 8bebea832..1cbb35ce5 100755 --- a/lib/puppet/daemon.rb +++ b/lib/puppet/daemon.rb @@ -54,17 +54,44 @@ module Puppet return log end - def initcerts + def readcert return unless @secureinit # verify we've got all of the certs set up and such + if defined? @cert and defined? @key and @cert and @key + return true + end + # we are not going to encrypt our key, but we need at a minimum # a keyfile and a certfile - certfile = File.join(Puppet[:certdir], [@fqdn, "pem"].join(".")) - cacertfile = File.join(Puppet[:certdir], ["ca", "pem"].join(".")) - keyfile = File.join(Puppet[:privatekeydir], [@fqdn, "pem"].join(".")) - publickeyfile = File.join(Puppet[:publickeydir], [@fqdn, "pem"].join(".")) + @certfile = File.join(Puppet[:certdir], [@fqdn, "pem"].join(".")) + @cacertfile = File.join(Puppet[:certdir], ["ca", "pem"].join(".")) + @keyfile = File.join(Puppet[:privatekeydir], [@fqdn, "pem"].join(".")) + @publickeyfile = File.join(Puppet[:publickeydir], [@fqdn, "pem"].join(".")) + if File.exists?(@keyfile) + # load the key + @key = OpenSSL::PKey::RSA.new(File.read(@keyfile)) + else + return false + end + + if File.exists?(@certfile) + if File.exists?(@cacertfile) + @cacert = OpenSSL::X509::Certificate.new(File.read(@cacertfile)) + else + raise Puppet::Error, "Found cert file with no ca cert file" + end + @cert = OpenSSL::X509::Certificate.new(File.read(@certfile)) + else + return false + end + return true + end + + def requestcert + retrieved = false + # create the directories involved [Puppet[:certdir], Puppet[:privatekeydir], Puppet[:csrdir], Puppet[:publickeydir]].each { |dir| unless FileTest.exists?(dir) @@ -72,69 +99,62 @@ module Puppet end } - inited = false - if File.exists?(keyfile) - # load the key - @key = OpenSSL::PKey::RSA.new(File.read(keyfile)) - else + if self.readcert + Puppet.info "Certificate already exists; not requesting" + return true + end + + unless defined? @key and @key # create a new one and store it - Puppet.info "Creating a new SSL key at %s" % keyfile + Puppet.info "Creating a new SSL key at %s" % @keyfile @key = OpenSSL::PKey::RSA.new(Puppet[:keylength]) - File.open(keyfile, "w", 0660) { |f| f.print @key.to_pem } - File.open(publickeyfile, "w", 0660) { |f| + File.open(@keyfile, "w", 0660) { |f| f.print @key.to_pem } + File.open(@publickeyfile, "w", 0660) { |f| f.print @key.public_key.to_pem } end - if File.exists?(certfile) - unless File.exists?(cacertfile) - raise Puppet::Error, "Found cert file with no ca cert file" - end - @cert = OpenSSL::X509::Certificate.new(File.read(certfile)) - inited = true - else - unless defined? @driver - Puppet.err "Cannot request a certificate without a defined target" - return false - end - Puppet.info "Creating a new certificate request for %s" % @fqdn - name = OpenSSL::X509::Name.new([["CN", @fqdn]]) - - @csr = OpenSSL::X509::Request.new - @csr.version = 0 - @csr.subject = name - @csr.public_key = @key.public_key - @csr.sign(@key, OpenSSL::Digest::MD5.new) - - Puppet.info "Requesting certificate" - - begin - cert, cacert = @driver.getcert(@csr.to_pem) - rescue => detail - raise Puppet::Error.new("Certificate retrieval failed: %s" % - detail) - end + unless defined? @driver + Puppet.err "Cannot request a certificate without a defined target" + return false + end + Puppet.info "Creating a new certificate request for %s" % @fqdn + name = OpenSSL::X509::Name.new([["CN", @fqdn]]) - if cert.nil? or cert == "" - return nil - end - File.open(certfile, "w", 0660) { |f| f.print cert } - File.open(cacertfile, "w", 0660) { |f| f.print cacert } - begin - @cert = OpenSSL::X509::Certificate.new(cert) - @cacert = OpenSSL::X509::Certificate.new(cacert) - inited = true - rescue => detail - raise Puppet::Error.new( - "Invalid certificate: %s" % detail - ) - end + @csr = OpenSSL::X509::Request.new + @csr.version = 0 + @csr.subject = name + @csr.public_key = @key.public_key + @csr.sign(@key, OpenSSL::Digest::MD5.new) + + Puppet.info "Requesting certificate" + + begin + cert, cacert = @driver.getcert(@csr.to_pem) + rescue => detail + raise Puppet::Error.new("Certificate retrieval failed: %s" % + detail) + end + + if cert.nil? or cert == "" + return nil + end + File.open(@certfile, "w", 0660) { |f| f.print cert } + File.open(@cacertfile, "w", 0660) { |f| f.print cacert } + begin + @cert = OpenSSL::X509::Certificate.new(cert) + @cacert = OpenSSL::X509::Certificate.new(cacert) + retrieved = true + rescue => detail + raise Puppet::Error.new( + "Invalid certificate: %s" % detail + ) end unless @cert.check_private_key(@key) raise Puppet::DevError, "Received invalid certificate" end - return inited + return retrieved end end end diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index 1ccade1d8..b8a4d27aa 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -56,6 +56,7 @@ module SSLCertificates if hash[:issuer] cert.issuer = hash[:issuer].subject else + # we're a self-signed cert cert.issuer = cert.subject end cert.not_before = from @@ -139,6 +140,36 @@ module SSLCertificates return cert end + def self.mkhash(dir, cert, certfile) + hash = "%x" % cert.issuer.hash + hashpath = nil + 10.times { |i| + path = File.join(dir, "%s.%s" % [hash, i]) + if FileTest.exists?(path) + if FileTest.symlink?(path) + dest = File.readlink(path) + if dest == certfile + # the correct link already exists + hashpath = path + break + else + next + end + else + next + end + end + + File.symlink(certfile, path) + + hashpath = path + break + } + + return hashpath + end + + class CA attr_accessor :keyfile, :file, :config, :dir, :cert @@ -425,7 +456,7 @@ module SSLCertificates class Certificate attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type - attr_accessor :key, :cert, :csr + attr_accessor :key, :cert, :csr, :cacert @@params2names = { :name => "CN", @@ -492,6 +523,8 @@ module SSLCertificates @certfile = File.join(@dir, @name) end + @cacertfile ||= File.join(Puppet[:certdir], "ca.pem") + unless FileTest.directory?(@dir) Puppet::SSLCertificates.mkdir(@dir) end @@ -581,36 +614,6 @@ module SSLCertificates return @csr end - def mkhash - hash = "%x" % @cert.issuer.hash - path = nil - 10.times { |i| - path = File.join(@dir, "%s.%s" % [hash, i]) - if FileTest.exists?(path) - if FileTest.symlink?(path) - dest = File.readlink(path) - if dest == @certfile - # the correct link already exists - puts "hash already exists" - @hash = path - return - else - next - end - else - next - end - end - - File.symlink(@certfile, path) - - @hash = path - break - } - - return path - end - def mkkey # @key is the file @@ -665,6 +668,8 @@ module SSLCertificates ) @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign + + return @cert end def subject(string = false) @@ -683,29 +688,44 @@ module SSLCertificates end end + # verify that we can track down the cert chain or whatever + def verify + "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem" + end + def write files = { @certfile => @cert, @keyfile => @key, } - #@csrfile => @csr + if defined? @cacert + files[@cacertfile] = @cacert + end files.each { |file,thing| if defined? thing and thing if FileTest.exists?(file) - newtext = File.open(file) { |f| f.read } - if newtext != thing.to_pem - raise "Cannot replace existing %s" % thing.class - else - next - end + next + end + + text = nil + + if thing.is_a?(OpenSSL::PKey::RSA) and @password + text = thing.export( + OpenSSL::Cipher::DES.new(:EDE3, :CBC), + @password + ) + else + text = thing.to_pem end - File.open(file, "w", 0660) { |f| f.print thing.to_pem } + File.open(file, "w", 0660) { |f| f.print text } end } - self.mkhash + if defined? @cacert + SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) + end end end end |