mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-10-26 22:20:59 +01:00
ADMIN: haproxy-dump-certs: implement a certificate dumper
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.
This commit is contained in:
parent
b70c7f48fa
commit
3a6ea8b959
198
admin/cli/haproxy-dump-certs
Executable file
198
admin/cli/haproxy-dump-certs
Executable file
@ -0,0 +1,198 @@
|
|||||||
|
#!/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 "$@"
|
||||||
Loading…
x
Reference in New Issue
Block a user