The hostnames are already declared, once, in the fabio route tags. A domains.txt would be a second source of truth free to disagree with what is actually served, so myos cert reads the tags instead and decides on its own which name needs a wildcard: one is asked for where a tag uses one, and it absorbs the concrete names it covers. A wildcard covers a single label, so a.b.example.org keeps its own certificate. dehydrated issues them: a shell script, no python, which fits a tool that has to install on any server. It answers http-01 itself on a port bound to the loopback and routed by fabio, and delegates dns-01 to a provider hook. The deploy hook writes the two file names fabio watches for, through a temporary name so fabio never reads half a certificate. Fixed on the way: the port parser wanted six spaces of indentation and the catalogue writes four, so every stack that binds its ports was reported unbound.
92 lines
3.1 KiB
Bash
92 lines
3.1 KiB
Bash
#shellcheck shell=sh
|
|
# shellcheck disable=SC1091 # lib/cmd files are sourced by path at run time
|
|
# shellcheck disable=SC3028 # HOSTNAME is a myos variable, set by bin/myos
|
|
# myos cert <list|domains|issue|renew|show> the certificates a server needs
|
|
#
|
|
# The hostnames come from the route tags of the stacks, so a site gets a
|
|
# certificate by being routed, not by being written down a second time.
|
|
myos_cmd_cert() {
|
|
_sub=$(myos_firstword "${MYOS_VARS:-}${MYOS_ARGS:+ $MYOS_ARGS}")
|
|
[ -n "$_sub" ] || _sub=list
|
|
case $_sub in
|
|
list) myos_cert_list ;;
|
|
domains) myos_cert_write_domains ;;
|
|
issue) myos_cert_run "" ;;
|
|
renew) myos_cert_run "--cron" ;;
|
|
show) myos_cert_show ;;
|
|
*) myos_die "$MYOS_E_USAGE" "myos cert <list|domains|issue|renew|show>" ;;
|
|
esac
|
|
}
|
|
|
|
# myos_cert_list the certificates that would be asked for, and how
|
|
myos_cert_list() {
|
|
_groups=$(myos_cert_groups)
|
|
[ -n "$_groups" ] || {
|
|
printf 'no routed hostname: nothing to certify\n'
|
|
return 0
|
|
}
|
|
printf '%s%-46s %-9s %s%s\n' "$MYOS_C_HIGHLIGHT" CERTIFICATE CHALLENGE NAMES "$MYOS_C_RESET"
|
|
printf '%s\n' "$_groups" | while IFS= read -r _line; do
|
|
_cn=$(myos_firstword "$_line")
|
|
case $_line in
|
|
*'*.'*) _ch=dns-01 ;;
|
|
*) _ch=http-01 ;;
|
|
esac
|
|
printf '%-46s %-9s %s\n' "$_cn" "$_ch" "$_line"
|
|
done
|
|
myos_cert_needs_dns &&
|
|
myos_info "a wildcard is asked for: dns-01 needs MYOS_CERT_HOOK to talk to your dns provider"
|
|
return 0
|
|
}
|
|
|
|
# myos_cert_write_domains the domains.txt dehydrated reads
|
|
myos_cert_write_domains() {
|
|
_dir=${MYOS_CERT_DIR:-$WORKDIR/.myos/dehydrated}
|
|
_file=$_dir/domains.txt
|
|
_groups=$(myos_cert_groups)
|
|
[ -n "$_groups" ] || { myos_warning "no routed hostname: not writing $_file"; return 0; }
|
|
myos_run mkdir -p "$_dir"
|
|
if [ "${DRYRUN:-false}" = true ]; then
|
|
printf 'would write %s:\n%s\n' "$_file" "$_groups"
|
|
else
|
|
printf '%s\n' "$_groups" > "$_file"
|
|
printf '%s\n' "$_file"
|
|
fi
|
|
}
|
|
|
|
# myos_cert_run ARGS run dehydrated in the host stack, on the domains derived
|
|
myos_cert_run() {
|
|
myos_cert_write_domains >/dev/null || return $?
|
|
_args=$1
|
|
[ -n "${MYOS_CERT_STAGING:-}" ] && _args="$_args --staging"
|
|
case ${MYOS_ARGS:-} in
|
|
*--staging*) _args="$_args --staging" ;;
|
|
esac
|
|
case ${MYOS_ARGS:-} in
|
|
*--force*) _args="$_args --force" ;;
|
|
esac
|
|
MYOS_ARGS="$_args" SERVICE=${SERVICE:-dehydrated} \
|
|
MYOS_STACKS="host/dehydrated" myos_cert_exec
|
|
}
|
|
|
|
myos_cert_exec() {
|
|
# shellcheck source=lib/cmd/exec.sh
|
|
. "$MYOS_ROOT/lib/cmd/exec.sh"
|
|
myos_cmd_exec
|
|
}
|
|
|
|
# myos_cert_show the certificates that exist, and when they expire
|
|
myos_cert_show() {
|
|
_vol=${HOST_DOCKER_VOLUME:-${HOSTNAME:-localhost}}
|
|
# shellcheck disable=SC2016 # the script runs in the container, not here
|
|
myos_run docker run --rm -v "$_vol:/host" alpine:3.20 sh -c '
|
|
apk add -q openssl 2>/dev/null
|
|
for c in /host/certs/*-cert.pem; do
|
|
[ -f "$c" ] || continue
|
|
n=$(basename "$c" -cert.pem)
|
|
e=$(openssl x509 -in "$c" -noout -enddate 2>/dev/null | sed "s/notAfter=//")
|
|
i=$(openssl x509 -in "$c" -noout -issuer 2>/dev/null | sed "s/.*CN *= *//;s/,.*//")
|
|
printf "%-46s %-28s %s\n" "$n" "$e" "$i"
|
|
done'
|
|
}
|