diff --git a/deploy/gen-ed25519-keypair.go b/deploy/gen-ed25519-keypair.go new file mode 100644 index 0000000..131fbba --- /dev/null +++ b/deploy/gen-ed25519-keypair.go @@ -0,0 +1,22 @@ +// gen-ed25519-keypair erzeugt ein Ed25519-Schluesselpaar fuer die +// Lizenzsignatur (LIC-01/LIC-04) und gibt beide Teile base64-raw-url- +// kodiert aus — dasselbe Format, das internal/license.NewIssuer/NewValidator +// erwarten. Nur vom Installer (deploy/install.sh) verwendet. +package main + +import ( + "crypto/ed25519" + "crypto/rand" + "encoding/base64" + "fmt" + "log" +) + +func main() { + pub, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + log.Fatal(err) + } + fmt.Printf("PUBLIC=%s\n", base64.RawURLEncoding.EncodeToString(pub)) + fmt.Printf("PRIVATE=%s\n", base64.RawURLEncoding.EncodeToString(priv)) +} diff --git a/deploy/install.sh b/deploy/install.sh new file mode 100755 index 0000000..796545a --- /dev/null +++ b/deploy/install.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# NEXARCH Core – Installer/Deployer fuer eine Debian/systemd-Zielumgebung. +# +# Baut alle Core-Binaries (cmd/core + die *-devserver), legt Postgres-Rolle +# und Registry-Datenbank an (falls nicht vorhanden), wendet die +# Registry-Migrationen an, generiert Secrets (falls nicht vorhanden) und +# installiert+startet jeden Dienst als eigenen systemd-Service. +# +# Idempotent: mehrfacher Aufruf ist sicher — vorhandene Rolle/DB/Secrets +# werden nicht ueberschrieben, Migrationen nur angewendet, wenn die +# Registry-DB noch leer ist (siehe Abschnitt "Migrationen" unten). +# +# Aufruf (als root): ./deploy/install.sh +# +# Ueberschreibbar per Umgebungsvariable: +# NEXARCH_INSTALL_DIR (Default: /opt/nexarch-core) +# NEXARCH_PG_ROLE (Default: nexarch_core) +# NEXARCH_PG_REGISTRY_DB (Default: nexarch_registry) +# NEXARCH_BRANCH (Default: aktueller Branch dieses Checkouts) +set -euo pipefail + +INSTALL_DIR="${NEXARCH_INSTALL_DIR:-/opt/nexarch-core}" +PG_ROLE="${NEXARCH_PG_ROLE:-nexarch_core}" +PG_DB="${NEXARCH_PG_REGISTRY_DB:-nexarch_registry}" +ENV_FILE=/etc/nexarch/core.env +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +if [ "$(id -u)" -ne 0 ]; then + echo "Bitte als root ausfuehren (legt Systembenutzer, systemd-Units und Postgres-Rolle an)." >&2 + exit 1 +fi + +echo "== 1. Systembenutzer ==" +if ! id nexarch >/dev/null 2>&1; then + useradd --system --no-create-home --shell /usr/sbin/nologin nexarch + echo "Benutzer 'nexarch' angelegt." +else + echo "Benutzer 'nexarch' existiert bereits." +fi + +echo "== 2. Postgres-Rolle und Registry-Datenbank ==" +if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname = '${PG_ROLE}'" | grep -q 1; then + PG_PASSWORD="$(openssl rand -hex 24)" + sudo -u postgres psql -v ON_ERROR_STOP=1 -c "CREATE ROLE ${PG_ROLE} WITH LOGIN PASSWORD '${PG_PASSWORD}';" + echo "Rolle '${PG_ROLE}' angelegt." +else + echo "Rolle '${PG_ROLE}' existiert bereits — Passwort wird NICHT neu gesetzt (siehe ${ENV_FILE} fuer das vorhandene)." + PG_PASSWORD="" +fi + +if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname = '${PG_DB}'" | grep -q 1; then + sudo -u postgres psql -v ON_ERROR_STOP=1 -c "CREATE DATABASE ${PG_DB} OWNER ${PG_ROLE};" + echo "Datenbank '${PG_DB}' angelegt." +else + echo "Datenbank '${PG_DB}' existiert bereits." +fi +# Fuer Tenant-Provisioning (CREATE DATABASE pro Mandant, Modell C) braucht +# die Rolle CREATEDB-Recht auf der physischen Postgres-Instanz. +sudo -u postgres psql -v ON_ERROR_STOP=1 -c "ALTER ROLE ${PG_ROLE} WITH CREATEDB;" >/dev/null + +echo "== 3. Secrets/Konfiguration ==" +mkdir -p /etc/nexarch +if [ ! -f "$ENV_FILE" ]; then + if [ -z "${PG_PASSWORD}" ]; then + echo "FEHLER: Rolle existierte bereits, aber ${ENV_FILE} fehlt — Passwort kann nicht rekonstruiert werden." >&2 + echo "Entweder ${ENV_FILE} von Hand mit dem bekannten Passwort anlegen, oder die Rolle droppen und erneut installieren." >&2 + exit 1 + fi + + AUDIT_ADMIN_TOKEN="$(openssl rand -hex 32)" + + # Ed25519-Schluesselpaar fuer die Lizenzsignatur (LIC-01/LIC-04): + # licadmin-devserver prueft Lizenzen nur mit dem OEFFENTLICHEN Schluessel, + # der private Schluessel wird NICHT deployt, sondern separat fuer das + # (noch zu bauende) offline Lizenz-Ausstellungswerkzeug aufbewahrt. + KEYPAIR_DIR=/etc/nexarch/license-signing + mkdir -p "$KEYPAIR_DIR" + chmod 700 "$KEYPAIR_DIR" + if [ ! -f "$KEYPAIR_DIR/private.b64" ]; then + go run "$SCRIPT_DIR/gen-ed25519-keypair.go" > "$KEYPAIR_DIR/keypair.txt" + grep '^PRIVATE=' "$KEYPAIR_DIR/keypair.txt" | cut -d= -f2 > "$KEYPAIR_DIR/private.b64" + grep '^PUBLIC=' "$KEYPAIR_DIR/keypair.txt" | cut -d= -f2 > "$KEYPAIR_DIR/public.b64" + chmod 600 "$KEYPAIR_DIR"/*.b64 "$KEYPAIR_DIR/keypair.txt" + rm -f "$KEYPAIR_DIR/keypair.txt" + fi + LICENSE_PUBLIC_KEY="$(cat "$KEYPAIR_DIR/public.b64")" + + cat > "$ENV_FILE" </dev/null + echo "angewendet: $(basename "$f")" + done +fi + +echo "== 6. systemd-Units ==" +for tmpl in "$SCRIPT_DIR"/systemd/*.service.tmpl; do + name="$(basename "$tmpl" .service.tmpl)" + sed "s#__INSTALL_DIR__#${INSTALL_DIR}#g" "$tmpl" > "/etc/systemd/system/${name}.service" +done +systemctl daemon-reload +for tmpl in "$SCRIPT_DIR"/systemd/*.service.tmpl; do + name="$(basename "$tmpl" .service.tmpl)" + systemctl enable --now "${name}.service" +done + +echo "== Fertig ==" +echo "Status pruefen mit: systemctl status 'nexarch-*'" +echo "Health-Checks:" +echo " curl -s http://localhost:8080/healthz" +echo " curl -s http://localhost:8081/healthz # licadmin" +echo " curl -s http://localhost:8082/healthz # tenantadmin" +echo " curl -s http://localhost:8083/healthz # auditlog" +echo " curl -s http://localhost:8084/healthz # statuspage" +echo " curl -s http://localhost:8085/healthz # metrics" +echo " curl -s http://localhost:8086/unprotected # secheaders (kein /healthz)" diff --git a/deploy/systemd/nexarch-auditlog-devserver.service.tmpl b/deploy/systemd/nexarch-auditlog-devserver.service.tmpl new file mode 100644 index 0000000..40d7b7a --- /dev/null +++ b/deploy/systemd/nexarch-auditlog-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH auditlog-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/auditlog-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-core.service.tmpl b/deploy/systemd/nexarch-core.service.tmpl new file mode 100644 index 0000000..4a0b22c --- /dev/null +++ b/deploy/systemd/nexarch-core.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH Core +After=network.target postgresql.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/core +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-licadmin-devserver.service.tmpl b/deploy/systemd/nexarch-licadmin-devserver.service.tmpl new file mode 100644 index 0000000..026963b --- /dev/null +++ b/deploy/systemd/nexarch-licadmin-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH licadmin-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/licadmin-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-metrics-devserver.service.tmpl b/deploy/systemd/nexarch-metrics-devserver.service.tmpl new file mode 100644 index 0000000..74622fb --- /dev/null +++ b/deploy/systemd/nexarch-metrics-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH metrics-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/metrics-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-secheaders-devserver.service.tmpl b/deploy/systemd/nexarch-secheaders-devserver.service.tmpl new file mode 100644 index 0000000..6bb06fa --- /dev/null +++ b/deploy/systemd/nexarch-secheaders-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH secheaders-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/secheaders-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-statuspage-devserver.service.tmpl b/deploy/systemd/nexarch-statuspage-devserver.service.tmpl new file mode 100644 index 0000000..125bf00 --- /dev/null +++ b/deploy/systemd/nexarch-statuspage-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH statuspage-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/statuspage-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target diff --git a/deploy/systemd/nexarch-tenantadmin-devserver.service.tmpl b/deploy/systemd/nexarch-tenantadmin-devserver.service.tmpl new file mode 100644 index 0000000..4293138 --- /dev/null +++ b/deploy/systemd/nexarch-tenantadmin-devserver.service.tmpl @@ -0,0 +1,17 @@ +[Unit] +Description=NEXARCH tenantadmin-devserver +After=network.target postgresql.service nexarch-core.service +Wants=postgresql.service + +[Service] +Type=simple +User=nexarch +Group=nexarch +EnvironmentFile=/etc/nexarch/core.env +ExecStart=__INSTALL_DIR__/bin/tenantadmin-devserver +Restart=on-failure +RestartSec=3 +WorkingDirectory=__INSTALL_DIR__ + +[Install] +WantedBy=multi-user.target