Commit d3e6ba68 authored by Paul Cammish's avatar Paul Cammish
Browse files

Fix for #249

parent 0131350e
......@@ -14,13 +14,12 @@ Depends: lsb-base (>= 3.0-6),
ruby | ruby-interpreter, ruby-json-jwt, ruby-password, ruby-diffy,
ruby-erubis, ruby-mocha, ruby-webmock, ruby-test-unit, ruby-faraday,
python, python-apt, gnutls-bin, gcc, libpam-tmpdir, wbritish | wordlist,
libpam-cracklib, ${misc:Depends}
libpam-cracklib, dnsutils, ${misc:Depends}
Recommends: sympl-backup, sympl-cron, sympl-mail, sympl-firewall,
sympl-ftp, sympl-web, sympl-monit, sympl-mysql, sympl-phpmyadmin,
sympl-dns, sympl-webmail, sympl-updater,
openssh-server, nano, vim, htop, strace, wget, curl, iotop, less, lsof,
psmisc, rsync, screen, smartmontools, telnet, mtr-tiny, xfsprogs, tree,
dnsutils
psmisc, rsync, screen, smartmontools, telnet, mtr-tiny, xfsprogs, tree
Provides: bytemark-symbiosis, sympl-common
Conflicts: bytemark-symbiosis
Replaces: bytemark-symbiosis, sympl-common
......
#!/usr/bin/ruby
#
# NAME
# sympl-ssl - Manage and generate SSL certificates
#
# SYNOPSIS
# sympl-ssl [ --threshold days ] [ --no-generate ] [ --no-rollover ] [ --select set ]
# [ --list ] [ --prefix prefix ] [ --verbose ] [ --debug ] [ --manual ] [ --help ]
# [ domain domain ... ]
#
# OPTIONS
# --force Re-generate certificates, and roll over to the new set even
# if they're not due to be renewed. Implies --verbose.
#
# --threshold days Number of days before expiry that certificates should be renewed. Defaults to 21.
#
# --select set Select a specific set for a single domain. A domain must be specified.
#
# --list List available SSL certificate sets for a domain.
#
# --no-generate Do not try and generate keys or certificates.
#
# --no-rollover Do not try and generate keys or certificates.
#
# --prefix prefix Set the directory prefix for sympl. Defaults to /srv.
#
# --help Show the help information for this script.
#
# --manual Show the manual for this script
#
# --verbose Show verbose information.
#
# --debug Show debugging information.
#
# USAGE
#
# This command is used to manage certificate sets automatically for domains on
# a Sympl system. It can request certificates from LetsEncrypt or generate
# self-signed ones (see PROVIDERS).
#
# In addition, if any domain's certificate set was altered, hooks are run (see
# HOOKS).
#
# PROVIDERS
#
# Currently two providers are supported, namely LetsEncrypt and SelfSigned. A
# domain can be set up to use either provider by setting a file
# /srv/example.com/config/ssl-provider with the name of the desired provider in
# it.
#
# If the provider is set to something else (e.g. CertificateProviderDuJour)
# then no certificates will be generated, but it is possible to manage updating
# certificates with this program.
#
# HOOKS
#
# Hooks are executed from the /etc/sympl/ssl-hooks.d directory, given the
# following conditions:
#
# * The file is executable
# * The file's name is made up only of alphanumerics, underscore (_) and hyphen
# (-)
#
# At present, only one event causes the hooks to be executed. If any domain's
# certificate set is altered by sympl-ssl, at the end of the process all
# the hooks are called with 'live-update' passed as their only command-line
# argument and the list of domains that were altered is written to standard
# input, one per line.
#
# AUTHOR
# Patrick J. Cherry <patrick@bytemark.co.uk>
#
#
# Modules we require
#
require 'English'
require 'getoptlong'
opts = GetoptLong.new(
['--help', '-h', GetoptLong::NO_ARGUMENT],
['--manual', '-m', GetoptLong::NO_ARGUMENT],
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
['--debug', '-d', GetoptLong::NO_ARGUMENT],
['--force', '-f', GetoptLong::NO_ARGUMENT],
['--list', '-l', GetoptLong::NO_ARGUMENT],
['--threshold', '-t', GetoptLong::REQUIRED_ARGUMENT],
['--no-generate', '-G', GetoptLong::NO_ARGUMENT],
['--no-rollover', '-R', GetoptLong::NO_ARGUMENT],
['--select', '-s', GetoptLong::REQUIRED_ARGUMENT],
['--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT],
['--etc-dir', '-r', GetoptLong::REQUIRED_ARGUMENT]
)
manual = help = false
$VERBOSELOCAL = false
$DEBUG = false
prefix = '/srv'
do_list = do_generate = do_rollover = nil
rollover_to = nil
threshold = 21
etc_dir = '/etc'
opts.each do |opt,arg|
case opt
when '--no-generate'
do_generate = false
when '--no-rollover'
do_rollover = false
when '--select'
rollover_to = arg.to_s
when '--force'
do_generate = do_rollover = true
$VERBOSELOCAL = true
when '--threshold'
begin
threshold = Integer(arg)
rescue ArgumentError
warn "** Could not parse #{arg.inspect} as an integer for --threshold"
end
when '--help'
help = true
when '--manual'
manual = true
when '--prefix'
prefix = arg
when '--etc-dir'
etc_dir = arg
when '--list'
do_list = true
when '--verbose'
$VERBOSELOCAL = true
when '--debug'
$DEBUG = true
end
end
#
# Output help as required.
#
if help || manual
require 'symbiosis/utils'
Symbiosis::Utils.show_help(__FILE__) if help
Symbiosis::Utils.show_manual(__FILE__) if manual
exit 0
end
require 'symbiosis'
require 'symbiosis/domains'
require 'symbiosis/domain/ssl'
require 'symbiosis/ssl'
require 'symbiosis/ssl/letsencrypt'
require 'symbiosis/ssl/selfsigned'
Symbiosis.etc = etc_dir
domains = []
ARGV.each do |arg|
domain = Symbiosis::Domains.find(arg.to_s, prefix)
if domain.nil?
warn "** Unable to find/parse domain #{arg.inspect}"
next
end
domains << domain
end
if rollover_to && ARGV.length != 1
warn '** Exactly one domain must be specfied when rolling over to a specific set.'
exit 1
end
domains = Symbiosis::Domains.all(prefix) if ARGV.empty?
exit_code = 0
%w[INT TERM].each do |sig|
trap(sig) do
if Process.uid.zero?
Process.euid = 0
Process.egid = 0
end
exit 1
end
end
now = Time.now
domains_altered = []
domains.sort_by(&:name).each do |domain|
if do_list || rollover_to
puts "Certificate sets for #{domain}:"
if domain.ssl_available_sets.empty?
puts "\t** No sets found\n\n"
next
end
domain.ssl_available_sets.each do |this_set|
if this_set.certificate.issuer == this_set.certificate.subject
puts "\tSSL set #{this_set.name}: self-signed for #{this_set.certificate.issuer}, expires #{this_set.certificate.not_after}"
else
puts "\tSSL set #{this_set.name}: signed by #{this_set.certificate.issuer}, expires #{this_set.certificate.not_after}"
end
end
current = domain.ssl_current_set
puts "\tCurrent SSL set: #{current.name}\n" unless $VERBOSELOCAL
next if rollover_to.nil?
to_set = domain.ssl_available_sets.find { |s| s.name.to_s == rollover_to }
if to_set.nil?
puts "\tThere is no set '#{rollover_to}' available for this domain."
next
end
if to_set == current
puts "\tNo need to change to set #{to_set.name} as this is already current."
next
end
puts "\tRolling over from set #{current.name} to #{to_set.name}"
domain.ssl_rollover(to_set)
puts "\tCurrent SSL set now: #{domain.ssl_current_set.name}\n"
next
end
begin
rollover_performed = domain.ssl_magic(threshold, do_generate, do_rollover, now)
domains_altered.push domain.name if rollover_performed
rescue StandardError => err
puts "\t!! Failed: #{err.to_s.gsub($RS, '')}" if $VERBOSELOCAL
puts err.backtrace.join("\n") if $DEBUG
exit_code = 1
end
end
success = Symbiosis::SSL::Hooks.run! 'live-update', domains_altered
exit_code = 2 unless success
exit exit_code
#!/bin/bash -e
# Workaround rapper script for sympl-ssl to fix a bug in IPv6 only resolution of the LE API DNS.
# If theres no IPv4 address assigned...
if [ $( sympl-ip -a | grep -c '\.' ) == 0 ]; then
if [[ $@ == *'--verbose'* ]]; then echo 'Applying IPv6 only workaround...'; fi
# Do a DNS lookup for acme-v01.api.letsencrypt.org...
ipv6=$( dig -t AAAA acme-v01.api.letsencrypt.org +short | grep ':' | head -n 1 )
# ... and add it to /etc/hosts
echo -e "$ipv6\facme-v01.api.letsencrypt.org # sympl-ssl workaround" >> /etc/hosts
# run sympl-ssl with all the parameters passed
/usr/sbin/sympl-ssl.rb $@
# and then remove the line from /etc/hosts
sed -i -n '/# sympl-ssl workaround/!p' /etc/hosts
if [[ $@ == *'--verbose'* ]]; then echo 'Removed IPv6 only workaround'; fi
else
# Just run it nomally...
/usr/sbin/sympl-ssl.rb $@
fi
#!/usr/bin/ruby
#
# NAME
# sympl-ssl - Manage and generate SSL certificates
#
# SYNOPSIS
# sympl-ssl [ --threshold days ] [ --no-generate ] [ --no-rollover ] [ --select set ]
# [ --list ] [ --prefix prefix ] [ --verbose ] [ --debug ] [ --manual ] [ --help ]
# [ domain domain ... ]
#
# OPTIONS
# --force Re-generate certificates, and roll over to the new set even
# if they're not due to be renewed. Implies --verbose.
#
# --threshold days Number of days before expiry that certificates should be renewed. Defaults to 21.
#
# --select set Select a specific set for a single domain. A domain must be specified.
#
# --list List available SSL certificate sets for a domain.
#
# --no-generate Do not try and generate keys or certificates.
#
# --no-rollover Do not try and generate keys or certificates.
#
# --prefix prefix Set the directory prefix for sympl. Defaults to /srv.
#
# --help Show the help information for this script.
#
# --manual Show the manual for this script
#
# --verbose Show verbose information.
#
# --debug Show debugging information.
#
# USAGE
#
# This command is used to manage certificate sets automatically for domains on
# a Sympl system. It can request certificates from LetsEncrypt or generate
# self-signed ones (see PROVIDERS).
#
# In addition, if any domain's certificate set was altered, hooks are run (see
# HOOKS).
#
# PROVIDERS
#
# Currently two providers are supported, namely LetsEncrypt and SelfSigned. A
# domain can be set up to use either provider by setting a file
# /srv/example.com/config/ssl-provider with the name of the desired provider in
# it.
#
# If the provider is set to something else (e.g. CertificateProviderDuJour)
# then no certificates will be generated, but it is possible to manage updating
# certificates with this program.
#
# HOOKS
#
# Hooks are executed from the /etc/sympl/ssl-hooks.d directory, given the
# following conditions:
#
# * The file is executable
# * The file's name is made up only of alphanumerics, underscore (_) and hyphen
# (-)
#
# At present, only one event causes the hooks to be executed. If any domain's
# certificate set is altered by sympl-ssl, at the end of the process all
# the hooks are called with 'live-update' passed as their only command-line
# argument and the list of domains that were altered is written to standard
# input, one per line.
#
# AUTHOR
# Patrick J. Cherry <patrick@bytemark.co.uk>
#
#
# Modules we require
#
require 'English'
require 'getoptlong'
opts = GetoptLong.new(
['--help', '-h', GetoptLong::NO_ARGUMENT],
['--manual', '-m', GetoptLong::NO_ARGUMENT],
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
['--debug', '-d', GetoptLong::NO_ARGUMENT],
['--force', '-f', GetoptLong::NO_ARGUMENT],
['--list', '-l', GetoptLong::NO_ARGUMENT],
['--threshold', '-t', GetoptLong::REQUIRED_ARGUMENT],
['--no-generate', '-G', GetoptLong::NO_ARGUMENT],
['--no-rollover', '-R', GetoptLong::NO_ARGUMENT],
['--select', '-s', GetoptLong::REQUIRED_ARGUMENT],
['--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT],
['--etc-dir', '-r', GetoptLong::REQUIRED_ARGUMENT]
)
manual = help = false
$VERBOSELOCAL = false
$DEBUG = false
prefix = '/srv'
do_list = do_generate = do_rollover = nil
rollover_to = nil
threshold = 21
etc_dir = '/etc'
opts.each do |opt,arg|
case opt
when '--no-generate'
do_generate = false
when '--no-rollover'
do_rollover = false
when '--select'
rollover_to = arg.to_s
when '--force'
do_generate = do_rollover = true
$VERBOSELOCAL = true
when '--threshold'
begin
threshold = Integer(arg)
rescue ArgumentError
warn "** Could not parse #{arg.inspect} as an integer for --threshold"
end
when '--help'
help = true
when '--manual'
manual = true
when '--prefix'
prefix = arg
when '--etc-dir'
etc_dir = arg
when '--list'
do_list = true
when '--verbose'
$VERBOSELOCAL = true
when '--debug'
$DEBUG = true
end
end
#
# Output help as required.
#
if help || manual
require 'symbiosis/utils'
Symbiosis::Utils.show_help(__FILE__) if help
Symbiosis::Utils.show_manual(__FILE__) if manual
exit 0
end
require 'symbiosis'
require 'symbiosis/domains'
require 'symbiosis/domain/ssl'
require 'symbiosis/ssl'
require 'symbiosis/ssl/letsencrypt'
require 'symbiosis/ssl/selfsigned'
Symbiosis.etc = etc_dir
domains = []
ARGV.each do |arg|
domain = Symbiosis::Domains.find(arg.to_s, prefix)
if domain.nil?
warn "** Unable to find/parse domain #{arg.inspect}"
next
end
domains << domain
end
if rollover_to && ARGV.length != 1
warn '** Exactly one domain must be specfied when rolling over to a specific set.'
exit 1
end
domains = Symbiosis::Domains.all(prefix) if ARGV.empty?
exit_code = 0
%w[INT TERM].each do |sig|
trap(sig) do
if Process.uid.zero?
Process.euid = 0
Process.egid = 0
end
exit 1
end
end
now = Time.now
domains_altered = []
domains.sort_by(&:name).each do |domain|
if do_list || rollover_to
puts "Certificate sets for #{domain}:"
if domain.ssl_available_sets.empty?
puts "\t** No sets found\n\n"
next
end
domain.ssl_available_sets.each do |this_set|
if this_set.certificate.issuer == this_set.certificate.subject
puts "\tSSL set #{this_set.name}: self-signed for #{this_set.certificate.issuer}, expires #{this_set.certificate.not_after}"
else
puts "\tSSL set #{this_set.name}: signed by #{this_set.certificate.issuer}, expires #{this_set.certificate.not_after}"
end
end
current = domain.ssl_current_set
puts "\tCurrent SSL set: #{current.name}\n" unless $VERBOSELOCAL
next if rollover_to.nil?
to_set = domain.ssl_available_sets.find { |s| s.name.to_s == rollover_to }
if to_set.nil?
puts "\tThere is no set '#{rollover_to}' available for this domain."
next
end
if to_set == current
puts "\tNo need to change to set #{to_set.name} as this is already current."
next
end
puts "\tRolling over from set #{current.name} to #{to_set.name}"
domain.ssl_rollover(to_set)
puts "\tCurrent SSL set now: #{domain.ssl_current_set.name}\n"
next
end
begin
rollover_performed = domain.ssl_magic(threshold, do_generate, do_rollover, now)
domains_altered.push domain.name if rollover_performed
rescue StandardError => err
puts "\t!! Failed: #{err.to_s.gsub($RS, '')}" if $VERBOSELOCAL
puts err.backtrace.join("\n") if $DEBUG
exit_code = 1
end
end
success = Symbiosis::SSL::Hooks.run! 'live-update', domains_altered
exit_code = 2 unless success
exit exit_code
Markdown is supported
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