#!/bin/sh # fetch.sh fetch and verify certificates from an HTTP endpoint # This is meant to be used with the ACME set -e verbose() { if [ $_verbose -ne 0 ] ; then return 0 fi return 1 } cleanup() { verbose && echo "Removing $_tmpdir" rm -rf "$_tmpdir" || echo exit 0 } _curl='curl -sS' fullchainf= certfile= keyfile= fetchurl= domain= encryptionKeyFile= signatureKeyFile= _verbose=0 _tmpdir="$(mktemp -d)" help() { cat < -c -k -u -d -K -S [-v] Optionally, AGE_ENCRYPTION_KEY and SIGNIFY_KEY can be set and the contents of the environment variables will be used as key files instead. -v is verbose. EOF exit 1 } #shellcheck disable=SC2034 while [ $# -gt 0 ] ; do case $1 in -f) fullchainf="$2"; shift ; shift ;; -c) certfile="$2"; shift ; shift ;; -k) keyfile="$2"; shift ; shift ;; -u) fetchurl="$2"; shift ; shift ;; -d) domain="$2"; shift ; shift ;; -K) encryptionKeyFile="$2"; shift ; shift ;; -S) signatureKeyFile="$2"; shift ; shift ;; -v) _verbose=1; shift ;; *) help ;; esac ; done cd "$_tmpdir" if [ -n "$AGE_ENCRYPTION_KEY" ] ; then encryptionKeyFile="age.key" chmod 600 "$encryptionKeyFile" echo "$AGE_ENCRYPTION_KEY" > "$encryptionKeyFile" fi if [ -n "$SIGNIFY_KEY" ] ; then signatureKeyFile="signify.sig" chmod 600 "$signatureKeyFile" echo "$SIGNIFY_KEY" > "$signatureKeyFile" fi cd - err=0 for opt in fullchainf certfile keyfile fetchurl domain \ encryptionKeyFile signatureKeyFile ; do eval val="\$$opt" #shellcheck disable=SC2154 if [ -z "$val" ] ; then echo "Missing $opt" err=1 fi done if [ $err -ne 0 ] ; then echo "missing required arguments" exit 1; fi encryptionKeyFile="$(realpath "$encryptionKeyFile")" signatureKeyFile="$(realpath "$signatureKeyFile")" [ -e "$keyfile" ] && keyfile="$(realpath "$keyfile")" [ -e "$fullchainf" ] && fullchainf="$(realpath "$fullchainf")" [ -e "$certfile" ] && certfile="$(realpath "$certfile")" if ! [ -e "$keyfile" ] ; then echo "Warning: no key file found" >&2 fi if ! [ -e "$fullchainf" ] ; then echo "Warning: no fullchain file found" >&2 fi if ! [ -e "$certfile" ] ; then echo "Warning: no cert file found" >&2 fi cd "$_tmpdir" trap cleanup EXIT INT verbose && echo Fetching checkums... $_curl "${fetchurl}/${domain}.sha256sum" > "${domain}.sha256sum" $_curl "${fetchurl}/${domain}.sha256sum.sig" > "${domain}.sha256sum.sig" signify -V -p "$signatureKeyFile" -m "${domain}.sha256sum" verbose && echo "Checksums OK" ok=0 checksum="$(sha256sum "$keyfile" | awk '{print $1}')" if grep -q "$checksum" "${domain}".sha256sum ; then verbose && echo "Current key file \"$keyfile\" OK" ok=$((ok + 1)) fi checksum="$(sha256sum "$fullchainf" | awk '{print $1}')" if grep -q "$checksum" "${domain}".sha256sum ; then verbose && echo "Current fullchain file \"$fullchainf\" ok" ok=$((ok + 1)) fi checksum="$(sha256sum "$certfile" | awk '{print $1}')" if grep -q "$checksum" "${domain}".sha256sum ; then verbose && echo "Current cert file \"$certfile\" ok" ok=$((ok + 1)) fi if [ $ok -eq 3 ] ; then verbose && echo "All files appear okay, exiting" exit 0 fi for _f in fullchain cer key.enc ; do verbose && echo "Fetching ${_f}..." $_curl "${fetchurl}/${domain}.${_f}" > "${domain}.$_f" done verbose && echo "Decrypting key" age -i "$encryptionKeyFile" -d "${domain}.key.enc" > "${domain}".key verbose && echo "Validating checksum for downloaded files" sha256sum -c "${domain}.sha256sum" verbose && echo "Updating files" cat < "${domain}".fullchain > "$fullchainf" cat < "${domain}".cer > "$certfile" cat < "${domain}.key" > "$keyfile"