116 lines
4.4 KiB
Bash
Executable File
116 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
#
|
|
# Erzeugt die Konfiguration des Tunnel-Gateways beim Start und startet Caddy.
|
|
#
|
|
# Warum erzeugt statt fest hinterlegt: die Namen stehen in der .env und sind je
|
|
# Installation andere, und zu jedem gehört ein eigenes Zertifikat. Caddy startet
|
|
# NICHT, wenn eine in `tls` genannte Datei fehlt — ein noch nicht ausgestelltes
|
|
# Zertifikat für www. nähme damit den Tunnel-Zugang zur Konsole mit, und das ist
|
|
# der Weg, auf dem sich ein ausgesperrter Betreiber zurückholt. Deshalb wird
|
|
# jeder Name einzeln geprüft und ausgelassen, wenn sein Zertifikat fehlt.
|
|
#
|
|
# Die Zertifikate sind die, die der öffentliche Caddy ohnehin erneuert. Ein
|
|
# Zertifikat hängt am NAMEN, nicht an der Adresse, die ihn ausliefert.
|
|
set -eu
|
|
|
|
HUB="${VPN_HUB_ADDRESS:-10.66.0.1}"
|
|
HEALTH="${VPN_HEALTH_PORT:-8081}"
|
|
CERT_DIR="${VPN_CERT_DIR:-/certs}"
|
|
OUT="${VPN_CONFIG_OUT:-/tmp/vpn.Caddyfile}"
|
|
|
|
# Die Zertifikate, die dieser Lauf wirklich geladen hat. Der Update-Agent
|
|
# ueberwacht sie und startet den Gateway nach einer Erneuerung neu — Caddys
|
|
# `tls` liest die Datei EINMAL beim Start, und ohne Neustart liefe der Tunnel
|
|
# danach mit einem abgelaufenen Zertifikat weiter, ausgerechnet fuer die
|
|
# einzigen Leute, die die Konsole noch erreichen.
|
|
CERT_LIST="${VPN_CERT_LIST:-/tmp/vpn-certs.list}"
|
|
: > "$CERT_LIST"
|
|
|
|
{
|
|
echo '{'
|
|
echo ' admin off'
|
|
echo ' auto_https off'
|
|
echo '}'
|
|
} > "$OUT"
|
|
|
|
# Der Konsolenname ZUERST, und getrennt von der Liste: er ist der einzige, ohne
|
|
# den der Gateway keinen Zweck hat.
|
|
emit_site() {
|
|
name="$1"
|
|
# `-print -quit`, nicht `| head -1`: eine Pipe, aus der head aussteigt,
|
|
# waehrend find noch schreibt, liefert SIGPIPE — install-agent.sh hat sich
|
|
# daran schon einmal selbst beendet. `|| true`, damit ein leeres Ergebnis
|
|
# unter `set -e` kein Abbruch ist.
|
|
crt="$(find "$CERT_DIR" -name "${name}.crt" -print -quit 2>/dev/null || true)"
|
|
|
|
if [ -z "$crt" ] || [ ! -f "${crt%.crt}.key" ]; then
|
|
echo " ausgelassen: $name — kein Zertifikat unter $CERT_DIR" >&2
|
|
return 0
|
|
fi
|
|
|
|
{
|
|
echo ""
|
|
echo "https://${name}:443 {"
|
|
echo " bind ${HUB}"
|
|
echo " tls ${crt} ${crt%.crt}.key"
|
|
echo " reverse_proxy app:80 {"
|
|
echo " header_up X-Forwarded-For {remote_host}"
|
|
echo " header_up X-Forwarded-Proto https"
|
|
echo " header_up Host {host}"
|
|
echo " }"
|
|
echo "}"
|
|
} >> "$OUT"
|
|
|
|
echo "$crt" >> "$CERT_LIST"
|
|
}
|
|
|
|
# `if`, nicht `[ … ] && …`. Bei leerem Wert gibt die AND-OR-Liste 1 zurueck, und
|
|
# genau diese Konstruktion hat install-agent.sh unter `set -e` schon einmal
|
|
# beendet — dort als letzte Anweisung einer Funktion. Hier waere sie geprueft
|
|
# unschaedlich, aber die Regel steht im Repo und eine Ausnahme davon muesste man
|
|
# jedem Nachfolger erklaeren.
|
|
if [ -n "${VPN_INTERNAL_HOST:-}" ]; then
|
|
emit_site "$VPN_INTERNAL_HOST"
|
|
fi
|
|
|
|
# Portal, Website und Statusseite. files. steht hier nie drin: dort holt ein
|
|
# Server im Rettungssystem sein Archiv, und der ist nicht im Tunnel.
|
|
echo "${VPN_TUNNEL_HOSTS:-}" | tr ',' '\n' | while read -r host; do
|
|
[ -n "$host" ] || continue
|
|
emit_site "$host"
|
|
done
|
|
|
|
# Antwortet der Gesundheits-Port mit 204, gilt der Tunnel als BEREIT — daran
|
|
# haengt, ob ausgegebene Client-Konfigurationen den Resolver ueberhaupt nennen.
|
|
# Er darf deshalb nicht bloss sagen „dieser Gateway laeuft": ohne Zertifikat fuer
|
|
# den Konsolennamen rendert dieses Skript einen Gateway, der auf 443 gar nichts
|
|
# bedient — und ein Client bekaeme einen Resolver genannt, der ihn auf eine
|
|
# Adresse schickt, die die Verbindung ablehnt. Frueher war das unmoeglich, weil
|
|
# Caddy ohne lesbares Zertifikat ueberhaupt nicht startete; genau diese Annahme
|
|
# hat dieses Skript aufgehoben.
|
|
if [ -n "${VPN_INTERNAL_HOST:-}" ] && grep -q "^https://${VPN_INTERNAL_HOST}:443 {" "$OUT"; then
|
|
HEALTH_CODE=204
|
|
else
|
|
HEALTH_CODE=503
|
|
fi
|
|
|
|
# Der Gesundheits-Port selbst, ohne TLS und ohne Namen: ein Client, der nur den
|
|
# Resolver braucht, soll nicht erst ein Zertifikat vorweisen muessen, um zu
|
|
# erfahren, ob der Tunnel steht.
|
|
{
|
|
echo ""
|
|
echo "http://${HUB}:${HEALTH} {"
|
|
echo " bind ${HUB}"
|
|
echo " respond /healthz ${HEALTH_CODE}"
|
|
echo " respond 404"
|
|
echo "}"
|
|
} >> "$OUT"
|
|
|
|
# Nur rendern, für den Test: er prüft, was das Skript AUSLÄSST, und braucht
|
|
# dafür kein laufendes Caddy.
|
|
if [ -n "${VPN_RENDER_ONLY:-}" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
exec caddy run --config "$OUT" --adapter caddyfile
|