Fix the OCSP management. Also for the swarm version.
This commit is contained in:
parent
8868333a8d
commit
ef2a73b6c2
|
@ -9,9 +9,11 @@ haproxy_enabled: True
|
||||||
haproxy_loglevel: info
|
haproxy_loglevel: info
|
||||||
haproxy_k_bind_non_local_ip: True
|
haproxy_k_bind_non_local_ip: True
|
||||||
haproxy_docker_container: False
|
haproxy_docker_container: False
|
||||||
haproxy_docker_version: '{{ haproxy_version }}.4'
|
haproxy_docker_version: '{{ haproxy_version }}.6'
|
||||||
haproxy_docker_image: 'haproxytech/haproxy-debian:{{ haproxy_version }}.4'
|
haproxy_docker_image: 'haproxytech/haproxy-debian:{{ haproxy_docker_version }}'
|
||||||
haproxy_docker_compose_dir: /srv/haproxy_swarm
|
haproxy_docker_compose_dir: /srv/haproxy_swarm
|
||||||
|
# Source volume for the socket
|
||||||
|
haproxy_docker_socket_dir: /srv/haproxy_s
|
||||||
haproxy_docker_restart_policy: 'on-failure'
|
haproxy_docker_restart_policy: 'on-failure'
|
||||||
|
|
||||||
haproxy_ha_with_keepalived: False
|
haproxy_ha_with_keepalived: False
|
||||||
|
@ -28,7 +30,9 @@ haproxy_default_port: 80
|
||||||
haproxy_terminate_tls: False
|
haproxy_terminate_tls: False
|
||||||
haproxy_ssl_port: 443
|
haproxy_ssl_port: 443
|
||||||
haproxy_admin_port: 8880
|
haproxy_admin_port: 8880
|
||||||
haproxy_admin_socket: /run/haproxy/admin.sock
|
haproxy_admin_socket_dir: /run/haproxy
|
||||||
|
haproxy_admin_socket_file: admin.sock
|
||||||
|
haproxy_admin_socket: '{{ haproxy_admin_socket_dir }}/{{ haproxy_admin_socket_file }}'
|
||||||
|
|
||||||
haproxy_letsencrypt_managed: True
|
haproxy_letsencrypt_managed: True
|
||||||
haproxy_cert_dir: '{{ pki_dir }}/haproxy'
|
haproxy_cert_dir: '{{ pki_dir }}/haproxy'
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
- name: Create the local haproxy configuration directory
|
- name: Create the local haproxy configuration directory
|
||||||
file: dest=/etc/haproxy state=directory mode='0755'
|
file: dest=/etc/haproxy state=directory mode='0755'
|
||||||
|
|
||||||
|
- name: Create the local directory for the socket volume
|
||||||
|
file: dest={{ haproxy_docker_socket_dir }} state=directory mode='0755'
|
||||||
|
|
||||||
- name: Install a bare haproxy configuration if there's none
|
- name: Install a bare haproxy configuration if there's none
|
||||||
copy: src=haproxy-sample.cfg dest=/etc/haproxy/haproxy.cfg mode='0644' force=no
|
copy: src=haproxy-sample.cfg dest=/etc/haproxy/haproxy.cfg mode='0644' force=no
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
apt: name=socat state=latest update_cache=yes cache_valid_time=3600
|
apt: name=socat state=latest update_cache=yes cache_valid_time=3600
|
||||||
|
|
||||||
- name: Install a script that refreshes the OCSP configuration and reloads haproxy if needed
|
- name: Install a script that refreshes the OCSP configuration and reloads haproxy if needed
|
||||||
template: src=hapos-upd.j2 dest=/usr/local/bin/hapos-upd owner=root group=root mode=0755
|
get_url: url='https://raw.githubusercontent.com/pierky/haproxy-ocsp-stapling-updater/master/hapos-upd' dest=/usr/local/bin/hapos-upd owner=root group=root mode=0755
|
||||||
|
|
||||||
- name: Install a cron job that refreshes the OCSP configuration
|
- name: Install a cron job that refreshes the OCSP configuration
|
||||||
cron:
|
cron:
|
||||||
name: "Refresh the haproxy OCSP information"
|
name: "Refresh the haproxy OCSP information"
|
||||||
user: root
|
user: root
|
||||||
special_time: daily
|
special_time: daily
|
||||||
job: "/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v {{ letsencrypt_acme_certs_dir }}/fullchain -s {{ haproxy_admin_socket }} >/var/log/hapos-upd.log 2>&1"
|
job: "/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v {{ letsencrypt_acme_certs_dir }}/fullchain -s {% if not haproxy_docker_container %}{{ haproxy_admin_socket }}{% else %}{{ haproxy_docker_socket_dir }}/{{ haproxy_admin_socket_file }}{% endif %} -v - >/var/log/hapos-upd.log 2>&1"
|
||||||
|
|
||||||
tags: [ 'haproxy', 'letsencrypt', 'ssl', 'ssl_ocsp' ]
|
tags: [ 'haproxy', 'letsencrypt', 'ssl', 'ssl_ocsp' ]
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
- haproxy_letsencrypt_managed
|
- haproxy_letsencrypt_managed
|
||||||
- letsencrypt_acme_sh_install
|
- letsencrypt_acme_sh_install
|
||||||
- import_tasks: haproxy-ssl.yml
|
- import_tasks: haproxy-ssl.yml
|
||||||
when:
|
when: haproxy_letsencrypt_managed
|
||||||
- haproxy_letsencrypt_managed
|
|
||||||
- not haproxy_docker_container
|
|
||||||
|
|
||||||
- import_tasks: haproxy-nagios.yml
|
- import_tasks: haproxy-nagios.yml
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -1,571 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# HAProxy OCSP Stapling Updater
|
|
||||||
# Copyright (c) 2015 Pier Carlo Chiodi - http://www.pierky.com
|
|
||||||
#
|
|
||||||
# https://github.com/pierky/haproxy-ocsp-stapling-updater
|
|
||||||
|
|
||||||
set -o nounset
|
|
||||||
|
|
||||||
VERSION="0.4.1-pre1"
|
|
||||||
|
|
||||||
PROGNAME="hapos-upd"
|
|
||||||
|
|
||||||
if [ -z ${OPENSSL_BIN+x} ]; then
|
|
||||||
OPENSSL_BIN="openssl"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SOCAT_BIN="socat"
|
|
||||||
|
|
||||||
CERT=""
|
|
||||||
VAFILE=""
|
|
||||||
HAPROXY_ADMIN_SOCKET_DEFAULT="/run/haproxy/admin.sock"
|
|
||||||
HAPROXY_ADMIN_SOCKET="$HAPROXY_ADMIN_SOCKET_DEFAULT"
|
|
||||||
GOOD_ONLY=0
|
|
||||||
SYSLOG_PRIO=""
|
|
||||||
DEBUG=0
|
|
||||||
KEEP_TEMP=0
|
|
||||||
OCSP_URL=""
|
|
||||||
OCSP_HOST=""
|
|
||||||
VERIFY=1
|
|
||||||
TMP=""
|
|
||||||
SKIP_UPDATE=0
|
|
||||||
PARTIAL_CHAIN=""
|
|
||||||
|
|
||||||
function Quit() {
|
|
||||||
if [ $KEEP_TEMP -eq 0 ]; then
|
|
||||||
if [ -n "$TMP" ]; then
|
|
||||||
rm -r $TMP &>/dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
|
|
||||||
function LogError() {
|
|
||||||
MSG="$1"
|
|
||||||
|
|
||||||
if [ -z "$SYSLOG_PRIO" ]; then
|
|
||||||
echo "$MSG" >&2
|
|
||||||
else
|
|
||||||
logger -p "$SYSLOG_PRIO" -s -- "$PROGNAME - $MSG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$MSG" >>$TMP/log
|
|
||||||
}
|
|
||||||
|
|
||||||
function Error() {
|
|
||||||
if [ $1 -eq 9 ]; then
|
|
||||||
MSG="Error: $2"
|
|
||||||
else
|
|
||||||
MSG="Error processing '$CERT': $2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
LogError "$MSG"
|
|
||||||
|
|
||||||
if [ $1 -eq 9 ]; then
|
|
||||||
echo "Run $PROGNAME -h for help" >&2
|
|
||||||
fi
|
|
||||||
|
|
||||||
Quit $1
|
|
||||||
}
|
|
||||||
|
|
||||||
function Debug() {
|
|
||||||
if [ $DEBUG -eq 1 ]; then
|
|
||||||
echo "$1"
|
|
||||||
fi
|
|
||||||
echo "$1" >>$TMP/log
|
|
||||||
}
|
|
||||||
|
|
||||||
function Trap() {
|
|
||||||
Debug "Aborting"
|
|
||||||
Quit 9
|
|
||||||
}
|
|
||||||
|
|
||||||
function Usage() {
|
|
||||||
echo "
|
|
||||||
HAProxy OCSP Stapling Updater - $VERSION
|
|
||||||
Copyright (c) 2015 Pier Carlo Chiodi - http://www.pierky.com
|
|
||||||
|
|
||||||
https://github.com/pierky/haproxy-ocsp-stapling-updater
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
$PROGNAME [options] --cert crt_full_path
|
|
||||||
|
|
||||||
This script extracts and queries the OCSP server present in a
|
|
||||||
certificate to obtain its revocation status, then updates HAProxy by
|
|
||||||
writing the '.issuer' and the '.ocsp' files and by sending it the
|
|
||||||
'set ssl ocsp-response' command through the local UNIX admin socket.
|
|
||||||
|
|
||||||
The crt_full_path argument is the full path to the certificate bundle
|
|
||||||
used in haproxy 'crt' setting. End-entity (EE) certificate plus any
|
|
||||||
intermediate CA certificates must be concatenated there.
|
|
||||||
An OCSP query is sent to the OCSP server given on the command line
|
|
||||||
(--ocsp-url and --ocsp-host argument); if these arguments are missing,
|
|
||||||
URL and Host header values are automatically extracted from the
|
|
||||||
certificate.
|
|
||||||
If the '.issuer' file already exists it's used to build the OCSP
|
|
||||||
request, otherwise the chain is extracted from crt_full_path and used
|
|
||||||
to identify the issuer.
|
|
||||||
Finally, it writes the related '.issuer' and .'ocsp' files and updates
|
|
||||||
haproxy, using 'socat' and the local UNIX socket (--socket argument,
|
|
||||||
default $HAPROXY_ADMIN_SOCKET_DEFAULT).
|
|
||||||
|
|
||||||
Exit codes:
|
|
||||||
0 OK
|
|
||||||
1 openssl certificates handling error
|
|
||||||
2 OCSP server URL not found
|
|
||||||
3 string parsing / PEM manipulation error
|
|
||||||
4 OCSP error
|
|
||||||
5 haproxy management error
|
|
||||||
9 program error (wrong arguments, missing dependencies)
|
|
||||||
|
|
||||||
Options:
|
|
||||||
|
|
||||||
-d, --debug : don't do anything, print debug messages only.
|
|
||||||
|
|
||||||
--keep-temp : keep temporary directory after exiting (for
|
|
||||||
debug purposes).
|
|
||||||
|
|
||||||
-g, --good-only : do not update haproxy if OCSP response
|
|
||||||
certificate status value is not 'good'.
|
|
||||||
|
|
||||||
-l, --syslog priority : log errors to syslog system log module.
|
|
||||||
The priority may be specified numerically
|
|
||||||
or as a facility.level pair (e.g.
|
|
||||||
local7.error).
|
|
||||||
|
|
||||||
--ocsp-url url : OCSP server URL; use this instead of the
|
|
||||||
one in the EE certificate.
|
|
||||||
|
|
||||||
--ocsp-host host : OCSP server hostname to be used in the
|
|
||||||
'Host:' header; use this instead of the one
|
|
||||||
extracted from the OCSP server URL.
|
|
||||||
|
|
||||||
--partial-chain : Allow partial certificate chain if at least one certificate
|
|
||||||
is in trusted store. Useful when validating an intermediate
|
|
||||||
certificate without the root CA.
|
|
||||||
|
|
||||||
-s, --socket file : haproxy admin socket. If omitted,
|
|
||||||
$HAPROXY_ADMIN_SOCKET_DEFAULT is used by default.
|
|
||||||
This script is distributed with only one
|
|
||||||
method to update haproxy: using 'socat'
|
|
||||||
with a local admin-level UNIX socket.
|
|
||||||
Feel free to implement other mechanisms as
|
|
||||||
needed! The right section in the code is
|
|
||||||
\"UPDATE HAPROXY\", at the end of the script.
|
|
||||||
|
|
||||||
-v, --VAfile file : same as the openssl ocsp -VAfile option
|
|
||||||
with 'file' as argument. For more details:
|
|
||||||
'man ocsp'.
|
|
||||||
If file = \"-\" then the chain extracted
|
|
||||||
from the certificate's bundle (or .issuer
|
|
||||||
file) is used (useful for OCSP responses
|
|
||||||
that don't include the signer certificate).
|
|
||||||
|
|
||||||
--noverify : Do not verify OCSP response.
|
|
||||||
|
|
||||||
-S, --skip-update : Do not notify haproxy of the new OCSP response.
|
|
||||||
|
|
||||||
-h, --help : this help."
|
|
||||||
}
|
|
||||||
|
|
||||||
trap Trap INT TERM
|
|
||||||
|
|
||||||
TMP="`mktemp -d -q -t $PROGNAME.XXXXXXXXXX`"
|
|
||||||
|
|
||||||
# COMMAND LINE PROCESSING
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
while [[ $# > 0 ]]
|
|
||||||
do
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
-h|--help)
|
|
||||||
Usage
|
|
||||||
Quit 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
-d|--debug)
|
|
||||||
DEBUG=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
--keep-temp)
|
|
||||||
KEEP_TEMP=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
-g|--good-only)
|
|
||||||
GOOD_ONLY=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
--noverify)
|
|
||||||
VERIFY=0
|
|
||||||
;;
|
|
||||||
|
|
||||||
--partial-chain)
|
|
||||||
PARTIAL_CHAIN="-partial_chain"
|
|
||||||
;;
|
|
||||||
|
|
||||||
-l|--syslog)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
SYSLOG_PRIO="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
--ocsp-url)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
OCSP_URL="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
--ocsp-host)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
OCSP_HOST="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
-c|--cert)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
CERT="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
-v|--VAfile)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
VAFILE="$2"
|
|
||||||
if [ "$VAFILE" == "-" ]; then
|
|
||||||
VAFILE="$TMP/chain.pem"
|
|
||||||
else
|
|
||||||
if [ ! -e "$VAFILE" ]; then
|
|
||||||
Error 9 "VAfile does not exists: $VAFILE"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
-s|--socket)
|
|
||||||
if [ $# -le 1 ]; then
|
|
||||||
Error 9 "mandatory value is missing for $1 argument"
|
|
||||||
fi
|
|
||||||
HAPROXY_ADMIN_SOCKET="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
|
|
||||||
-S|--skip-update)
|
|
||||||
SKIP_UPDATE=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
Error 9 "unknown option: $1"
|
|
||||||
esac
|
|
||||||
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
Debug "Temporary directory: $TMP"
|
|
||||||
|
|
||||||
$OPENSSL_BIN version | grep OpenSSL &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 9 "openssl binary not found; adjust OPENSSL_BIN variable in the script"
|
|
||||||
fi
|
|
||||||
|
|
||||||
$SOCAT_BIN -V | grep socat &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 9 "socat binary not found; adjust SOCAT_BIN variable in the script"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$CERT" ]; then
|
|
||||||
Error 9 "certificate not provided (--cert argument)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# CURRENT RESPONSE EXPIRED?
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
ISNEW=1
|
|
||||||
if [ -e $CERT.ocsp ]; then
|
|
||||||
ISNEW=0
|
|
||||||
Debug "An OCSP response already exists: checking its expiration."
|
|
||||||
|
|
||||||
$OPENSSL_BIN ocsp -respin $CERT.ocsp -text -noverify | \
|
|
||||||
grep "Next Update:" &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
CURR_EXP=`$OPENSSL_BIN ocsp -respin $CERT.ocsp -text -noverify | grep "Next Update:" | cut -d ':' -f 2-`
|
|
||||||
CURR_EXP_EPOCH=`date --date="$CURR_EXP" +%s`
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 3 "can't parse Next Update from current OCSP response"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $CURR_EXP_EPOCH -lt `date +%s` ]; then
|
|
||||||
Debug "Current OCSP response expiration: $CURR_EXP - expired"
|
|
||||||
LogError "current OCSP response is expired: please consider running this script more frequently"
|
|
||||||
else
|
|
||||||
Debug "Current OCSP response expiration: $CURR_EXP - NOT expired"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# EXTRACT EE CERTIFICATE INFO
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
# extract EE certificate
|
|
||||||
$OPENSSL_BIN x509 -in $CERT -outform PEM -out $TMP/ee.pem &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 1 "can't extract EE certificate from $CERT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# get OCSP server URL
|
|
||||||
if [ -z "$OCSP_URL" ]; then
|
|
||||||
OCSP_URL="`$OPENSSL_BIN x509 -in $TMP/ee.pem -ocsp_uri -noout`"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 1 "can't obtain OCSP server URL from $CERT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$OCSP_URL" ]; then
|
|
||||||
Error 2 "OCSP server URL not found in the EE certificate"
|
|
||||||
fi
|
|
||||||
|
|
||||||
Debug "OCSP server URL found: $OCSP_URL"
|
|
||||||
else
|
|
||||||
Debug "Using OCSP server URL from command line: $OCSP_URL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check OCSP server URL format (http:// or https://)
|
|
||||||
echo "$OCSP_URL" | egrep -i "(http://|https://)" &>/dev/null
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 3 "OCSP server URL not in http[s]:// format"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# get OCSP server URL host name
|
|
||||||
if [ -z "$OCSP_HOST" ]; then
|
|
||||||
OCSP_HOST="`echo "$OCSP_URL" | egrep -i "(http://|https://)" | cut -d'/' -f 3`"
|
|
||||||
|
|
||||||
if [ $? -ne 0 -o -z "$OCSP_HOST" ]; then
|
|
||||||
Error 3 "can't extract hostname from OCSP server URL $OCSP_URL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
Debug "OCSP server hostname: $OCSP_HOST"
|
|
||||||
else
|
|
||||||
Debug "Using OCSP server hostname from command line: $OCSP_HOST"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# EXTRACT CHAIN INFO
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
if [ -e $CERT.issuer ]; then
|
|
||||||
Debug "Using existing chain ($CERT.issuer)"
|
|
||||||
|
|
||||||
# copy .issuer file to temporary chain.pem
|
|
||||||
cp $CERT.issuer $TMP/chain.pem &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 3 "can't copy current chain from $CERT.issuer"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
Debug "Extracting chain from certificates bundle"
|
|
||||||
|
|
||||||
# get EE certificate's fingerprint
|
|
||||||
FP_EE="`$OPENSSL_BIN x509 -fingerprint -noout -in $TMP/ee.pem`"
|
|
||||||
|
|
||||||
if [ $? -ne 0 -o -z "$FP_EE" ]; then
|
|
||||||
Error 1 "can't obtain EE certificate's fingerprint"
|
|
||||||
fi
|
|
||||||
|
|
||||||
Debug "EE certificate's fingerprint: $FP_EE"
|
|
||||||
|
|
||||||
# get BEGIN CERTIFICATE and END CERTIFICATE separators
|
|
||||||
PEM_BEGIN_CERT="`head $TMP/ee.pem -n 1`"
|
|
||||||
PEM_END_CERT="`tail $TMP/ee.pem -n 1`"
|
|
||||||
|
|
||||||
# get number of certificates in the bundle file
|
|
||||||
NUM_OF_CERTS=`cat $CERT | grep -e "$PEM_BEGIN_CERT" | wc -l`
|
|
||||||
|
|
||||||
if [ $NUM_OF_CERTS -le 1 ]; then
|
|
||||||
Error 3 "can't obtain the number of certificates in the chain"
|
|
||||||
fi
|
|
||||||
|
|
||||||
Debug "$NUM_OF_CERTS certificates found in the bundle"
|
|
||||||
|
|
||||||
# save each certificate in the bundle into $TMP/chain-X.pem
|
|
||||||
cat $CERT | \
|
|
||||||
sed -n -e "/$PEM_BEGIN_CERT/,/$PEM_END_CERT/p" | \
|
|
||||||
awk "/$PEM_BEGIN_CERT/{x=\"$TMP/chain-\" ++i \".pem\";}{print > x;}" &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 3 "can't extract certificates from bundle"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# for each certificate that is extracted from the bundle check if
|
|
||||||
# it's the EE certificate, otherwise uses it to build the chain file
|
|
||||||
for c in `seq 1 $NUM_OF_CERTS`;
|
|
||||||
do
|
|
||||||
# check fingerprint of current and EE certificates
|
|
||||||
FP="`$OPENSSL_BIN x509 -fingerprint -noout -in $TMP/chain-$c.pem`"
|
|
||||||
if [ $? -ne 0 -o -z "$FP" ]; then
|
|
||||||
Error 1 "can't obtain the fingerprint of the certificate n. $c in the bundle"
|
|
||||||
else
|
|
||||||
if [ ! "$FP" == "$FP_EE" ]; then
|
|
||||||
Debug "Bundle certificate n. $c fingerprint: $FP - it's part of the chain"
|
|
||||||
|
|
||||||
# current certificate is not the same as the EE; append to the chain
|
|
||||||
cat $TMP/chain-$c.pem >> $TMP/chain.pem
|
|
||||||
else
|
|
||||||
Debug "Bundle certificate n. $c fingerprint: $FP - EE certificate"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check if the EE certificate validates against the chain
|
|
||||||
$OPENSSL_BIN verify $PARTIAL_CHAIN -CAfile $TMP/chain.pem $TMP/ee.pem &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
if [ -e $CERT.issuer ]; then
|
|
||||||
Error 1 "can't validate the EE certificate against the existing chain; if it has been changed recently consider removing the current $CERT.issuer file and let this script to figure out a new one"
|
|
||||||
else
|
|
||||||
Error 1 "can't validate the EE certificate against the extracted chain"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# OCSP
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
# query the OCSP server and save its response
|
|
||||||
|
|
||||||
$OPENSSL_BIN version | grep "OpenSSL 1.0" &>/dev/null
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
# OpenSSL 1.0.x
|
|
||||||
|
|
||||||
$OPENSSL_BIN ocsp $PARTIAL_CHAIN -issuer $TMP/chain.pem -cert $TMP/ee.pem \
|
|
||||||
-respout $TMP/ocsp.der -noverify \
|
|
||||||
-no_nonce -url $OCSP_URL -header "Host" "$OCSP_HOST" &>>$TMP/log
|
|
||||||
else
|
|
||||||
$OPENSSL_BIN ocsp $PARTIAL_CHAIN -issuer $TMP/chain.pem -cert $TMP/ee.pem \
|
|
||||||
-respout $TMP/ocsp.der -noverify \
|
|
||||||
-no_nonce -url $OCSP_URL -header "Host=$OCSP_HOST" &>>$TMP/log
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 1 "can't receive the OCSP server response"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# process the OCSP response
|
|
||||||
VERIFYOPT=""
|
|
||||||
if [ $VERIFY -eq 0 ]; then
|
|
||||||
VERIFYOPT="-noverify"
|
|
||||||
fi
|
|
||||||
if [ -z "$VAFILE" ]; then
|
|
||||||
$OPENSSL_BIN ocsp $PARTIAL_CHAIN $VERIFYOPT -issuer $TMP/chain.pem -cert $TMP/ee.pem \
|
|
||||||
-respin $TMP/ocsp.der -no_nonce -CAfile $TMP/chain.pem \
|
|
||||||
-out $TMP/ocsp.txt &>>$TMP/ocsp-verify.txt
|
|
||||||
else
|
|
||||||
$OPENSSL_BIN ocsp $PARTIAL_CHAIN $VERIFYOPT -issuer $TMP/chain.pem -cert $TMP/ee.pem \
|
|
||||||
-respin $TMP/ocsp.der -no_nonce -CAfile $TMP/chain.pem \
|
|
||||||
-VAfile $VAFILE \
|
|
||||||
-out $TMP/ocsp.txt &>>$TMP/ocsp-verify.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 1 "can't receive OCSP response"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $VERIFY -eq 1 ]; then
|
|
||||||
Debug "OCSP response verification results: `cat $TMP/ocsp-verify.txt`"
|
|
||||||
|
|
||||||
cat $TMP/ocsp-verify.txt | grep "Response verify OK" &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
grep "signer certificate not found" $TMP/ocsp-verify.txt &>/dev/null
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
Error 4 "OCSP response verification failure: signer certificate not found; try with '--VAfile -' or '--VAfile OCSP-response-signing-certificate-file' arguments"
|
|
||||||
else
|
|
||||||
Error 4 "OCSP response verification failure."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
Debug "OCSP response: `cat $TMP/ocsp.txt`"
|
|
||||||
|
|
||||||
if [ $GOOD_ONLY -eq 1 ]; then
|
|
||||||
cat $TMP/ocsp.txt | head -n 1 | grep ": good" &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 4 "OCSP response, certificate status not good"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# UPDATE HAPROXY
|
|
||||||
# ----------------------------------
|
|
||||||
|
|
||||||
# Status:
|
|
||||||
# - $TMP/ocsp.der contains the OCSP response, DER format
|
|
||||||
# - $TMP/ocsp.txt contains the textual OCSP response as produced
|
|
||||||
# by openssl
|
|
||||||
# - the OCSP response has been verified against the chain or
|
|
||||||
# the --VAfile
|
|
||||||
|
|
||||||
if [ $DEBUG -eq 0 ]; then
|
|
||||||
# update .ocsp and .issuer files
|
|
||||||
|
|
||||||
cp $TMP/ocsp.der $CERT.ocsp &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 5 "can't update $CERT.ocsp file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -e $CERT.issuer ]; then
|
|
||||||
cp $TMP/chain.pem $CERT.issuer &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 5 "can't update $CERT.issuer file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $SKIP_UPDATE -eq 0 ]; then
|
|
||||||
if [ $ISNEW -eq 1 ]; then
|
|
||||||
# no .ocsp file found, maybe it's an initial run
|
|
||||||
Debug "Reloading haproxy."
|
|
||||||
|
|
||||||
service haproxy reload
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 5 "can't reload haproxy with 'service haproxy reload'"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# update haproxy via local UNIX socket
|
|
||||||
Debug "Updating haproxy."
|
|
||||||
|
|
||||||
echo "set ssl ocsp-response `base64 -w 0 $TMP/ocsp.der`" | $SOCAT_BIN stdio $HAPROXY_ADMIN_SOCKET &>>$TMP/log
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
Error 5 "can't update haproxy ssl ocsp-response using $HAPROXY_ADMIN_SOCKET socket"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
Debug "Not notifying haproxy because skip-update is set."
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
|
||||||
Debug "Debug mode: haproxy update skipped."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# remove temporary files and quit with success
|
|
||||||
Quit 0
|
|
||||||
|
|
||||||
# vim: set tabstop=4 shiftwidth=4 expandtab:
|
|
|
@ -1,4 +1,4 @@
|
||||||
version: '3.2'
|
version: '3.6'
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
{{ haproxy_docker_overlay_network }}:
|
{{ haproxy_docker_overlay_network }}:
|
||||||
|
@ -7,10 +7,12 @@ networks:
|
||||||
services:
|
services:
|
||||||
haproxy:
|
haproxy:
|
||||||
image: {{ haproxy_docker_image }}
|
image: {{ haproxy_docker_image }}
|
||||||
|
entrypoint: ["haproxy", "-sf", "350", "-x", "{{ haproxy_admin_socket }}", "-W", "-db", "-f", "/usr/local/etc/haproxy/haproxy.cfg", "-L", "local_haproxy"]
|
||||||
volumes:
|
volumes:
|
||||||
- {{ haproxy_cert_dir }}:{{ haproxy_cert_dir }}:ro
|
- {{ haproxy_cert_dir }}:{{ haproxy_cert_dir }}:ro
|
||||||
- /etc/haproxy:/usr/local/etc/haproxy:ro
|
- /etc/haproxy:/usr/local/etc/haproxy:ro
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- {{ haproxy_docker_socket_dir }}:{{ haproxy_admin_socket_dir }}
|
||||||
networks:
|
networks:
|
||||||
- {{ haproxy_docker_overlay_network }}
|
- {{ haproxy_docker_overlay_network }}
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -24,34 +24,34 @@ else
|
||||||
echo "No letsencrypt default file" >> $LE_LOG_DIR/haproxy.log
|
echo "No letsencrypt default file" >> $LE_LOG_DIR/haproxy.log
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
haproxy_socket={% if not haproxy_docker_container %}{{ haproxy_admin_socket }}{% else %}{{ haproxy_docker_socket_dir }}/{{ haproxy_admin_socket_file }}{% endif %}
|
||||||
|
|
||||||
echo "Building the new certificate file" >> $LE_LOG_DIR/haproxy.log
|
echo "Building the new certificate file" >> $LE_LOG_DIR/haproxy.log
|
||||||
cat ${LE_CERTS_DIR}/{fullchain,privkey} > ${HAPROXY_CERTFILE}
|
cat ${LE_CERTS_DIR}/{fullchain,privkey} > ${HAPROXY_CERTFILE}
|
||||||
chmod 440 ${HAPROXY_CERTFILE}
|
chmod 440 ${HAPROXY_CERTFILE}
|
||||||
chgrp haproxy ${HAPROXY_CERTFILE}
|
chgrp haproxy ${HAPROXY_CERTFILE}
|
||||||
|
|
||||||
{% if not haproxy_docker_container %}
|
# Run the OCSP stapling script
|
||||||
|
if [ -x /usr/local/bin/hapos-upd ] ; then
|
||||||
|
upd_retval=
|
||||||
|
echo "Run the OCSP stapling updater script" >> $LE_LOG_DIR/haproxy.log
|
||||||
|
/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v ${LE_CERTS_DIR}/fullchain -s $haproxy_socket -v - >> $LE_LOG_DIR/haproxy.log 2>&1
|
||||||
|
upd_retval=$?
|
||||||
|
if [ $upd_retval -ne 0 ] ; then
|
||||||
|
rm -f ${HAPROXY_CERTFILE}.issuer
|
||||||
|
/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v ${LE_CERTS_DIR}/fullchain -s $haproxy_socket -v - >> $LE_LOG_DIR/haproxy.log 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "No OCPS stapling updater script" >> $LE_LOG_DIR/haproxy.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
{% if not haproxy_docker_container %}
|
||||||
echo "Reload the haproxy service" >> $LE_LOG_DIR/haproxy.log
|
echo "Reload the haproxy service" >> $LE_LOG_DIR/haproxy.log
|
||||||
if [ -x /bin/systemctl ] ; then
|
if [ -x /bin/systemctl ] ; then
|
||||||
systemctl reload haproxy >> $LE_LOG_DIR/haproxy.log 2>&1
|
systemctl reload haproxy >> $LE_LOG_DIR/haproxy.log 2>&1
|
||||||
else
|
else
|
||||||
service haproxy reload >> $LE_LOG_DIR/haproxy.log 2>&1
|
service haproxy reload >> $LE_LOG_DIR/haproxy.log 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run the OCSP stapling script
|
|
||||||
if [ -x /usr/local/bin/hapos-upd ] ; then
|
|
||||||
upd_retval=
|
|
||||||
echo "Run the OCSP stapling updater script" >> $LE_LOG_DIR/haproxy.log
|
|
||||||
/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v ${LE_CERTS_DIR}/fullchain -s {{ haproxy_admin_socket }} -v - >> $LE_LOG_DIR/haproxy.log 2>&1
|
|
||||||
upd_retval=$?
|
|
||||||
if [ $upd_retval -ne 0 ] ; then
|
|
||||||
rm -f ${HAPROXY_CERTFILE}.issuer
|
|
||||||
/usr/local/bin/hapos-upd --cert {{ haproxy_cert_dir }}/haproxy.pem -v ${LE_CERTS_DIR}/fullchain -s {{ haproxy_admin_socket }} -v - >> $LE_LOG_DIR/haproxy.log 2>&1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "No OCPS stapling updater script" >> $LE_LOG_DIR/haproxy.log
|
|
||||||
fi
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
docker kill --signal USR2 $(docker container ls --filter name=haproxy_haproxy --quiet)
|
docker kill --signal USR2 $(docker container ls --filter name=haproxy_haproxy --quiet)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in New Issue