e58c78d21c
- scripts/install-client.sh: bootstraps a pi client — fetches certs from the Caddy host via scp, rsyncs the extensions into ~/.pi/agent/, sets up SSH key-auth to the ai-server for admin commands, probes the mTLS /health endpoint to verify. - scripts/issue-client-cert.sh: run on the Caddy host to mint a new device identity — generates key + CSR, signs with the local root CA, and emits both a modern p12 (AES-256) and a -legacy p12 (3DES/RC2-40) for NSS-based browsers. - scripts/install-browser-certs.sh: imports certs into Brave Flatpak's isolated NSS DB, ~/.pki/nssdb for packaged Chromium-family browsers, each Firefox profile, optionally the system trust store, and optionally drops a Brave AutoSelectCertificateForUrls policy so the cert prompt stops appearing on every page load. All three are idempotent, --help-aware, and accept env/flag overrides for the hardcoded defaults. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
101 lines
3.6 KiB
Bash
Executable File
101 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# issue-client-cert.sh — Generate a new mTLS client identity signed by the
|
|
# local root CA. Run this ON THE CADDY HOST (where root-ca.key lives).
|
|
#
|
|
# Produces four files in $CERT_DIR, keyed on a per-device name:
|
|
# client-<name>.crt client cert (for pi CLI, nginx config, etc.)
|
|
# client-<name>.key client private key
|
|
# client-<name>.p12 modern bundle (PBES2/AES-256) — CLI use only
|
|
# client-<name>-legacy.p12 legacy bundle (3DES/RC2-40) — for browser import
|
|
#
|
|
# Usage:
|
|
# scripts/issue-client-cert.sh <device-name> [--force]
|
|
# <device-name> alphanumerics + dashes/underscores (e.g. laptop-alice)
|
|
# --cert-dir PATH override $CERT_DIR (default /mnt/ssdpool/@docker/caddy/certs)
|
|
# --days N validity (default 3650)
|
|
# --force overwrite existing files for this name
|
|
# --help show this message
|
|
|
|
set -euo pipefail
|
|
|
|
CERT_DIR="${CERT_DIR:-/mnt/ssdpool/@docker/caddy/certs}"
|
|
DAYS="${DAYS:-3650}"
|
|
ORG="${ORG:-ShahODin}"
|
|
COUNTRY="${COUNTRY:-DE}"
|
|
FORCE=0
|
|
NAME=""
|
|
|
|
usage() { sed -n '2,/^$/p' "$0" | sed 's/^#\{0,1\} \{0,1\}//'; exit 0; }
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--cert-dir) CERT_DIR="$2"; shift 2 ;;
|
|
--days) DAYS="$2"; shift 2 ;;
|
|
--force) FORCE=1; shift ;;
|
|
-h|--help) usage ;;
|
|
-*) echo "Unknown arg: $1" >&2; exit 1 ;;
|
|
*)
|
|
if [[ -z "$NAME" ]]; then NAME="$1"; shift
|
|
else echo "Extra positional arg: $1" >&2; exit 1; fi ;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$NAME" ]] || { echo "Usage: $0 <device-name>" >&2; exit 1; }
|
|
[[ "$NAME" =~ ^[A-Za-z0-9_-]+$ ]] || { echo "Invalid name: $NAME (alphanumerics, - and _ only)" >&2; exit 1; }
|
|
|
|
[[ -d "$CERT_DIR" ]] || { echo "Cert dir not found: $CERT_DIR" >&2; exit 1; }
|
|
cd "$CERT_DIR"
|
|
|
|
[[ -f root-ca.key && -f root-ca.pem ]] || { echo "root-ca.key and root-ca.pem must exist in $CERT_DIR" >&2; exit 1; }
|
|
|
|
for f in "client-${NAME}.key" "client-${NAME}.crt" "client-${NAME}.p12" "client-${NAME}-legacy.p12"; do
|
|
if [[ -e "$f" && $FORCE -eq 0 ]]; then
|
|
echo "Refusing to overwrite $CERT_DIR/$f (use --force)" >&2; exit 1
|
|
fi
|
|
done
|
|
|
|
echo "==> Generating 4096-bit RSA key + CSR for '$NAME'"
|
|
openssl genrsa -out "client-${NAME}.key" 4096 2>/dev/null
|
|
chmod 600 "client-${NAME}.key"
|
|
openssl req -new -key "client-${NAME}.key" -out "client-${NAME}.csr" \
|
|
-subj "/CN=${ORG} Client ${NAME}/O=${ORG}/C=${COUNTRY}"
|
|
|
|
echo "==> Signing with root CA"
|
|
openssl x509 -req -in "client-${NAME}.csr" \
|
|
-CA root-ca.pem -CAkey root-ca.key -CAcreateserial \
|
|
-out "client-${NAME}.crt" -days "$DAYS" 2>/dev/null
|
|
rm -f "client-${NAME}.csr"
|
|
|
|
echo "==> Bundling PKCS#12 (modern + legacy)"
|
|
openssl pkcs12 -export \
|
|
-out "client-${NAME}.p12" \
|
|
-inkey "client-${NAME}.key" \
|
|
-in "client-${NAME}.crt" \
|
|
-certfile root-ca.pem \
|
|
-name "${ORG} Client (${NAME})" \
|
|
-passout pass:
|
|
chmod 600 "client-${NAME}.p12"
|
|
|
|
openssl pkcs12 -legacy -export \
|
|
-out "client-${NAME}-legacy.p12" \
|
|
-inkey "client-${NAME}.key" \
|
|
-in "client-${NAME}.crt" \
|
|
-certfile root-ca.pem \
|
|
-name "${ORG} Client (${NAME}, legacy)" \
|
|
-passout pass:
|
|
chmod 600 "client-${NAME}-legacy.p12"
|
|
|
|
echo
|
|
echo "==> Done. Files in $CERT_DIR:"
|
|
ls -la "client-${NAME}".* | sed 's/^/ /'
|
|
echo
|
|
echo "To install on a pi client (run there):"
|
|
echo " mkdir -p ~/.pi/agent/certs"
|
|
echo " scp $(whoami)@$(hostname -f):${CERT_DIR}/client-${NAME}.crt ~/.pi/agent/certs/client.pem"
|
|
echo " scp $(whoami)@$(hostname -f):${CERT_DIR}/client-${NAME}.key ~/.pi/agent/certs/client-key.pem"
|
|
echo " scp $(whoami)@$(hostname -f):${CERT_DIR}/root-ca.pem ~/.pi/agent/certs/"
|
|
echo
|
|
echo "To import in a browser, fetch client-${NAME}-legacy.p12 and pass it to"
|
|
echo "scripts/install-browser-certs.sh on the client."
|