diff --git a/docs/dan25-zabezpieczenie-nfs.md b/docs/dan25-zabezpieczenie-nfs.md new file mode 100644 index 0000000..923500f --- /dev/null +++ b/docs/dan25-zabezpieczenie-nfs.md @@ -0,0 +1,195 @@ +# DAN-25 — zamknięcie dostępu do baz na NFS (TrueNAS SCALE) + +Bazy interpretacyjne leżą na `192.168.1.34:/mnt/Tank1/astrololo`. Dziś udział jest +osiągalny z całej sieci, więc **kto ma dostęp do LAN, bierze kompletne bazy +w oryginale — z pominięciem logowania, limitów, audytu i canary**. Żadne +zabezpieczenie w kodzie tego nie zamyka: to najkrótsza droga do wycieku. + +Cel: udział `astrololo` widoczny **tylko dla trzech węzłów k3s**, **tylko do +odczytu**, z **root_squash**. + +## ⚠️ Zasada nadrzędna: ruszamy WYŁĄCZNIE udział astrololo + +Tank1 obsługuje cały homelab — Proxmox (`proxmox-NFS`), conjurera (`conjurer_swap`, +z **zapisem**), media, LXC-e, stację roboczą. **Nie dotykamy globalnych ustawień +usługi NFS ani innych udziałów** — inaczej wywalimy VM-y, bota i bibliotekę mediów. +Każda komenda niżej celuje w jeden konkretny udział. + +Druga zasada: **w TrueNAS SCALE nie edytuje się `/etc/exports` ręcznie.** Plik +generuje middleware i nadpisze każdą ręczną zmianę. Wszystko robimy przez `midclt` +(albo GUI: *Shares → Unix (NFS) Shares*). + +## Ustalone dane + +| Co | Wartość | +|---|---| +| NAS | `192.168.1.34` (TrueNAS SCALE / Community Edition) | +| Udział do zamknięcia | `/mnt/Tank1/astrololo` | +| Węzły k3s (jedyni uprawnieni) | `192.168.1.73` (server), `192.168.1.80` (agent2), `192.168.1.81` (agent1) | +| Kto montuje astrololo | wyłącznie pod `data` w ns `astrololo`, **read-only** | + +--- + +## Faza 0 — rozpoznanie (nic nie zmienia) + +```bash +ssh admin@192.168.1.34 +``` + +Wersja systemu (potwierdza, że komendy niżej pasują): + +```bash +midclt call system.version +``` + +Lista udziałów NFS z ich obecnymi ustawieniami — **stąd bierzemy ID udziału astrololo**: + +```bash +midclt call sharing.nfs.query | python3 -m json.tool +``` + +> W wyniku poszukaj wpisu ze ścieżką `/mnt/Tank1/astrololo` i zapamiętaj jego `id`. +> **Sprawdź też, jak nazywają się pola** (`path` vs `paths`, `hosts`, `networks`, +> `ro`, `maproot_user`, `mapall_user`) — middleware zmieniało ich nazwy między +> wersjami SCALE. Dalsze komendy używają nazw z Twojego wyniku. + +Kto jest teraz podłączony (żeby nie odciąć czegoś w trakcie pracy): + +```bash +ss -tn state established '( sport = :2049 )' +``` + +## Faza 1 — dowód dziury (zrób PRZED zmianą) + +Na **stacji roboczej** (Mac mini, czyli host spoza klastra): + +```bash +mkdir -p /tmp/nfs-test && sudo mount -t nfs -o ro,vers=3 192.168.1.34:/mnt/Tank1/astrololo /tmp/nfs-test +``` + +```bash +ls -la /tmp/nfs-test | head +``` + +Jeśli widzisz pliki baz — **to jest dokładnie problem, który zamykamy**. Odmontuj: + +```bash +sudo umount /tmp/nfs-test +``` + +## Faza 2 — kopia obecnej konfiguracji (możliwość cofnięcia) + +Na NAS-ie, podstaw `` z Fazy 0: + +```bash +midclt call sharing.nfs.query '[["id","=",]]' > /root/astrololo-nfs-share.backup.json && cat /root/astrololo-nfs-share.backup.json +``` + +## Faza 3 — zawężenie udziału + +Jedna komenda ustawia wszystkie trzy zabezpieczenia naraz: listę hostów, tylko +odczyt i root_squash. Podstaw ``: + +```bash +midclt call sharing.nfs.update '{"hosts": ["192.168.1.73", "192.168.1.80", "192.168.1.81"], "ro": true, "maproot_user": null, "maproot_group": null, "mapall_user": null, "mapall_group": null}' +``` + +Co robi każdy element: + +| Ustawienie | Znaczenie | +|---|---| +| `hosts` | eksport **tylko** dla trzech węzłów k3s — reszta LAN przestaje widzieć udział | +| `ro: true` | tylko odczyt; aplikacja i tak montuje read-only, więc niczego nie łamie | +| `maproot_*`, `mapall_*` = `null` | **root_squash**: root z klienta nie jest rootem na udziale | + +Zastosuj i sprawdź, że middleware przepisał eksporty: + +```bash +midclt call service.reload nfs && exportfs -v | grep -A1 astrololo +``` + +> Jeśli Twoja wersja nie ma `service.reload`, użyj GUI (*Shares → NFS → zapisz*), +> co wymusi to samo. + +## Faza 4 — weryfikacja (wszystkie cztery testy) + +**1. Spoza klastra ma NIE działać.** Na Macu: + +```bash +sudo mount -t nfs -o ro,vers=3 192.168.1.34:/mnt/Tank1/astrololo /tmp/nfs-test +``` + +Oczekiwane: `access denied` / `Operation not permitted`. **Jeśli montuje się dalej — +zmiana nie zadziałała, nie idź dalej.** + +**2. Z węzła klastra ma działać.** + +```bash +ssh 192.168.1.73 'sudo mount -t nfs -o ro 192.168.1.34:/mnt/Tank1/astrololo /mnt/test && ls /mnt/test | head -3 && sudo umount /mnt/test' +``` + +**3. Aplikacja żyje.** Pody muszą wstać i realnie czytać bazy: + +```bash +kubectl -n astrololo rollout restart deploy/data && kubectl -n astrololo rollout status deploy/data +``` + +```bash +kubectl -n astrololo exec deploy/data -- ls /app/data_files | head -3 +``` + +**4. Reszta homelabu nietknięta** — conjurer (zapis!) i pozostałe udziały: + +```bash +kubectl -n conjurer get pods +``` + +```bash +midclt call sharing.nfs.query | python3 -c "import sys,json;[print(s.get('path') or s.get('paths'), '| hosts:', s.get('hosts'), '| ro:', s.get('ro')) for s in json.load(sys.stdin)]" +``` + +Oczekiwane: **tylko** astrololo ma zawężone `hosts` i `ro: true`; reszta bez zmian. + +## Faza 5 — wycofanie (gdyby coś padło) + +```bash +midclt call sharing.nfs.update '{"hosts": [], "ro": false}' +``` + +```bash +midclt call service.reload nfs +``` + +To przywraca poprzedni stan (pełna kopia w `/root/astrololo-nfs-share.backup.json`). + +--- + +## Pułapki, o których warto wiedzieć + +**Hookscript Proxmoxa.** Na Proxmoxie działa `wait-truenas.sh`, który przed startem +VM czeka w pętli na `showmount -e 192.168.1.34`. Zawężamy tylko udział astrololo, +więc `showmount` nadal zwróci pozostałe eksporty i pętla przejdzie. Mimo to sprawdź +po zmianie: + +```bash +ssh root@pve2 'showmount -e 192.168.1.34' +``` + +**Aktualizacja baz przestanie działać przez NFS.** Po `ro: true` nikt nie wgra +nowych plików baz przez ten udział — również Ty. Do wgrywania użyj GUI TrueNAS, +SMB albo SSH bezpośrednio na NAS-ie. To celowe: udział ma być drogą tylko do +czytania przez aplikację. + +**`hosts` przyjmuje adresy IP, nie nazwy** — świadomie, żeby dostęp nie zależał od +DNS-u (AdGuard na `.57`). Gdyby doszedł czwarty węzeł k3s, trzeba dopisać jego IP, +inaczej pod `data` na nim nie wstanie. + +**To nie jest uwierzytelnianie.** Lista IP zatrzymuje przypadkowy i oportunistyczny +dostęp, ale adres da się podszyć w tej samej sieci. Docelowo (poza zakresem tego +kroku): NFSv4 + Kerberos albo przeniesienie plików na wolumen nieosiągalny poza +klastrem — tak mówi samo wymaganie DAN-25. + +## Po wykonaniu + +Zaktualizuj status DAN-25 w `docs/astrololo_wymagania.xlsx` na **Zrobione** (albo +**W trakcie**, jeśli zostawiasz Kerberosa jako etap docelowy).