Commit ddc32981 authored by Patrick J Cherry's avatar Patrick J Cherry
Browse files

common: Refactored how --force works and when certs get generated/rolled over

The defaults are as follows:

* If the current set is available

** If it is due to expire inside the threshold

*** generate a new set if there is no set more recent (unless instructed
otherwise)
*** roll over to the new set if one has been generated (unless
instructed not to)

** Otherwise

*** do not generate a new set (unless instructed otherwise)
*** do not roll over (unless instructed to)

* If the "current" set is missing, but other sets are available

** If the most recent set is due to expire inside the threshold

*** generate a new set (unless instructed otherwise)
*** roll over to the new set if one has been generated (unless
instructed not to)

** If the most recent set is not due to expire soon

*** do not generate a new set (unless instructed otherwise)
*** roll over to the latest set (unless instructed not to)

* If there are no certificate sets

** generate a new one (unless instructed otherwise)
** roll over to the new set if one has been generate (unless instructed
not to)
parent 22b602b3
......@@ -8,7 +8,8 @@
# [ --help ] [ DOMAIN DOMAIN ...]
#
# OPTIONS
# --force Re-generate certificates even if they're not due to be renewed.
# --force Re-generate certificates, and roll over to the new set even
# if they're not due to be renewed.
#
# --threshold N Number days before expiry that certificates should be renewed. Defaults to 10.
#
......@@ -48,9 +49,8 @@ opts = GetoptLong.new(
manual = help = false
$VERBOSE = false
prefix = "/srv"
do_generate = do_rollover = true
do_generate = do_rollover = nil
threshold = 10
force = false
opts.each do |opt,arg|
case opt
......@@ -59,7 +59,7 @@ opts.each do |opt,arg|
when '--no-rollover'
do_rollover = false
when '--force'
force = true
do_generate = do_rollover = true
when '--threshold'
begin
threshold = Integer(arg)
......@@ -141,7 +141,7 @@ now = Time.now
domains.each do |domain|
begin
domain.ssl_magic(threshold, do_generate, do_rollover, force, now)
domain.ssl_magic(threshold, do_generate, do_rollover, now)
rescue StandardError => err
puts "\t!! Failed: #{err.to_s.gsub($/,'')}" if $VERBOSE
puts err.backtrace.join("\n") if $DEBUG
......
......@@ -307,10 +307,15 @@ module Symbiosis
# set of certificates discovered by #ssl_available_sets. This returns true
# if a rollover was performed, or false otherwise.
#
def ssl_rollover
@ssl_available_sets = []
def ssl_rollover(to_set = nil)
current = self.ssl_current_set
latest = self.ssl_available_sets.last
if to_set.is_a?(Symbiosis::SSL::CertificateSet)
latest = to_set
else
@ssl_available_sets = []
latest = self.ssl_available_sets.last
end
if latest.nil? or !File.directory?(latest.directory)
warn "\tNo valid sets of certificates found." if $VERBOSE
......@@ -371,32 +376,72 @@ module Symbiosis
# * generation
# * rollover
#
def ssl_magic(threshold = 14, do_generate = true, do_rollover = true, force = false, now = Time.now)
def ssl_magic(threshold = 14, do_generate = nil, do_rollover = nil, now = Time.now)
puts "* Examining certificates for #{self.name}" if $VERBOSE
#
# Stage 0: verify and check expiriy
#
set = self.ssl_current_set
set = self.ssl_available_sets.last unless set.is_a?(Symbiosis::SSL::CertificateSet)
current_set = self.ssl_current_set
latest_set = self.ssl_available_sets.last
current_set_expires_in = ((current_set.certificate.not_after - now)/86400.0).round if current_set.is_a?(Symbiosis::SSL::CertificateSet)
latest_set_expires_in = ((latest_set.certificate.not_after - now)/86400.0).round if latest_set.is_a?(Symbiosis::SSL::CertificateSet)
if current_set.is_a?(Symbiosis::SSL::CertificateSet)
#
# If our current set is not due to expire, do nothing.
#
# Otherwise we should generate a new certificate if there is no other
# set with an expiry date further into the future.
#
if current_set_expires_in > threshold
do_generate = false if do_generate.nil?
else
puts "\tThe current certificate expires in #{current_set_expires_in} days." if $VERBOSE
do_generate = (!latest_set_expires_in or latest_set_expires_in <= current_set_expires_in) if do_generate.nil?
end
expires_in = nil
if set.is_a?(Symbiosis::SSL::CertificateSet)
expires_in = ((set.certificate.not_after - now)/86400.0).round
if expires_in < threshold
puts "\tThe certificate is due to expire in #{expires_in} days" if $VERBOSE
elsif latest_set.is_a?(Symbiosis::SSL::CertificateSet)
#
# If there is no current certificate set, but there is another set
# avaialable, and it is not due to expire soon, then don't generate,
# but do roll over.
#
# Otherwise generate a new certificate.
#
if latest_set_expires_in > threshold
do_generate = false if do_generate.nil?
do_rollover = true if do_rollover.nil?
else
puts "\tThe latest available certificate expires in #{latest_set_expires_in} days." if $VERBOSE
do_generate = true if do_generate.nil?
end
else
puts "\tNo valid certificate sets found." if $VERBOSE
do_generate = true if do_generate.nil?
end
#
# If we generate a new set, always roll over to it, unless told
# otherwise.
#
do_rollover = do_generate if do_rollover.nil?
#
# Stage 1: Generate
#
if do_generate and (set.nil? or (expires_in.is_a?(Integer) and expires_in < threshold) or force)
cert_set = nil
if do_generate
#
# If ssl-provision has been disabled, move on.
#
......@@ -439,10 +484,10 @@ module Symbiosis
#
# Stage 2: Roll over
#
if do_rollover and self.ssl_rollover
return true
if do_rollover
return self.ssl_rollover(cert_set)
else
return !do_rollover
return false
end
end
......
......@@ -436,13 +436,13 @@ module Symbiosis
# including any bundle that has been uploaded.
#
if store.verify(certificate)
puts "\tSSL set #{name}: Signed by \"#{certificate.issuer.to_s}\" for #{@domain.name}" if $DEBUG
puts "\tSSL set #{name}: Signed by \"#{certificate.issuer.to_s}\" for #{@domain.name}, expires #{certificate.not_after}" if $DEBUG
elsif store.error == 18
unless certificate.verify(key)
raise OpenSSL::X509::CertificateError, "\tSSL set #{name}: Self signed, but the signature doesn't validate."
end
puts "\tSSL set #{name}: Self-signed certificate for #{@domain.name}." if $DEBUG
puts "\tSSL set #{name}: Self-signed certificate for #{@domain.name}, expires #{certificate.not_after}.." if $DEBUG
else
msg = "Not valid for #{@domain.name} -- "
case store.error
......
......@@ -708,11 +708,10 @@ class SSLTest < Test::Unit::TestCase
request = OpenSSL::X509::Request.new
key, cert = do_generate_key_and_crt(@domain.name, {:ca_key => ca_key, :ca_cert => ca_cert})
#
# Set up our dummy provider
#
Symbiosis::SSL::Dummy.any_instance.stubs(:verify_and_request_certificate!).returns(true)
Symbiosis::SSL::Dummy.any_instance.stubs(:verify_and_request_certificate!).returns(request)
Symbiosis::SSL::Dummy.any_instance.stubs(:register).returns(true)
Symbiosis::SSL::Dummy.any_instance.stubs(:registered?).returns(false)
Symbiosis::SSL::Dummy.any_instance.stubs(:key).returns(key)
......@@ -913,20 +912,17 @@ class SSLTest < Test::Unit::TestCase
assert_nothing_raised{ result = @domain.ssl_magic(500) }
#
# Now test a forced roll-over
# Now test a forced roll-over. First make sure nothing happens with force
# set to false.
#
current_cert = @domain.ssl_certificate
@domain.ssl_magic(14,true,true,false)
#
# Make sure nothing happens with force set to false.
#
@domain.ssl_magic(14)
assert_equal(current_cert.to_pem, @domain.ssl_certificate.to_pem, "Existing certificate replaced, even with force off")
#
# And do it again, this time set the flag to true. It should regenerate it.
#
@domain.ssl_magic(14,true,true,true)
@domain.ssl_magic(15,true,true)
assert(current_cert.to_pem != @domain.ssl_certificate.to_pem, "Certificate not replaced with force on")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment