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>
5.5 KiB
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
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 → „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ń.
# skrypt w repo aplikacji; format hasha wspólny dla wszystkich usług
python services/presentation/scripts/make_user.py klientA # wypisze: scrypt$…
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_USERSalbo zmiana jego hasła natychmiast ubija jego otwarte sesje — odcisk poświadczenia w ciasteczku przestaje pasować, - rotacja
SESSION_SECRETwylogowuje wszystkich naraz.
Pula zostaje na udziale. Odebranie dostępu nie kasuje plików klienta — przestaje być tylko komu je pokazywać.
Dodanie konta później
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.
Sprawdzenie po wdrożeniu
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:
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 → „Import puli klienta".
Ścieżka źródłowa to /mnt/Tank1/astrololo-klient/<login>.