feat(admin): SUPER_ADMIN TLS-Zertifikat-Status + Renewal-Trigger

Neuer Router /admin/tls (SUPER_ADMIN only, AuditLog, Rate-Limit 5/hour):
- GET  /admin/tls/status         – erkennt proxy/certbot/internal-Modus,
  liest Ablaufdatum via openssl x509 -enddate
- POST /admin/tls/renew/certbot  – ruft setup-tls.sh <domain> auf
- POST /admin/tls/renew/internal – ruft setup-tls-internal.sh <hostname> [ip]
  auf, reloaded nginx danach

Läuft mit den Root-Rechten des bestehenden timemaster.service (User=root,
unverändert) - Angriffsfläche dadurch begrenzt auf SUPER_ADMIN-Auth +
Domain/Hostname-Validierung (Regex, kein Shell-Interpolieren, subprocess
mit Argument-Liste statt shell=True).

Frontend: neuer Tab "Server / TLS" in TenantsPage – Status-Anzeige +
zwei Formulare (öffentlich/intern).

3 neue Tests in test_tls_admin.py (Rollen-Gate, Status im Testcontext,
Input-Validierung).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LTxkZEUdfgMxZvHPiZJ8bV
This commit is contained in:
2026-08-05 20:29:47 +02:00
co-authored by Claude Sonnet 5
parent f354bddd1e
commit f3ed234e56
6 changed files with 436 additions and 3 deletions
+2
View File
@@ -20,6 +20,7 @@ from app.routers import hours_payouts
from app.routers import public_stamp
from app.routers import ical
from app.routers import reseller, tenants
from app.routers import tls_admin
@asynccontextmanager
@@ -112,6 +113,7 @@ app.include_router(special_assignments.router, prefix=API_PREFIX)
app.include_router(hours_payouts.router, prefix=API_PREFIX)
app.include_router(reseller.router, prefix=API_PREFIX)
app.include_router(tenants.router, prefix=API_PREFIX)
app.include_router(tls_admin.router, prefix=API_PREFIX)
# ── Health ────────────────────────────────────────────────────────────────────