summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/defaults.rb7
-rw-r--r--lib/puppet/indirector/certificate/file.rb1
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/ca_file.rb8
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/file.rb8
-rw-r--r--lib/puppet/indirector/key/file.rb8
-rw-r--r--lib/puppet/indirector/ssl_file.rb82
-rw-r--r--lib/puppet/ssl/certificate_revocation_list.rb50
-rw-r--r--lib/puppet/ssl/host.rb28
8 files changed, 139 insertions, 53 deletions
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 300f9bad4..7b206901c 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -183,7 +183,7 @@ module Puppet
},
:hostcsr => { :default => "$ssldir/csr_$certname.pem",
:mode => 0644,
- :desc => "Where individual hosts store and look for their certificates."
+ :desc => "Where individual hosts store and look for their certificate requests."
},
:hostcert => { :default => "$certdir/$certname.pem",
:mode => 0644,
@@ -200,6 +200,11 @@ module Puppet
:localcacert => { :default => "$certdir/ca.pem",
:mode => 0644,
:desc => "Where each client stores the CA certificate."
+ },
+ :hostcrl => { :default => "$ssldir/crl.pem",
+ :mode => 0644,
+ :desc => "Where the host's certificate revocation list can be found.
+ This is distinct from the certificate authority's CRL."
}
)
diff --git a/lib/puppet/indirector/certificate/file.rb b/lib/puppet/indirector/certificate/file.rb
index 9e2e8ed99..5f4ade051 100644
--- a/lib/puppet/indirector/certificate/file.rb
+++ b/lib/puppet/indirector/certificate/file.rb
@@ -5,4 +5,5 @@ class Puppet::SSL::Certificate::File < Puppet::Indirector::SslFile
desc "Manage SSL certificates on disk."
store_in :certdir
+ store_ca_at :cacert
end
diff --git a/lib/puppet/indirector/certificate_revocation_list/ca_file.rb b/lib/puppet/indirector/certificate_revocation_list/ca_file.rb
new file mode 100644
index 000000000..d29a5ce3b
--- /dev/null
+++ b/lib/puppet/indirector/certificate_revocation_list/ca_file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::CaFile < Puppet::Indirector::SslFile
+ desc "Manage the CA collection of certificate requests on disk."
+
+ store_at :cacrl
+end
diff --git a/lib/puppet/indirector/certificate_revocation_list/file.rb b/lib/puppet/indirector/certificate_revocation_list/file.rb
new file mode 100644
index 000000000..037aa6b8c
--- /dev/null
+++ b/lib/puppet/indirector/certificate_revocation_list/file.rb
@@ -0,0 +1,8 @@
+require 'puppet/indirector/ssl_file'
+require 'puppet/ssl/certificate_revocation_list'
+
+class Puppet::SSL::CertificateRevocationList::File < Puppet::Indirector::SslFile
+ desc "Manage the global certificate revocation list."
+
+ store_at :hostcrl
+end
diff --git a/lib/puppet/indirector/key/file.rb b/lib/puppet/indirector/key/file.rb
index 41d30a2d4..4536f8aa7 100644
--- a/lib/puppet/indirector/key/file.rb
+++ b/lib/puppet/indirector/key/file.rb
@@ -5,9 +5,15 @@ class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
desc "Manage SSL private and public keys on disk."
store_in :privatekeydir
+ store_ca_at :cakey
+ # Where should we store the public key?
def public_key_path(name)
- File.join(Puppet[:publickeydir], name.to_s + ".pem")
+ if ca?(name)
+ Puppet[:capub]
+ else
+ File.join(Puppet[:publickeydir], name.to_s + ".pem")
+ end
end
# Remove the public key, in addition to the private key
diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb
index eddf82ac5..582d282ff 100644
--- a/lib/puppet/indirector/ssl_file.rb
+++ b/lib/puppet/indirector/ssl_file.rb
@@ -1,27 +1,67 @@
require 'puppet/indirector/file'
+require 'puppet/ssl/host'
class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
+ # Specify the directory in which multiple files are stored.
def self.store_in(setting)
@directory_setting = setting
end
+ # Specify a single file location for storing just one file.
+ # This is used for things like the CRL.
+ def self.store_at(setting)
+ @file_setting = setting
+ end
+
+ # Specify where a specific ca file should be stored.
+ def self.store_ca_at(setting)
+ @ca_setting = setting
+ end
+
class << self
- attr_reader :directory_setting
+ attr_reader :directory_setting, :file_setting, :ca_setting
end
# The full path to where we should store our files.
def self.collection_directory
- raise(Puppet::DevError, "No setting defined for %s" % self) unless @directory_setting
- Puppet.settings[@directory_setting]
+ return nil unless directory_setting
+ Puppet.settings[directory_setting]
+ end
+
+ # The full path to an individual file we would be managing.
+ def self.file_location
+ return nil unless file_setting
+ Puppet.settings[file_setting]
+ end
+
+ # The full path to a ca file we would be managing.
+ def self.ca_location
+ return nil unless ca_setting
+ Puppet.settings[ca_setting]
+ end
+
+ # We assume that all files named 'ca' are pointing to individual ca files,
+ # rather than normal host files. It's a bit hackish, but all the other
+ # solutions seemed even more hackish.
+ def ca?(name)
+ name == Puppet::SSL::Host.ca_name
end
def initialize
Puppet.settings.use(:ssl)
+
+ (collection_directory || file_location) or raise Puppet::DevError, "No file or directory setting provided; terminus %s cannot function" % self.class.name
end
# Use a setting to determine our path.
def path(name)
- File.join(collection_directory, name.to_s + ".pem")
+ if ca?(name) and ca_location
+ ca_location
+ elsif collection_directory
+ File.join(collection_directory, name.to_s + ".pem")
+ else
+ file_location
+ end
end
# Remove our file.
@@ -53,13 +93,9 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
dir = File.dirname(path)
raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [request.key, dir]) unless FileTest.directory?(dir)
- raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [request.key, dir]) unless FileTest.writable?(dir)
+ raise Puppet::Error.new("Cannot save %s; parent directory %s is not writable" % [request.key, dir]) unless FileTest.writable?(dir)
- begin
- File.open(path, "w") { |f| f.print request.instance.to_s }
- rescue => detail
- raise Puppet::Error, "Could not write %s: %s" % [request.key, detail]
- end
+ write(request.key, path) { |f| f.print request.instance.to_s }
end
# Search for more than one file. At this point, it just returns
@@ -76,8 +112,32 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
private
- # A demeterish pointer to the collection directory.
+ # Demeterish pointers to class info.
def collection_directory
self.class.collection_directory
end
+
+ def file_location
+ self.class.file_location
+ end
+
+ def ca_location
+ self.class.ca_location
+ end
+
+ # Yield a filehandle set up appropriately, either with our settings doing
+ # the work or opening a filehandle manually.
+ def write(name, path)
+ if ca?(name) and ca_location
+ Puppet.settings.write(self.class.ca_setting) { |f| yield f }
+ elsif file_location
+ Puppet.settings.write(self.class.file_setting) { |f| yield f }
+ else
+ begin
+ File.open(path, "w") { |f| yield f }
+ rescue => detail
+ raise Puppet::Error, "Could not write %s: %s" % [path, detail]
+ end
+ end
+ end
end
diff --git a/lib/puppet/ssl/certificate_revocation_list.rb b/lib/puppet/ssl/certificate_revocation_list.rb
index e892e276a..939b48443 100644
--- a/lib/puppet/ssl/certificate_revocation_list.rb
+++ b/lib/puppet/ssl/certificate_revocation_list.rb
@@ -1,12 +1,16 @@
require 'puppet/ssl/base'
+require 'puppet/indirector'
# Manage the CRL.
class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
wraps OpenSSL::X509::CRL
+ extend Puppet::Indirector
+ indirects :certificate_revocation_list
+
# Knows how to create a CRL with our system defaults.
- def generate(cert, key)
- Puppet.info "Creating a new SSL key for %s" % name
+ def generate(cert)
+ Puppet.info "Creating a new certificate revocation list"
@content = wrapped_class.new
@content.issuer = cert.subject
@content.version = 1
@@ -14,29 +18,19 @@ class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
@content
end
- def initialize(name, cert, key)
+ def initialize
raise Puppet::Error, "Cannot manage the CRL when :cacrl is set to false" if [false, "false"].include?(Puppet[:cacrl])
- @name = name
-
- read_or_generate(cert, key)
- end
-
- # A stupid indirection method to make this easier to test. Yay.
- def read_or_generate(cert, key)
- unless read(Puppet[:cacrl])
- generate(cert, key)
- save(key)
- end
+ @name = "crl"
end
# Revoke the certificate with serial number SERIAL issued by this
- # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
- def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
- if @config[:cacrl] == 'false'
- raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'false'"
- end
+ # CA, then write the CRL back to disk. The REASON must be one of the
+ # OpenSSL::OCSP::REVOKED_* reasons
+ def revoke(serial, cakey, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
time = Time.now
+
+ # Add our revocation to the CRL.
revoked = OpenSSL::X509::Revoked.new
revoked.serial = serial
revoked.time = time
@@ -44,13 +38,7 @@ class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
ext = OpenSSL::X509::Extension.new("CRLReason", enum)
revoked.add_extension(ext)
@content.add_revoked(revoked)
- store_crl
- end
- # Save the CRL to disk. Note that none of the other Base subclasses
- # have this method, because they all use the indirector to find and save
- # the CRL.
- def save(key)
# Increment the crlNumber
e = @content.extensions.find { |e| e.oid == 'crlNumber' }
ext = @content.extensions.reject { |e| e.oid == 'crlNumber' }
@@ -59,14 +47,12 @@ class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
@content.extensions = ext
# Set last/next update
- now = Time.now
- @content.last_update = now
+ @content.last_update = time
# Keep CRL valid for 5 years
- @content.next_update = now + 5 * 365*24*60*60
+ @content.next_update = time + 5 * 365*24*60*60
+
+ @content.sign(cakey, OpenSSL::Digest::SHA1.new)
- sign_with_key(@content)
- Puppet.settings.write(:cacrl) do |f|
- f.puts @content.to_pem
- end
+ save
end
end
diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb
index 6f49175aa..dbd885316 100644
--- a/lib/puppet/ssl/host.rb
+++ b/lib/puppet/ssl/host.rb
@@ -15,7 +15,15 @@ class Puppet::SSL::Host
extend Puppet::Util::ConstantInflector
attr_reader :name
- attr_accessor :ca
+ attr_accessor :ca, :password_file
+
+ CA_NAME = "ca"
+
+ # This is the constant that people will use to mark that a given host is
+ # a certificate authority.
+ def self.ca_name
+ CA_NAME
+ end
# Search for more than one host, optionally only specifying
# an interest in hosts with a given file type.
@@ -36,6 +44,11 @@ class Puppet::SSL::Host
end
end
+ # Is this a ca host, meaning that all of its files go in the CA location?
+ def ca?
+ ca
+ end
+
def key
return nil unless (defined?(@key) and @key) or @key = Key.find(name)
@key.content
@@ -45,8 +58,12 @@ class Puppet::SSL::Host
# with no inputs.
def generate_key
@key = Key.new(name)
+
+ # If a password file is set, then the key will be stored
+ # encrypted by the password.
+ @key.password_file = password_file if password_file
@key.generate
- @key.save :in => :file
+ @key.save
true
end
@@ -60,7 +77,7 @@ class Puppet::SSL::Host
generate_key unless key
@certificate_request = CertificateRequest.new(name)
@certificate_request.generate(key)
- @certificate_request.save :in => :file
+ @certificate_request.save
return true
end
@@ -71,11 +88,6 @@ class Puppet::SSL::Host
@certificate.content
end
- # Is this a ca host, meaning that all of its files go in the CA collections?
- def ca?
- ca
- end
-
# Remove all traces of this ssl host
def destroy
[key, certificate, certificate_request].each do |instance|