1
0
Fork 0

Address review comments.

This commit is contained in:
Timo Reimann 2017-06-23 00:49:05 +02:00 committed by Ludovic Fernandez
parent 927003329e
commit ceec81011b

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# Copyright (c) 2017 Brian 'redbeard' Harrington <redbeard@dead-city.org> # Copyright (c) 2017 Brian 'redbeard' Harrington <redbeard@dead-city.org>
# #
# dumpcerts.sh - A simple utility to explode a Traefik acme.json file into a # dumpcerts.sh - A simple utility to explode a Traefik acme.json file into a
@ -36,58 +36,68 @@
# 4 - The destination certificate directory does not exist # 4 - The destination certificate directory does not exist
# 8 - Missing private key # 8 - Missing private key
USAGE="dumpcerts.sh <path to acme> <destination cert directory>" set -o errexit
set -o pipefail
set -o nounset
USAGE="$(basename "$0") <path to acme> <destination cert directory>"
# Allow us to exit on a missing jq binary # Allow us to exit on a missing jq binary
exitJQ() { exit_jq() {
echo "" echo "
echo "You must have the binary 'jq' to use this." You must have the binary 'jq' to use this.
echo "jq is available at: https://stedolan.github.io/jq/download/" jq is available at: https://stedolan.github.io/jq/download/
echo ""
echo ${USAGE} ${USAGE}" >&2
exit 1 exit 1
} }
bad_acme() {
echo "
There was a problem parsing your acme.json file.
badACME() { ${USAGE}" >&2
echo ""
echo "There was a problem parsing your acme.json file."
echo ""
echo ${USAGE}
exit 2 exit 2
} }
if [ $# -ne 2 ]; then
echo "
Insufficient number of parameters.
acme="${1}" ${USAGE}" >&2
certdir="${2}"
if [ ! -r "${acme}" ]; then
echo ""
echo "There was a problem reading from '${acme}'"
echo "We need to read this file to explode the JSON bundle... exiting."
echo ""
echo ${USAGE}
exit 1 exit 1
fi
readonly acmefile="${1}"
readonly certdir="${2%/}"
if [ ! -r "${acmefile}" ]; then
echo "
There was a problem reading from '${acmefile}'
We need to read this file to explode the JSON bundle... exiting.
${USAGE}" >&2
exit 2
fi fi
if [ ! -d "${certdir}" ]; then if [ ! -d "${certdir}" ]; then
echo "" echo "
echo "Path ${certdir} does not seem to be a directory" Path ${certdir} does not seem to be a directory
echo "We need a directory in which to explode the JSON bundle... exiting." We need a directory in which to explode the JSON bundle... exiting.
echo ""
echo ${USAGE} ${USAGE}" >&2
exit 4 exit 4
fi fi
jq=$(which jq) || exitJQ jq=$(command -v jq) || exit_jq
priv=$(${jq} -r '.PrivateKey' ${acme}) || badACME priv=$(${jq} -e -r '.PrivateKey' "${acmefile}") || bad_acme
if [ ! -n "${priv}" ]; then if [ ! -n "${priv}" ]; then
echo "" echo "
echo "There didn't seem to be a private key in ${acme}." There didn't seem to be a private key in ${acmefile}.
echo "Please ensure that there is a key in this file and try again." Please ensure that there is a key in this file and try again." >&2
exit 8 exit 8
fi fi
@ -95,16 +105,18 @@ fi
# and place each in a variable for later use, normalizing the path # and place each in a variable for later use, normalizing the path
mkdir -p "${certdir}"/{certs,private} mkdir -p "${certdir}"/{certs,private}
pdir=$(realpath "${certdir}/private/") pdir="${certdir}/private/"
cdir=$(realpath "${certdir}/certs/") cdir="${certdir}/certs/"
# Save the existing umask, change the default mode to 600, then # Save the existing umask, change the default mode to 600, then
# after writing the private key switch it back to the default # after writing the private key switch it back to the default
oldumask=$(umask) oldumask=$(umask)
umask 177 umask 177
# For some reason traefik stores the private key in stripped base64 format, but trap 'umask ${oldumask}' EXIT
# the certificates bundled as a base64 object without stripping headers. This
# normalizes the headers and formatting. # traefik stores the private key in stripped base64 format but the certificates
# bundled as a base64 object without stripping headers. This normalizes the
# headers and formatting.
# #
# In testing this out it was a balance between the following mechanisms: # In testing this out it was a balance between the following mechanisms:
# gawk: # gawk:
@ -126,16 +138,14 @@ umask 177
# key if it does not parse out correctly. The other mechanisms were left as # key if it does not parse out correctly. The other mechanisms were left as
# comments so that the user can choose the mechanism most appropriate to them. # comments so that the user can choose the mechanism most appropriate to them.
echo -e "-----BEGIN RSA PRIVATE KEY-----\n${priv}\n-----END RSA PRIVATE KEY-----" \ echo -e "-----BEGIN RSA PRIVATE KEY-----\n${priv}\n-----END RSA PRIVATE KEY-----" \
| openssl rsa -inform pem -out "${pdir}/letsencrypt.key" | openssl rsa -inform pem -out "${pdir}/letsencrypt.key"
umask ${oldumask}
# Process the certificates for each of the domains in acme.json # Process the certificates for each of the domains in acme.json
for domain in $(jq -r '.DomainsCertificate.Certs[].Certificate.Domain' acme.json); do for domain in $(jq -r '.DomainsCertificate.Certs[].Certificate.Domain' acme.json); do
# Traefik stores a cert bundle for each domain. Within this cert # Traefik stores a cert bundle for each domain. Within this cert
# bundle there is both proper the certificate and the Let's Encrypt CA # bundle there is both proper the certificate and the Let's Encrypt CA
echo "Extracting cert bundle for ${domain}" echo "Extracting cert bundle for ${domain}"
cert=$(jq -r --arg domain "$domain" '.DomainsCertificate.Certs[].Certificate | cert=$(jq -e -r --arg domain "$domain" '.DomainsCertificate.Certs[].Certificate |
select (.Domain == $domain )| .Certificate' ${acme}) || badACME select (.Domain == $domain )| .Certificate' ${acmefile}) || bad_acme
echo ${cert} | base64 --decode > "${cdir}/${domain}.pem" echo "${cert}" | base64 --decode > "${cdir}/${domain}.pem"
done done