Files
astrololo/docs/konta-i-audyt.md
T
gitea c6b6f43cb9
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m27s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 7s
feat(bezpieczeństwo): konta imienne i dziennik audytowy (PRE-17)
Jedno wspólne hasło nie mówiło, KTO sięgał do baz, a odebranie dostępu jednej
osobie wymagało zmiany hasła wszystkim. Przy bazach o realnej wartości handlowej
to za mało.

KONTA IMIENNE: `APP_USERS='alicja:scrypt$…,bartek:scrypt$…'`. Hash liczy scrypt ze
STDLIB — zero nowych zależności; hasła nie ma w konfiguracji jawnie. Zakładanie
konta: scripts/make_user.py (hasło interaktywnie, nie w historii powłoki).
Odebranie dostępu = usunięcie wpisu, reszta nie zmienia haseł.

Gdy APP_USERS jest ustawione, wspólne APP_PASSWORD PRZESTAJE działać (ostrzeżenie
przy starcie) — działające obok kont byłoby tylnym wejściem bez śladu w dzienniku.
Dopóki APP_USERS nie jest ustawione, stary tryb działa jak dotąd (zgodność wstecz).

DZIENNIK AUDYTOWY: każde żądanie zostawia wpis „kto, skąd, co, status, ILE
rekordów, ile ms". Liczba rekordów jest tu sednem — pojedyncze zapytanie wygląda
niewinnie, suma pokazuje powolne wypompowywanie bazy przez osobę uprawnioną.
Liczona dla wyszukiwarki sygnifikatorów, raportu i eksportu do Excela (ten wynosi
najwięcej naraz). W logach NIE MA treści — ani rekordów, ani promptów.

Dwa realne błędy złapane po drodze:
- `secrets.compare_digest` rzuca TypeError na znakach spoza ASCII, więc hasło z
  polskimi literami wywracało logowanie błędem 500 zamiast odmowy (błąd ZASTANY,
  sprzed tej zmiany) — porównujemy teraz bajty;
- dziennik był PUSTY na żywym serwerze: domyślna konfiguracja uvicorna nie
  obsługuje naszych loggerów. Niewidoczny dziennik jest gorszy niż jego brak,
  więc audyt dostał własny handler na stdout. Oba przypadki mają testy regresji.

Instrukcja wdrożeniowa: docs/konta-i-audyt.md. Testy: +15. Prezentacja 243.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 21:47:18 +02:00

2.5 KiB

Konta imienne i dziennik audytowy (PRE-17)

Zamiast jednego wspólnego hasła: konta imienne, bo przy bazach o realnej wartości handlowej trzeba wiedzieć kto sięgał do treści — i móc odciąć jedną osobę bez zmiany hasła całej reszcie.

Zakładanie konta

Hasło podajesz interaktywnie (nie trafia do historii powłoki ani do listy procesów); na wyjściu dostajesz hash, nie hasło:

cd services/presentation && python scripts/make_user.py alicja

Wynik wklejasz do APP_USERS (wpisy po przecinku):

APP_USERS='alicja:scrypt$…,bartek:scrypt$…'

Hash liczy scrypt ze stdlib — bez nowych zależności. Sekret ustawiasz jak resztę (kubectl create secret …, secretKeyRef), nigdy w repo GitOps.

Odebranie dostępu jednej osobie

Usuń jej wpis z APP_USERS i zrestartuj presentation. Pozostali nie zmieniają haseł — to była główna bolączka wspólnego hasła.

Uwaga: wspólne hasło przestaje działać

Gdy APP_USERS jest ustawione, stare APP_PASSWORD nie działa (aplikacja zgłasza to ostrzeżeniem przy starcie). Celowo: działające obok kont wspólne hasło byłoby tylnym wejściem bez śladu w dzienniku, czyli dokładnie problemem, który to wymaganie zamyka. Po migracji usuń APP_PASSWORD z konfiguracji.

Zgodność wstecz: dopóki APP_USERS nie jest ustawione, APP_USER/APP_PASSWORD działa jak dotąd — aktualizacja nie wywraca istniejącego wdrożenia.

Dziennik audytowy

Każde żądanie do chronionej ścieżki zostawia wpis na stdout (w k8s zbierany standardowo):

2026-08-03 21:45:44 INFO AUDYT user=alicja ip=10.1.2.3 method=POST path=/interpret status=200 records=428 ms=1530
Pole Znaczenie
user kto (- przy nieudanym logowaniu — nie podpowiadamy, które konto istnieje)
path, method, status co robił i z jakim skutkiem
records ile rekordów baz oddaliśmy (- gdy żądanie nie dotyka baz)
ms czas obsługi

records jest tu najważniejsze: pojedyncze zapytanie wygląda niewinnie, ale suma pokazuje powolne wypompowywanie bazy przez osobę uprawnioną — czego żadne uwierzytelnienie nie wykryje. Liczone m.in. dla wyszukiwarki sygnifikatorów, raportu interpretacji i eksportu do Excela (ten wynosi najwięcej naraz).

W dzienniku nie ma treści — ani rekordów, ani promptów, ani danych urodzeniowych. Logi byłyby kolejnym nośnikiem wycieku; do wykrycia nadużycia wystarczą metadane i liczby.

Poziom sterujesz przez AUDIT_LEVEL (domyślnie INFO).