docs(auth): document runtime projection operations

This commit is contained in:
User
2026-08-22 01:51:26 +02:00
parent 3d9a9f0675
commit ef7ae7053c
10 changed files with 415 additions and 1 deletions
+11
View File
@@ -68,3 +68,14 @@ values into tickets, logs, or evidence.
Check readiness with `tht auth check`; add `--json` for the machine contract. Use
`tht doctor --json` for the aggregate installation report.
## Projected server installations
This section applies only when a Linux `profile: server` descriptor declares a runtime projection.
The canonical authentication root stays root-owned and is the only authority. The container reads
only the separate read-only runtime projection selected by `CURRENT`; it never falls back to the
canonical files or to a previous generation. Run projected mutations and repairs through the
root-operated `tht` commands documented in the [server guide](server.md), and never edit runtime
files directly.
Mac, Windows, and local direct-file authentication remain unchanged when the projection is absent.
@@ -8,7 +8,13 @@ workspaceRepository:
branch: main
access: ssh
authentication:
configDirectory: "/absolute/path/to/thothii-auth"
# Root-operated source of truth; it is never mounted into core.
configDirectory: "/srv/example/thothii/auth-canonical"
runtimeProjection:
# The only authentication bind exposed to core by the automatic override.
directory: "/srv/example/thothii/auth-runtime"
uid: 10001
gid: 10001
overrides:
- "/absolute/path/to/ThothII/deploy/compose.session-server.yaml.example"
- "/absolute/path/to/ThothII/deploy/compose.git-ssh.yaml"
+67
View File
@@ -88,6 +88,73 @@ Expected: the parent is `operator_uid:10001 750`; source/operator are
`10001:10001 750`; backups are `0:0 700`. Re-run the empty `getent` checks after creation. Do not
make `/srv/thothii` a shared application directory.
## Projected server authentication: canonical root and runtime projection
For a server descriptor that declares `authentication.runtimeProjection`, authentication has two
different roots. The **canonical authentication root** (`authentication.configDirectory`) is the
root-operated source of truth. It and its regular files are `root:root 0700/0600`. The **runtime
projection** is a separate Linux-only tree for the container reader: its root, `generations`, and
generation directories are `10001:10001 0700`; `CURRENT`, `manifest.json`, `auth.yaml`, and (for
local mode) `users.yaml` are `10001:10001 0600`. The publisher assigns the numeric IDs directly;
it does not create a host user or group for 10001.
The runtime projection has only `CURRENT` and `generations/<64-lowercase-hex>/`. `CURRENT` selects
one complete immutable generation. A successful configure, user mutation, restore, or explicit
publish first blocks `CURRENT`, then verifies a new immutable generation, then makes it ready.
The selected generation and up to two predecessor generations are retained; no operator edits a
generation or `CURRENT` directly. A ready projection is usable only when its canonical revision is
equal to the current canonical authentication root. If the runtime projection is blocked, missing,
tampered, or unequal, `start`, `update --check-only`, `auth check`, and `doctor` fail closed before
admission or Compose lifecycle work.
The runtime directory must be an absolute canonical path, distinct from the canonical root, and
must exactly equal `THT_AUTH_RUNTIME_ROOT` in the protected installation environment. The server
profile and numeric UID/GID values are validated before any projected mutation or publication.
The descriptor loader adds `compose.auth-runtime-projection.yaml` automatically when
`runtimeProjection` is present; do not list that file under `overrides`. The automatic override
mounts the runtime projection **read-only and core-only** at `/run/thothii-auth`; the canonical
authentication root is never mounted. No other service receives that mount or
`THT_AUTH_RUNTIME_PROJECTION_ROOT`. The example descriptor uses
`/srv/example/thothii/auth-runtime` only as a replaceable path and contains no credential value.
This source change is prepared and tested only: Project A has not been started. It does not
authorize a raw Compose lifecycle launch, an Nginx change, legacy-stack change, or mutation of
`/srv`. A later manual gate needs separate explicit authorization before applying any descriptor
or runtime root to a server.
### Status, repair, and safe evidence
Use the root-operated installation command; retain only its small redacted JSON result:
```sh
sudo tht --installation "$INSTALLATION" auth status --json
```
`state: "ready"` and `equal: true` are required before a projected server can start. `state:
"blocked"`, `equal: false`, or a command refusal means that the runtime projection is blocked or
cannot be validated. Do not start the stack, inspect YAML, print an environment, or edit `CURRENT`
or a generation. Confirm the protected canonical root is available, then republish it with:
```sh
sudo tht --installation "$INSTALLATION" auth publish
sudo tht --installation "$INSTALLATION" auth status --json
```
`auth publish` reconstructs the selected immutable generation from the canonical root; it never
uses an older runtime generation as authority. If publish fails, leave the projection blocked and
escalate using the sanitized command result plus descriptor path and timestamp only. Do not attach
passwords, hashes, YAML, raw environment output, `nginx -T`, or a secret-bearing diff to evidence.
### Authentication restore
An authentication-bearing restore first publishes a blocked selector, restores canonical
authentication, and publishes a verified candidate generation before any restart. If candidate or
recovery verification fails, the verified recovery checkpoint is republished when possible; an
unverified result remains blocked and prevents start. A restore without authentication entries
does not touch the runtime projection. This is in addition to the normal restore requirement that
browser sessions and pending OIDC state are cleared.
## Firewall and network boundaries
Set `THOTH_SERVER_BIND=127.0.0.1`. Permit inbound TCP 80/443 only to the TLS proxy; port 80 should
@@ -251,6 +251,14 @@ Use `profile: server`, the exact new source root/env/auth root, workspace remote
access, Project A override, and exactly one Git transport override. Do not include the public
session-server overlay in Project A.
For the projected local-auth descriptor, keep `authentication.configDirectory` as the canonical
root and add `runtimeProjection` with a distinct absolute runtime directory plus numeric `uid: 10001`
and `gid: 10001`. The descriptor loader includes the automatic runtime-projection override; do
not list it manually under `overrides`. The canonical root stays `root:root 0700/0600`; the
publisher owns the projection numerically as `10001:10001 0700/0600`. Only the projection is
mounted read-only into core. Do not create a host user/group, edit `CURRENT` or `generations`, or
apply these paths before the separately authorized start gate.
**Step 4: Validate permissions and render**
```bash
@@ -274,6 +282,11 @@ Create a temporary mode-0600 password file using an echo-free prompt, then run:
Remove the temporary input file after success and record that removal. Do not delete generated
`auth.yaml` or `users.yaml`.
Before the later start gate, run the redacted projected status command and require `ready` plus
`equal: true`. A blocked result prevents start. `auth publish` is the only repair path: it rebuilds
from canonical authentication, including after a candidate or recovery restore outcome; it never
promotes a retained runtime generation on its own.
### Task 6: Build and start the clean stack
**Files:**
@@ -35,6 +35,13 @@ than inferring a PASS.
4. Confirm the exact direct `groups` claim for both identities and the mappings `TOT Users → user`
and `TOT Admin → admin`. Confirm extra upstream groups are ignored without warning.
5. For a projected Linux server, before any start gate, collect only the redacted result of
`sudo tht --installation "$INSTALLATION" auth status --json`. Record `state`, generation,
canonical revision, and `equal`; do not retain authentication YAML, user records, hashes, or
environment output. `ready` plus `equal: true` is required. A blocked or unequal result is a
fail-closed condition: do not start, and use `sudo tht --installation "$INSTALLATION" auth
publish` followed by the same status command only after the canonical root is available.
## Matrix
| Scenario | Expected result |
@@ -56,6 +63,7 @@ than inferring a PASS.
| Logout | Cookie expires and the server session is deleted. |
| Provider outage | Live check reports `oidc_discovery_unreachable`; browser login fails closed without exposing credentials. |
| Restore is completed | Sessions and OIDC state are absent; all users must reauthenticate. |
| Projected authentication restore | Candidate generation and any recovery generation are published from the canonical root; a failed verification remains blocked and start is refused. |
## Status at Task 15
@@ -29,6 +29,13 @@ verdi installazione, workspace, DWH, Qdrant, Ollama e preprocessing.
## 1. Stato generale
Prima del gate manuale di avvio, per una descriptor server con runtime projection eseguire solo il
controllo redatto `sudo tht --installation "$INSTALLATION" auth status --json`. Il risultato deve
dire `ready` ed `equal: true`. Se è `blocked`, mancante o diverso dal canonical root, non avviare:
Sol può eseguire `sudo tht --installation "$INSTALLATION" auth publish` e ripetere il controllo,
senza copiare YAML, hash, password, token o environment nel rapporto. Questo documento non
autorizza l'avvio; Project A resta soggetto a un'esplicita autorizzazione separata.
Eseguire:
```bash