astroklient: wdrożenie warstwy pośredniej z własnym stosem danych (5/5)
Domyka drabinę produktów: astrodemo (dwie funkcje) → astroklient → astrololo. Host astroklient.czernobog.pl, obraz astrololo-astroklient, port 8006. WŁASNY STOS, NIE WSPÓLNY. Nowa para data-astroklient + logic-astroklient i nowy udział /mnt/Tank1/astrololo-klient. Pule kont izolują klientów od siebie w każdym wariancie, ale to izolacja PROGRAMOWA — opiera się na poprawności mechanizmu pul. Granica na poziomie systemu plików nie zależy od tego, czy w kodzie niczego nie przeoczono, a przy sprzątaniu demo nie da się przez pomyłkę skasować cudzych danych, bo leżą gdzie indziej. Klaster ma zapas (węzły na 24–38% pamięci), więc koszt dwóch podów nie był argumentem przeciw. Silnik własny (permisywny) — silnik B (AGPL) nie wchodzi do produktu oddawanego klientom. data-astroklient dostaje nodeAffinity na etykietę zdolności procesora, jak pozostałe warstwy danych: ciągnie pandas, a przez nią NumPy z bazą x86-64-v2. WPIS W LIŚCIE OBSERWOWANYCH OBRAZÓW od razu, z komentarzem dlaczego. Bez niego usługa nie deployuje się sama: obraz powstaje w rejestrze, kustomization zostaje na starym tagu, i wygląda to na zepsute CI. Tak zawisł kiedyś render. Certyfikat obejmuje trzeci host; DNS już wskazuje (wildcard). RUNBOOK: udział NFS ze WSZYSTKIMI CZTEREMA węzłami, konta jako hashe scrypt, własny SESSION_SECRET i własna nazwa ciasteczka (trzy produkty nie mają powodu uznawać nawzajem swoich sesji), unieważnianie dostępu bez wolumenu stanu, oraz sprawdzenie po wdrożeniu. W sprawdzeniu poprawiona rzecz, którą najpierw napisałem błędnie: BEZ SESJI każdy adres oddaje 303, także nieistniejący, bo bramka logowania działa przed trasowaniem. Pętla curl bez ciasteczka pokazywałaby 303 dla wszystkiego i sugerowała, że nieobecne ekrany „są". Sprawdzenie ma sens dopiero z sesją — i wtedy dają 404, nie 403. Zweryfikowane: kustomize build (37 obiektów), dry-run serwerowy przyjmuje wszystkie osiem nowych obiektów, kody odpowiedzi sprawdzone na złożonym drzewie. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit was merged in pull request #26.
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# Astroklient — wdrożenie warstwy pośredniej
|
||||
|
||||
Pełne funkcje astrologiczne, bez generowania tekstu i bez administracji.
|
||||
Trzeci produkt drabiny: **astrodemo** (dwie funkcje) → **astroklient** → **astrololo**.
|
||||
|
||||
Host: `astroklient.czernobog.pl` · obraz `astrololo-astroklient` · port 8006.
|
||||
|
||||
## Jak to jest odizolowane
|
||||
|
||||
Trzy granice, w kolejności od najmocniejszej:
|
||||
|
||||
**Obraz.** Plików ekranów, których ten produkt nie ma, NIE MA w obrazie — usuwa
|
||||
je `usun.txt` przy budowaniu. Nie ma więc czego wyłączać ani czym odsłaniać:
|
||||
uprawnienia liczą się z katalogu funkcji, a katalog składa się ze zgłoszeń
|
||||
ekranów obecnych w obrazie. Test w repo aplikacji sprawdza to na złożonym
|
||||
drzewie, razem z zaporą słownikową — po nieobecnych funkcjach nie zostaje nawet
|
||||
słowo w komentarzu.
|
||||
|
||||
**Udział NFS.** Własny `astrololo-klient`, osobny od produkcyjnego i od demo.
|
||||
Pule kont izolują klientów od siebie, ale to izolacja PROGRAMOWA — opiera się na
|
||||
poprawności mechanizmu pul. Granica na poziomie systemu plików nie zależy od
|
||||
tego, czy w kodzie niczego nie przeoczono. Przy sprzątaniu demo nie da się przez
|
||||
pomyłkę skasować cudzych danych, bo leżą gdzie indziej.
|
||||
|
||||
**Warstwa danych i logiki.** Własna para `data-astroklient` + `logic-astroklient`,
|
||||
z silnikiem własnym (permisywnym) — silnik B (AGPL) nie wchodzi do produktu
|
||||
oddawanego klientom.
|
||||
|
||||
---
|
||||
|
||||
## Krok 1 — udział `astrololo-klient` na TrueNAS
|
||||
|
||||
```bash
|
||||
midclt call sharing.nfs.create '{
|
||||
"path": "/mnt/Tank1/astrololo-klient",
|
||||
"hosts": ["192.168.1.73", "192.168.1.80", "192.168.1.81", "192.168.1.82"],
|
||||
"maproot_user": "root", "maproot_group": "root", "enabled": true
|
||||
}'
|
||||
midclt call service.restart nfs
|
||||
```
|
||||
|
||||
**Wszystkie CZTERY węzły.** Klaster ma cztery (`kubectl get nodes -o wide`), a nie
|
||||
trzy — pominięcie jednego daje `access denied by server` dopiero wtedy, gdy
|
||||
scheduler tam coś postawi, czyli w losowym momencie tygodnie później.
|
||||
|
||||
Kontrolę wyłapującą braki i literówki w adresach masz w
|
||||
[README.md](README.md) → „Kontrola: czy każdy udział obejmuje każdy węzeł".
|
||||
|
||||
Jeśli katalog jeszcze nie istnieje, utwórz dataset przed eksportem.
|
||||
|
||||
## Krok 2 — konta klientów
|
||||
|
||||
Każde konto to osobna pula, więc **rozdajesz konta, nie jedno hasło**.
|
||||
Wszystkie mają ten sam poziom dostępu — konta rozdziela się dla rozdzielenia
|
||||
plików, nie uprawnień.
|
||||
|
||||
```bash
|
||||
# skrypt w repo aplikacji; format hasha wspólny dla wszystkich usług
|
||||
python services/presentation/scripts/make_user.py klientA # wypisze: scrypt$…
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo create secret generic astrololo-astroklient \
|
||||
--from-literal=ASTROKLIENT_USERS='klientA:scrypt$…,klientB:scrypt$…' \
|
||||
--from-literal=SESSION_SECRET="$(openssl rand -hex 32)"
|
||||
```
|
||||
|
||||
`SESSION_SECRET` jest **własny**, nie ten z pełnej aplikacji ani z demo: trzy
|
||||
produkty nie mają powodu uznawać nawzajem swoich sesji. Ciasteczko też ma własną
|
||||
nazwę (`astroklient_sesja`), więc logowanie do jednego nie wyrzuca z drugiego.
|
||||
|
||||
**Pod bez `SESSION_SECRET` celowo nie wstanie** — logowanie bez klucza podpisu
|
||||
nie miałoby czym się bronić.
|
||||
|
||||
### Unieważnienie dostępu
|
||||
|
||||
Nie ma wolumenu stanu, więc nie ma licznika pokolenia sesji. Zamiast tego:
|
||||
|
||||
- usunięcie konta z `ASTROKLIENT_USERS` albo zmiana jego hasła **natychmiast ubija
|
||||
jego otwarte sesje** — odcisk poświadczenia w ciasteczku przestaje pasować,
|
||||
- rotacja `SESSION_SECRET` wylogowuje wszystkich naraz.
|
||||
|
||||
**Pula zostaje na udziale.** Odebranie dostępu nie kasuje plików klienta —
|
||||
przestaje być tylko komu je pokazywać.
|
||||
|
||||
### Dodanie konta później
|
||||
|
||||
```bash
|
||||
STARE=$(kubectl -n astrololo get secret astrololo-astroklient -o jsonpath='{.data.ASTROKLIENT_USERS}' | base64 -d)
|
||||
|
||||
kubectl -n astrololo create secret generic astrololo-astroklient \
|
||||
--from-literal=ASTROKLIENT_USERS="${STARE},klientC:scrypt\$…" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
kubectl -n astrololo rollout restart deploy/astroklient
|
||||
```
|
||||
|
||||
## Krok 3 — wdrożenie
|
||||
|
||||
Sekret i udział **muszą istnieć wcześniej**. Potem wystarczy merge do `master` —
|
||||
ArgoCD zsynchronizuje, a image-updater będzie odtąd podbijał tag sam, bo obraz
|
||||
jest dopisany do [`image-updater.yaml`](image-updater.yaml).
|
||||
|
||||
## Sprawdzenie po wdrożeniu
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo get pods -l app=astroklient -o wide
|
||||
kubectl -n astrololo logs -l app=astroklient --tail=30
|
||||
curl -sk https://astroklient.czernobog.pl/ -o /dev/null -w '%{http_code}\n' # 303 → bramka logowania odpowiada
|
||||
```
|
||||
|
||||
Po zalogowaniu w nawigacji ma być **sześć** pozycji: Horoskop, Interpretacje,
|
||||
Kalendarz, Synastria, Sygnifikatory, Pliki.
|
||||
|
||||
**Bez zalogowania każdy adres oddaje 303** — także nieistniejący. Bramka
|
||||
logowania działa przed trasowaniem, więc niezalogowany nie wyczyta z kodów
|
||||
odpowiedzi, które ekrany istnieją. Sprawdzanie nieobecnych adresów bez sesji nic
|
||||
więc nie mówi: pokaże 303 dla wszystkiego, łącznie z `/nie-ma-takiego-ekranu`.
|
||||
|
||||
Sprawdzenie ma sens dopiero Z SESJĄ, i wtedy nieobecne ekrany dają **404, nie
|
||||
403** — odmowa z powodem byłaby informacją, że coś tam jest:
|
||||
|
||||
```bash
|
||||
CIASTKO='astroklient_sesja=<wartość z przeglądarki po zalogowaniu>'
|
||||
for A in / /compile /settings /accounts /files; do
|
||||
printf "%-12s %s\n" "$A" \
|
||||
"$(curl -sk -o /dev/null -w '%{http_code}' -H "Cookie: $CIASTKO" https://astroklient.czernobog.pl$A)"
|
||||
done
|
||||
# oczekiwane: / → 200, reszta → 404
|
||||
```
|
||||
|
||||
## Import puli klienta do pełnej aplikacji
|
||||
|
||||
Pula to zwykły katalog na udziale — kopiuje się go tak samo jak w demo,
|
||||
patrz [README-astrodemo.md](README-astrodemo.md) → „Import puli klienta".
|
||||
Ścieżka źródłowa to `/mnt/Tank1/astrololo-klient/<login>`.
|
||||
Reference in New Issue
Block a user