#!/usr/bin/env bash # Renew the openbao.famfi.home leaf cert from OpenBAO's pki_int engine and # install it where Traefik serves it. Idempotent: only renews when the current # cert expires within $RENEW_WINDOW_DAYS. Run as root (writes Traefik's tls dir). # # Installed as a systemd timer (openbao-cert-renew.timer). Manual run: # sudo /home/lutz/Projects/OpenBAO/scripts/renew-openbao-cert.sh [--force] set -euo pipefail ADDR="${BAO_ADDR:-http://127.0.0.1:8200}" TOKEN_FILE="/etc/openbao-cert-renew.token" ROLE="pki_int/issue/famfi-home" CN="openbao.famfi.home" TTL="2160h" # 90 days DEST="/srv/TRAEFIK/etc/traefik/tls/openbao" DYN="/srv/TRAEFIK/etc/traefik/traefik.d/tls-openbao.yml" RENEW_WINDOW_DAYS="${RENEW_WINDOW_DAYS:-21}" # renew when <= this many days left FORCE="${1:-}" log() { printf '%s [renew-cert] %s\n' "$(date '+%F %T')" "$*"; } die() { log "ERROR: $*"; exit 1; } [ -r "$TOKEN_FILE" ] || die "token file $TOKEN_FILE not readable (run as root?)" TOKEN="$(cat "$TOKEN_FILE")" # Skip if the current cert is still good (unless --force) if [ "$FORCE" != "--force" ] && [ -f "$DEST/fullchain.pem" ]; then end="$(openssl x509 -in "$DEST/fullchain.pem" -noout -enddate | cut -d= -f2)" days_left=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 )) if [ "$days_left" -gt "$RENEW_WINDOW_DAYS" ]; then log "cert valid ${days_left}d (> ${RENEW_WINDOW_DAYS}d) — nothing to do" exit 0 fi log "cert has ${days_left}d left (<= ${RENEW_WINDOW_DAYS}d) — renewing" fi # Issue a fresh cert resp="$(curl -sS --fail-with-body --max-time 15 \ -H "X-Vault-Token: ${TOKEN}" \ --data "{\"common_name\":\"${CN}\",\"ttl\":\"${TTL}\"}" \ "${ADDR}/v1/${ROLE}")" || die "issue request failed" tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT export RESP="$resp" python3 - "$tmp" </dev/null | openssl md5)" [ "$cmod" = "$kmod" ] || die "cert/key modulus mismatch — refusing to install" install -d -o root -g root -m 0755 "$DEST" install -o root -g root -m 0644 "$tmp/fullchain.pem" "$DEST/fullchain.pem" install -o root -g root -m 0600 "$tmp/privkey.pem" "$DEST/privkey.pem" # Rewrite the watched dynamic config (with a fresh timestamp) so Traefik's file # provider reparses and reloads the cert from disk — changing the cert file # alone does NOT trigger a reload. cat > "$DYN" <