diff --git a/deploy/k8s/overlays/encry/configmap-backend.yaml b/deploy/k8s/overlays/encry/configmap-backend.yaml index 5af6665..fa9027c 100644 --- a/deploy/k8s/overlays/encry/configmap-backend.yaml +++ b/deploy/k8s/overlays/encry/configmap-backend.yaml @@ -1,6 +1,6 @@ # Werte fuer den Cluster. Bedeutung der Schluessel: -# base/backend/configmap.example.yaml. Hosts und Tenant sind Platzhalter, -# Runbook Schritt 1 uebernimmt die Live-Werte. Geheimes gehoert ins Secret +# base/backend/configmap.example.yaml. Live-Werte (Stand 2026-10-15) aus dem +# Cluster uebernommen (Runbook Schritt 1). Geheimes gehoert ins Secret # apicore-backend-secret, nie hierher. apiVersion: v1 kind: ConfigMap @@ -10,15 +10,17 @@ data: PORT: "3001" JWT_ACCESS_EXPIRES_IN: "15m" JWT_REFRESH_EXPIRES_IN: "7d" - FRONTEND_ORIGIN: "https://apicore.example.com" + FRONTEND_ORIGIN: "https://apicore.encry.de" DOCUMENTS_STORAGE_PATH: "/data/documents" BACKUP_STORAGE_PATH: "/data/backups" BACKUP_CRON_SCHEDULE: "0 3 * * *" - BACKUP_RETENTION_COUNT: "14" + BACKUP_RETENTION_COUNT: "30" COOKIE_SECURE: "true" TRUST_PROXY: "loopback, 10.42.0.0/16, 173.245.48.0/20, 103.21.244.0/22, 103.22.200.0/22, 103.31.4.0/22, 141.101.64.0/18, 108.162.192.0/18, 190.93.240.0/20, 188.114.96.0/20, 197.234.240.0/22, 198.41.128.0/17, 162.158.0.0/15, 104.16.0.0/13, 104.24.0.0/14, 172.64.0.0/13, 131.0.72.0/22, 2400:cb00::/32, 2606:4700::/32, 2803:f800::/32, 2405:b500::/32, 2405:8100::/32, 2a06:98c0::/29, 2c0f:f248::/32" - OIDC_ISSUER_URL: "https://login.microsoftonline.com//v2.0" - OIDC_REDIRECT_URI: "https://api.apicore.example.com/api/v1/auth/sso/callback" + OIDC_ISSUER_URL: "https://login.microsoftonline.com/30e1c0c9-0295-4074-b45d-c3372140d2a4/v2.0/.well-known/openid-configuration" + # Oeffentliche Client-ID der Entra-App (kein Geheimnis); laeuft live hier. + OIDC_CLIENT_ID: "fe64e5ac-55c4-46dc-8b86-3340797d2451" + OIDC_REDIRECT_URI: "https://apicorebackend.encry.de/api/v1/auth/sso/callback" WEATHER_HISTORY_SOURCE: "open-meteo" OPEN_METEO_FORECAST_URL: "https://api.open-meteo.com/v1/forecast" OPEN_METEO_ARCHIVE_URL: "https://archive-api.open-meteo.com/v1/archive" diff --git a/deploy/k8s/overlays/encry/configmap-frontend.yaml b/deploy/k8s/overlays/encry/configmap-frontend.yaml index 1c4d618..bc79be0 100644 --- a/deploy/k8s/overlays/encry/configmap-frontend.yaml +++ b/deploy/k8s/overlays/encry/configmap-frontend.yaml @@ -5,4 +5,4 @@ kind: ConfigMap metadata: name: apicore-frontend-config data: - API_URL: "https://api.apicore.example.com/api/v1" + API_URL: "https://apicorebackend.encry.de/api/v1" diff --git a/deploy/k8s/scripts/ensure-secrets.sh b/deploy/k8s/scripts/ensure-secrets.sh new file mode 100644 index 0000000..82a5c6f --- /dev/null +++ b/deploy/k8s/scripts/ensure-secrets.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Ergaenzt fehlende Schluessel in den ApiCore-Secrets, ohne vorhandene Werte +# zu aendern. Gibt nur Schluesselnamen aus, nie Werte. Mehrfach ausfuehrbar. +# +# bash deploy/k8s/scripts/ensure-secrets.sh # Namespace apicore +# bash deploy/k8s/scripts/ensure-secrets.sh --dry-run # nur anzeigen +# +# Werte: +# - MFA_/WEBHOOK_/BACKUP_ENCRYPTION_KEY: zufaellig (48 Byte, base64url). Die +# App verlangt mindestens 32 Zeichen; "dummy" wuerde den Start abbrechen. +# Diese Schluessel nie wieder aendern ohne *_PREVIOUS (sonst sind MFA- +# Geheimnisse, Webhook-Secrets und Backups nicht mehr lesbar). Sichern! +# - OPEN_METEO_API_KEY: leer = freie Open-Meteo-API (ein Fantasiewert wuerde +# die kostenpflichtige API mit falschem Schluessel ansprechen). +# - TELEGRAM_BOT_TOKEN (Secret apicore-telegram, nur Worker): "dummy". Die App +# erkennt ein ungueltiges Format und schaltet Telegram ab, bis das echte +# Token von BotFather eingetragen ist. +set -euo pipefail + +NS="${NAMESPACE:-apicore}" +DRY_RUN=false +[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true + +random_key() { + node -e "process.stdout.write(require('crypto').randomBytes(48).toString('base64url'))" +} + +existing_keys() { + kubectl get secret "$1" -n "$NS" -o jsonpath='{.data}' 2>/dev/null \ + | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{console.log(Object.keys(JSON.parse(s||'{}')).join('\n'))}catch{}})" +} + +# ensure_keys [ ...] +ensure_keys() { + local secret="$1"; shift + local have + have="$(existing_keys "$secret")" + local patch="{}" added=() + while (($#)); do + local key="$1" mode="$2"; shift 2 + if grep -qx "$key" <<<"$have"; then + continue + fi + local value + case "$mode" in + random) value="$(random_key)" ;; + empty) value="" ;; + dummy) value="dummy" ;; + esac + patch="$(KEY="$key" VALUE="$value" PATCH="$patch" node -e "const p=JSON.parse(process.env.PATCH);p.stringData=p.stringData||{};p.stringData[process.env.KEY]=process.env.VALUE;process.stdout.write(JSON.stringify(p))")" + added+=("$key") + done + if ((${#added[@]} == 0)); then + echo "$secret: alle Schluessel vorhanden" + return + fi + if $DRY_RUN; then + echo "$secret: wuerde ergaenzen: ${added[*]}" + return + fi + if ! kubectl get secret "$secret" -n "$NS" >/dev/null 2>&1; then + kubectl create secret generic "$secret" -n "$NS" >/dev/null + fi + kubectl patch secret "$secret" -n "$NS" --type merge -p "$patch" >/dev/null + echo "$secret: ergaenzt: ${added[*]}" +} + +ensure_keys apicore-backend-secret \ + MFA_ENCRYPTION_KEY random \ + WEBHOOK_ENCRYPTION_KEY random \ + BACKUP_ENCRYPTION_KEY random \ + OPEN_METEO_API_KEY empty + +ensure_keys apicore-telegram \ + TELEGRAM_BOT_TOKEN dummy + +echo "Fertig. Laufende Pods lesen neue Werte erst nach einem Neustart."