fix(security): применить ревью PR #426 — route wrap + log rotation + base64 busybox + runbook log fix
- Caddyfile: обернуть gendsgn.ru и :80 в route { } — сохраняет порядок директив,
/health и /preview/* теперь действительно short-circuit до basic_auth
- Caddyfile: добавить roll_size 50MiB / roll_keep 5 / roll_keep_for 720h в gendsgn.ru.log
- scripts/auth/add_user.sh: заменить base64 -w 0 (GNU-only) на base64 | tr -d "\n"
(busybox-compatible, caddy:2 Alpine base image)
- docs/runbooks/basic_auth_management.md: убрать несуществующий auth_audit.log,
заменить на реальную команду grep по статусу 401 в gendsgn.ru.log
caddy validate: Valid configuration (confirmed locally via caddy:2 container).
Ref: #426 (comment)
This commit is contained in:
parent
b89b34c300
commit
cdce8e84a1
3 changed files with 72 additions and 57 deletions
20
Caddyfile
20
Caddyfile
|
|
@ -10,16 +10,26 @@
|
|||
# Auth gate: basic_auth for pilot phase (2026-05-23).
|
||||
# Users managed via caddy/users.caddy.snippet (git history = audit trail).
|
||||
# Public exclusions: /health (liveness probe), /preview/* (static mockups).
|
||||
#
|
||||
# IMPORTANT: route { } block is required to preserve directive order.
|
||||
# Without route { }, Caddy executes directives in hard-coded default order
|
||||
# (basic_auth runs before handle), making /health and /preview/* exclusions
|
||||
# ineffective. With route { }, handlers are matched top-to-bottom as written.
|
||||
|
||||
gendsgn.ru {
|
||||
encode zstd gzip
|
||||
|
||||
log {
|
||||
output file /var/log/caddy/gendsgn.ru.log
|
||||
output file /var/log/caddy/gendsgn.ru.log {
|
||||
roll_size 50MiB
|
||||
roll_keep 5
|
||||
roll_keep_for 720h
|
||||
}
|
||||
format json
|
||||
}
|
||||
|
||||
# Liveness probe — public, before auth (GHA deploy smoke check).
|
||||
route {
|
||||
# /health и /preview/* — public, без auth, short-circuit.
|
||||
handle /health {
|
||||
reverse_proxy backend:8000
|
||||
}
|
||||
|
|
@ -31,7 +41,7 @@ gendsgn.ru {
|
|||
file_server browse
|
||||
}
|
||||
|
||||
# Auth gate (applies to all routes not matched above).
|
||||
# Auth gate (applies to all routes below within this route block).
|
||||
import caddy/users.caddy.snippet
|
||||
|
||||
# Trade-In MVP subproject (tradein-mvp/) — gendesign-tradein docker stack,
|
||||
|
|
@ -62,6 +72,7 @@ gendsgn.ru {
|
|||
reverse_proxy frontend:3000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
www.gendsgn.ru {
|
||||
redir https://gendsgn.ru{uri} permanent
|
||||
|
|
@ -117,6 +128,8 @@ git.gendsgn.ru {
|
|||
:80 {
|
||||
encode zstd gzip
|
||||
|
||||
route {
|
||||
# /health — public, без auth (GHA deploy smoke check, liveness probe).
|
||||
handle /health {
|
||||
reverse_proxy backend:8000
|
||||
}
|
||||
|
|
@ -132,4 +145,5 @@ git.gendsgn.ru {
|
|||
reverse_proxy frontend:3000
|
||||
}
|
||||
}
|
||||
}
|
||||
# Test deploy flow 2026-05-15T21:43:32Z
|
||||
|
|
|
|||
|
|
@ -39,16 +39,13 @@ Caddy начнёт отклонять запросы этого юзера ср
|
|||
|
||||
## Аудит логи
|
||||
|
||||
- Access log: `/var/log/caddy/gendsgn.ru.log` (все запросы, JSON)
|
||||
- Auth audit: `/var/log/caddy/auth_audit.log` (authentication events, JSON)
|
||||
|
||||
- Access log: `/var/log/caddy/gendsgn.ru.log` (все запросы JSON, включая auth events).
|
||||
- Failed auth последние 100:
|
||||
```bash
|
||||
# Просмотр auth событий в реальном времени
|
||||
docker compose -f docker-compose.prod.yml exec caddy tail -f /var/log/caddy/auth_audit.log | jq
|
||||
|
||||
# Посмотреть кто логинился сегодня
|
||||
docker compose -f docker-compose.prod.yml exec caddy grep "$(date +%Y-%m-%d)" /var/log/caddy/auth_audit.log | jq '.user_id'
|
||||
docker compose -f docker-compose.prod.yml exec caddy \
|
||||
grep -P '"status":401' /var/log/caddy/gendsgn.ru.log | tail -100 | jq
|
||||
```
|
||||
- Phase 2 TODO: отдельный auth_audit.log + GlitchTip forwarder sidecar.
|
||||
|
||||
## Caddy reload после ручной правки на VPS
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,11 @@ fi
|
|||
# Caddy 2.11+ requires base64-encoded bcrypt in Caddyfile basic_auth.
|
||||
# Password passed via stdin to avoid exposure in process list.
|
||||
|
||||
HASH="$(printf '%s' "$PLAIN_PASS" | docker run --rm -i caddy:2 sh -c 'read -r p; caddy hash-password --plaintext "$p" | tr -d "\n" | base64 -w 0')"
|
||||
HASH="$(printf '%s' "$PLAIN_PASS" | docker run --rm -i caddy:2 sh -c '
|
||||
pass=$(cat)
|
||||
raw=$(caddy hash-password --algorithm bcrypt --plaintext "$pass")
|
||||
printf "%s" "$raw" | base64 | tr -d "\n"
|
||||
')"
|
||||
|
||||
if [[ -z "$HASH" ]]; then
|
||||
echo "ERROR: caddy hash-password returned empty hash" >&2
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue