mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-10-26 14:10:59 +01:00
haproxy-dump0-certs is a bash script that connects to your master socket or your stat socket in order to dump certificates from haproxy memory to the corresponding files.
199 lines
4.7 KiB
Bash
Executable File
199 lines
4.7 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Dump certificates from the HAProxy stats or master socket to the filesystem
|
|
# Experimental script
|
|
#
|
|
|
|
set -e
|
|
|
|
export BASEPATH=${BASEPATH:-/etc/haproxy}/
|
|
export SOCKET=${SOCKET:-/var/run/haproxy-master.sock}
|
|
export DRY_RUN=0
|
|
export DEBUG=
|
|
export VERBOSE=
|
|
export M="@1 "
|
|
|
|
vecho() {
|
|
|
|
[ -n "$VERBOSE" ] && echo "$@"
|
|
return 0
|
|
}
|
|
|
|
read_certificate() {
|
|
name=$1
|
|
crt_filename=
|
|
key_filename=
|
|
|
|
OFS=$IFS
|
|
IFS=":"
|
|
|
|
while read -r key value; do
|
|
case "$key" in
|
|
"Crt filename")
|
|
crt_filename="${value# }"
|
|
key_filename="${value# }"
|
|
;;
|
|
"Key filename")
|
|
key_filename="${value# }"
|
|
;;
|
|
esac
|
|
done < <(echo "${M}show ssl cert ${name}" | socat "${SOCKET}" -)
|
|
IFS=$OFS
|
|
|
|
if [ -z "$crt_filename" ] || [ -z "$key_filename" ]; then
|
|
echo "error: can't dump \"$name\", crt/key filename details not found in \"show ssl cert\"" >&2
|
|
return 1
|
|
fi
|
|
|
|
# handle fields without a crt-base/key-base
|
|
[ "${crt_filename:0:1}" != "/" ] && crt_filename="${BASEPATH}${crt_filename}"
|
|
[ "${key_filename:0:1}" != "/" ] && key_filename="${BASEPATH}${key_filename}"
|
|
|
|
vecho "name:$name"
|
|
vecho "crt:$crt_filename"
|
|
vecho "key:$key_filename"
|
|
|
|
export NAME="$name"
|
|
export CRT_FILENAME="$crt_filename"
|
|
export KEY_FILENAME="$key_filename"
|
|
|
|
return 0
|
|
}
|
|
|
|
dump_certificate() {
|
|
name=$1
|
|
crt_filename=$2
|
|
key_filename=$3
|
|
|
|
tmp="tmp.${RANDOM}"
|
|
d="old.$(date +%s)"
|
|
|
|
if ! touch "${crt_filename}.${tmp}" || ! touch "${key_filename}.${tmp}"; then
|
|
echo "error: can't dump \"$name\", can't create tmp files" >&2
|
|
return 1
|
|
fi
|
|
|
|
echo "${M}dump ssl cert ${name}" | socat "${SOCKET}" - | openssl pkey >> "${key_filename}.${tmp}"
|
|
# use crl2pkcs7 as a way to dump multiple x509, storeutl could be used in modern versions of openssl
|
|
echo "${M}dump ssl cert ${name}" | socat "${SOCKET}" - | openssl crl2pkcs7 -nocrl -certfile /dev/stdin | openssl pkcs7 -print_certs >> "${crt_filename}.${tmp}"
|
|
|
|
if ! cmp -s <(openssl x509 -in "${crt_filename}.${tmp}" -pubkey -noout) <(openssl pkey -in "${key_filename}.${tmp}" -pubout); then
|
|
echo "Error: Private key \"${key_filename}.${tmp}\" and public key \"${crt_filename}.${tmp}\" don't match" >&2
|
|
return 1
|
|
fi
|
|
|
|
# move the current certificates to ".old.timestamp"
|
|
mv "${crt_filename}" "${crt_filename}.${d}"
|
|
[ "${crt_filename}" != "${key_filename}" ] && mv "${key_filename}" "${key_filename}.${d}"
|
|
|
|
mv "${crt_filename}.${tmp}" "${crt_filename}"
|
|
[ "${crt_filename}" != "${key_filename}" ] && mv "${key_filename}.${tmp}" "${key_filename}"
|
|
|
|
return 0
|
|
}
|
|
|
|
dump_all_certificates() {
|
|
echo "${M}show ssl cert" | socat "${SOCKET}" - | grep -v '^#' | grep -v '^$' | while read -r line; do
|
|
export NAME
|
|
export CRT_FILENAME
|
|
export KEY_FILENAME
|
|
|
|
if read_certificate "$line"; then
|
|
[ "${DRY_RUN}" = "0" ] && dump_certificate "$NAME" "$CRT_FILENAME" "$KEY_FILENAME"
|
|
fi
|
|
done
|
|
}
|
|
|
|
usage() {
|
|
echo "Usage:"
|
|
echo " $0 [options]* [cert]*"
|
|
echo ""
|
|
echo " Dump certificates from the HAProxy stats or master socket to the filesystem"
|
|
echo " Require socat and openssl"
|
|
echo " EXPERIMENTAL script, backup your files!"
|
|
echo " The script will move your previous files to FILE.old.unixtimestamp (ex: foo.com.pem.old.1759044998)"
|
|
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -S, --master-socket <path> Use the master socket at <path> (default: ${SOCKET})"
|
|
echo " -s, --socket <path> Use the stats socket at <path>"
|
|
echo " -p, --path <path> Specifiy a base path for relative files (default: ${BASEPATH})"
|
|
echo " -n, --dry-run Read certificates on the socket but don't dump them"
|
|
echo " -d, --debug Debug mode, set -x"
|
|
echo " -v, --verbose Verbose mode"
|
|
echo " -h, --help This help"
|
|
echo " -- End of options"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 -v -p ${BASEPATH} -S ${SOCKET}"
|
|
echo " $0 -v -p ${BASEPATH} -S ${SOCKET} bar.com.rsa.pem"
|
|
echo " $0 -v -p ${BASEPATH} -S ${SOCKET} -- foo.com.ecdsa.pem bar.com.rsa.pem"
|
|
}
|
|
|
|
main() {
|
|
while [ -n "$1" ]; do
|
|
case "$1" in
|
|
-S|--master-socket)
|
|
SOCKET="$2"
|
|
M="@1 "
|
|
shift 2
|
|
;;
|
|
-s|--socket)
|
|
SOCKET="$2"
|
|
M=
|
|
shift 2
|
|
;;
|
|
-p|--path)
|
|
BASEPATH="$2"
|
|
shift 2
|
|
;;
|
|
-n|--dry-run)
|
|
DRY_RUN=1
|
|
shift
|
|
;;
|
|
-d|--debug)
|
|
DEBUG=1
|
|
shift
|
|
;;
|
|
-v|--verbose)
|
|
VERBOSE=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage "$@"
|
|
exit 0
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
-*)
|
|
echo "error: Unknown option '$1'" >&2
|
|
usage "$@"
|
|
exit 1
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -n "$DEBUG" ]; then
|
|
set -x
|
|
fi
|
|
|
|
|
|
if [ -z "$1" ]; then
|
|
dump_all_certificates
|
|
else
|
|
# compute the certificates names at the end of the command
|
|
while [ -n "$1" ]; do
|
|
read_certificate "$1"
|
|
[ "${DRY_RUN}" = "0" ] && dump_certificate "$NAME" "$CRT_FILENAME" "$KEY_FILENAME"
|
|
shift
|
|
done
|
|
fi
|
|
}
|
|
|
|
main "$@"
|