diff --git a/persistent-memory.md b/persistent-memory.md index 94d877d..df2854c 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -185,6 +185,7 @@ Every vLLM seat on a shared card (GPU 0, GPU 1) has byte-pinned KV (`--kv-cache- ## Recent decisions +- `[2026-10-16]` **albok unit 6: the first encrypted wing `personal/sealed` provisioned on nh3-albok** (Prime's goal "land all of u6", via albok-dev): a 20 GiB LUKS2 file + ext4, key ONLY in vault `albok/wing-key-personal-sealed`, gid 1513, mountpoint `/srv/albok/sealed/personal.sealed` (immutable while unmounted), the parent bound rslave. The lock/unlock lifecycle was tested with the container running. It is not in albok.yaml until albok-dev's release. Runbook: `stacks/albok-service/README.md` § Sealed. After an nh3-albok reboot the wing is LOCKED until someone unlocks it. - `[2026-10-13]` **pewpewstudio LIVE on nh3-docker :8185** (Prime via pewpew-dev): api + Caddy front; the Host allowlist must sit in a `route` (foreign Host 400); DB, assets and shop config on named volumes. → `stacks/pewpewstudio/README.md` - `[2026-10-13]` **infra-ops on esh-nas (CT 103) + per-host satellite keys (Prime)** — bootstrapped via pct from esh-pve-nas; satellite-1 authorized on esh-nas only (`playbooks/files/infra-ops-satellite-keys`); its login test + name pending. - `[2026-10-13]` **Worldtree memory gate: 0730 harness error (the tagger's MalformedClassification latched the writer), re-run `20261013T160414Z` PASS (median 0.83)** — the latch fix is worldtree-dev's (thread `01M4V035SF73XKVG3NRVX37XQ6`). diff --git a/stacks/albok-service/README.md b/stacks/albok-service/README.md index e3ba411..b9ef381 100644 --- a/stacks/albok-service/README.md +++ b/stacks/albok-service/README.md @@ -184,3 +184,32 @@ docker push gitea.phasefinal.com/pfi/albok-service: # then pin the new Mount `/srv/albok/store` **`:ro`**, `group_add` the read group's **numeric** gid (1510 / 1511), set `GIT_OPTIONAL_LOCKS=0`, and add `safe.directory` for the path as the viewer sees it. Nothing else may mount the store read-write. + +## Sealed (encrypted) wings: unit 6 (2026-10-16) + +The first is `personal/sealed`: restricted, default-deny, gid **1513 `albok-sealed`**. It is empty, has no Nemi source, +and what goes in it is Prime's call. albok-dev provisioned it on Prime's goal "land all of u6". **It is not yet in +`albok.yaml`**: albok-dev sends that stanza with the release that carries the encrypted-wing replay fix. Until then the +service ignores the mount. + +| | | +|---|---| +| container | `/srv/albok/luks/personal.sealed.img`: a 20 GiB file (root 0600, dir 0700), LUKS2 aes-xts, ext4 inside (label `personal.sealed`). The file grows later with `truncate` + `cryptsetup resize` + `resize2fs` | +| key | vault **`albok/wing-key-personal-sealed`** (64 random base64 chars). It is never written to nh3-albok's disk: it is piped in over ssh, and infra-ops' sudo there logs output, not input | +| mapping | `/dev/mapper/albok-personal-sealed` | +| mountpoint | **`/srv/albok/sealed/personal.sealed`**: EMPTY and `chattr +i` while unmounted, so nothing can write plaintext into a locked wing (root's `touch` there fails, tested). The mounted root is `1500:1513 0750`, holding `.albok-wing` (`1500:1513 0640`) and ext4's `lost+found`. The service creates `store/` and `private/` there on its first start with the wing configured | +| container view | the parent `/srv/albok/sealed` is bound with `propagation: rslave`, so a lock or unlock on the host shows inside the RUNNING container (tested both ways) | + +```bash +# UNLOCK (after a VM reboot the wing comes up LOCKED, by design: no crypttab). No service restart is needed. +secret get albok/wing-key-personal-sealed | tr -d '\n' | ssh infra-ops@10.100.50.44 \ + 'sudo -n cryptsetup open --type luks2 --key-file=- /srv/albok/luks/personal.sealed.img albok-personal-sealed \ + && sudo -n mount /dev/mapper/albok-personal-sealed /srv/albok/sealed/personal.sealed' +# LOCK: the service holds the wing's SQLite/Chroma open, so umount refuses while it runs. +ssh infra-ops@10.100.50.44 'cd /opt/docker/compose/albok-service && sudo -n docker compose stop \ + && sudo -n umount /srv/albok/sealed/personal.sealed && sudo -n cryptsetup close albok-personal-sealed \ + && sudo -n docker compose start' +``` +**Backups:** nh3-albok has NO file-level backup, so nothing ever copies the plaintext. Its whole-VM vzdump (nh3-pve-2, +21:30) holds the LUKS file, which is ciphertext; the key lives only in the vault. Never add a file-level job that walks +`/srv/albok/sealed`. ⚠ Losing the vault entry loses the wing. diff --git a/stacks/albok-service/compose.yaml b/stacks/albok-service/compose.yaml index eb4fedf..020f4bf 100644 --- a/stacks/albok-service/compose.yaml +++ b/stacks/albok-service/compose.yaml @@ -13,6 +13,7 @@ # ⚠ Nothing else may mount /srv/albok/store read-write. Viewers mount it :ro with group_add by gid # (1510 albok-read, 1511 albok-personal) and need GIT_OPTIONAL_LOCKS=0 + a safe.directory entry. # 1512 albok-feedback (restricted wing personal/agent-feedback) is default-deny: no viewer gets it. +# 1513 albok-sealed (encrypted wing personal/sealed, unit 6) likewise; its plaintext exists only while unlocked. services: albok-service: image: gitea.phasefinal.com/pfi/albok-service:0.1.23@sha256:026de87f3ca3907e9eb0a2a2489a7507f69f9f0eca50e8e8be3fcfcb36a03de3 @@ -25,12 +26,20 @@ services: - "1510" - "1511" - "1512" # albok-feedback: restricted wing personal/agent-feedback + - "1513" # albok-sealed: encrypted wing personal/sealed (unit 6, 2026-10-16) volumes: - /srv/albok/store:/srv/albok/store - /srv/albok/private:/srv/albok/private - /srv/albok/etc/albok.yaml:/etc/albok/albok.yaml:ro # the read groups must RESOLVE BY NAME inside the container (layout.py uses grp.getgrnam) - /opt/docker/conf/albok-service/group:/etc/group:ro + # Unit 6 encrypted wings: the PARENT of the LUKS mountpoints, bound with slave propagation, so a wing unlocked + # (cryptsetup open + mount) after the container started is visible inside it without a restart (README § Sealed). + - type: bind + source: /srv/albok/sealed + target: /srv/albok/sealed + bind: + propagation: rslave mem_limit: 8g # 4g on nh3-docker (7.7 GiB shared host); 12 GiB VM to itself now healthcheck: test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8390/health', timeout=5).status == 200 else 1)"] diff --git a/stacks/albok-service/conf/group b/stacks/albok-service/conf/group index 1c57c28..bf8c850 100644 --- a/stacks/albok-service/conf/group +++ b/stacks/albok-service/conf/group @@ -40,3 +40,4 @@ albok:x:1500: albok-read:x:1510:albok albok-personal:x:1511:albok albok-feedback:x:1512:albok +albok-sealed:x:1513:albok