feat(Phase 11b): Bypass-DB-Logging + Auto-Rotation-Skript
- auth_bypass_uses-Tabelle additiv (used_at, client_ip, path, user_agent). - _check_debug_token schreibt jeden Use als Best-Effort-Insert (Try/Except, kein Fehler an User). - scripts/rotate-debug-token.sh: wöchentlicher Cron, generiert neues Secret + re-creates dev-Container. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c13292133c
commit
d853101275
21
app/auth.py
21
app/auth.py
@ -116,10 +116,29 @@ def _check_debug_token(request: Request) -> Optional[dict]:
|
||||
presented = (request.query_params.get("__debug_token") or "").strip()
|
||||
if presented and presented == expected:
|
||||
client = request.client.host if request.client else "?"
|
||||
path = request.url.path
|
||||
user_agent = request.headers.get("user-agent", "")[:200]
|
||||
logger.warning(
|
||||
"DEBUG_AUTH_TOKEN bypass active — request from %s to %s",
|
||||
client, request.url.path,
|
||||
client, path,
|
||||
)
|
||||
# Best-Effort-Logging in DB (synchron, fire-and-forget).
|
||||
# Schlägt unter keinen Umständen den Request fehl.
|
||||
try:
|
||||
import sqlite3
|
||||
from .config import settings
|
||||
conn = sqlite3.connect(str(settings.db_path), timeout=2)
|
||||
try:
|
||||
conn.execute(
|
||||
"INSERT INTO auth_bypass_uses (client_ip, path, user_agent) "
|
||||
"VALUES (?, ?, ?)",
|
||||
(client, path, user_agent),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
except Exception:
|
||||
pass # Logging-Fehler nie an User propagieren
|
||||
return {
|
||||
"sub": "debug-user",
|
||||
"email": "debug@local",
|
||||
|
||||
@ -363,6 +363,22 @@ async def init_db():
|
||||
"ON auto_rate_runs(started_at DESC)"
|
||||
)
|
||||
|
||||
# auth_bypass_uses (Phase 11b) — Tracking jeder Verwendung des
|
||||
# DEBUG_AUTH_TOKEN-Bypass (siehe app/auth.py:_check_debug_token).
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS auth_bypass_uses (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
used_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
client_ip TEXT,
|
||||
path TEXT NOT NULL,
|
||||
user_agent TEXT
|
||||
)
|
||||
""")
|
||||
await db.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_auth_bypass_used "
|
||||
"ON auth_bypass_uses(used_at DESC)"
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
|
||||
|
||||
|
||||
36
scripts/rotate-debug-token.sh
Executable file
36
scripts/rotate-debug-token.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Auto-Rotation des DEBUG_AUTH_TOKEN-Bypass-Secrets (Phase 11b).
|
||||
#
|
||||
# Generiert wöchentlich ein neues Secret, schreibt es in
|
||||
# /opt/gwoe-antragspruefer-dev/.env und re-creates den Container, damit
|
||||
# die ENV-Änderung greift.
|
||||
#
|
||||
# Cron (Sonntag 04:00):
|
||||
# 0 4 * * 0 /opt/gwoe-antragspruefer-dev/scripts/rotate-debug-token.sh \
|
||||
# >> /var/log/gwoe-rotate-debug.log 2>&1
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ENV_FILE="/opt/gwoe-antragspruefer-dev/.env"
|
||||
COMPOSE_FILE="/opt/gwoe-antragspruefer-dev/docker-compose.dev.yml"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "$(date -Iseconds) FAIL — $ENV_FILE not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_TOKEN=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
|
||||
|
||||
# Bestehenden Eintrag entfernen, neuen anhängen — atomar via temp-Datei
|
||||
TMP=$(mktemp)
|
||||
grep -v "^DEBUG_AUTH_TOKEN=" "$ENV_FILE" > "$TMP"
|
||||
echo "DEBUG_AUTH_TOKEN=$NEW_TOKEN" >> "$TMP"
|
||||
mv "$TMP" "$ENV_FILE"
|
||||
|
||||
echo "$(date -Iseconds) ROTATED — new token written to $ENV_FILE"
|
||||
|
||||
# Container re-creates (compose liest .env nur beim Container-Create).
|
||||
cd /opt/gwoe-antragspruefer-dev
|
||||
docker compose -f "$COMPOSE_FILE" up -d --force-recreate
|
||||
|
||||
echo "$(date -Iseconds) END"
|
||||
Loading…
Reference in New Issue
Block a user