Fix Directory topology: containers aren't hosts; bump submodules; docs

bootstrap.js no longer creates host_theta-proxy / host_theta-jump as
synthetic kind:'host' resources. Proxy and jump-host are containers running
on the one real stack host, not machines of their own -- and jump-host
resolves its SSH-reachable-hosts list from exactly kind:'host', so the
mistake wasn't just conceptual, it could offer unreachable SSH targets.
Their services now parent directly onto the stack host, like every other
component. Installs seeded between 2026-08-05 and this release self-heal on
the next ./setup.sh run: existing children are re-parented off the
synthetic hosts and the now-empty synthetic hosts are removed. Validated
live against a running instance carrying the exact bad state.

Bumps submodules to sso-manager-node v1.30.2, proxy v1.35.1,
jump-host v1.19.1.

Also: README's architecture diagram + repo layout were stale (2-service
view predating jump-host/OpenBao, 2 of 5 submodules listed); new
docs/fixtures.md + docs/screenshots.md + bootstrap/seed-demo-users.sh for
consistent, repeatable demo data and screenshot passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113gCdnfSCuZr6xvPDxTo3D
This commit is contained in:
2026-08-06 21:38:48 -04:00
parent ea5d2350a4
commit 5925940936
12 changed files with 606 additions and 66 deletions
+43 -27
View File
@@ -44,29 +44,40 @@ The SSO Manager and the proxy it fronts, both stood up by one `./setup.sh` run:
-**Phases 2-5**: Pending (see [roadmap](#)).
```
┌──────────────────────────────────────────────┐
│ your browser / apps
└───────────────┬──────────────────────────────┘
│ https
┌─────────▼─────────┐
proxyOpenResty :80/:443/:4443
│ (OIDC + LDAP) │ mgmt app :3000 (localhost)
└─────────┬─────────┘ bundled redis
┌─────────────┼──────────────────────┐
│ ldaps:636 │ http:3001 (internal)│ OIDC token/userinfo
▼ ▼
──────────────────────────┐
│ sso-manager │◄────────────────┘
│ OIDC provider + OpenLDAP │ bundled redis
│ web UI :3001 (localhost) │
ldaps :636 (LAN clients)
└───────────────────────────┘
──────────────────────────────────────────────────────────┐
browser / OIDC apps │ SSH clients │ Linux hosts
│ │ │ (PAM/SSSD, sudo, keys) │
└────────┬────────────┴──────┬──────┴───────────┬───────────┘
https (:443) ssh (:2222) ldaps (:636)
┌────────▼────────┐ ┌──────────▼────────┐ │
│ proxy │ │ jump-host │ │
│ OpenResty │ │ sshd :2222 │ │
│ :80/:443/:4443 │ │ web UI :3002 │ │
│ mgmt app :3000 └────────┬──────────┘
─────────────────┘ │ OIDC + LDAP
│ http:3001 (internal)│ via sso-manager │
▼ ▼ ▼
┌───────────────────────────────────────────────────────┐
sso-manager (Express + OpenLDAP + Redis)
│ OIDC provider + LDAP directory │
│ web UI :3001 (internal) ldaps :636 (published) │
└───────────────────────────────────────────────────────┘
▲ loads secrets at boot (scoped token each)
┌───────────┴───────────────────┐
│ openbao (KV-v2 at secret/) │ ← central secrets store
│ :8200 (internal) │ per-user + per-app KV
│ :8080 (operator UI/API) │
└───────────────────────────────┘
```
The proxy fronts the SSO Manager UI under TLS and protects it with OIDC login.
It is **both** an OIDC client of the SSO (for login) **and** a direct LDAP
client (for user lookups). Legacy apps can still bind to LDAPS on the SSO
directly.
The proxy fronts the SSO Manager UI (and the jump-host web UI) under TLS and
protects them with OIDC login. It is **both** an OIDC client of the SSO (for
login) **and** a direct LDAP client (for user lookups). Legacy apps can still
bind to LDAPS on the SSO directly. See
[docs/architecture.md](docs/architecture.md) for the full diagram (ports,
secrets flow, jump-host, ldap-client) and [docs/secrets.md](docs/secrets.md)
for the OpenBao model.
- **Self-service API tokens** in both apps' UIs, for scripting/CI without a browser session.
- **Multi-Site Support (Geo-Location Scaling)** — built-in support for N-Way Multi-Master LDAP replication across physical locations.
@@ -273,17 +284,19 @@ for details.
## Logs
The stack runs under Docker Compose with two services — `sso-manager` and
`proxy`. Both the Node app and, for the SSO, OpenLDAP write to the container's
stdout/stderr, so `docker compose logs` is the primary view.
The stack runs under Docker Compose with several services — `sso-manager`,
`proxy`, `jump-host`, and `openbao` (plus its `bao-renewer` sidecar). Both the
Node app and, for the SSO, OpenLDAP write to the container's stdout/stderr, so
`docker compose logs` is the primary view.
```bash
# Follow both services live
# Follow all services live
docker compose logs -f
# One service
docker compose logs -f sso-manager
docker compose logs -f proxy
docker compose logs -f jump-host
# Last 200 lines and keep following
docker compose logs --tail=200 -f proxy
@@ -473,12 +486,15 @@ exactly in the bootstrap) so the SSO can verify them on bind.
theta-suite/
├── setup.env.example # first-run config template — cp to setup.env, set CFG_DOMAIN
├── config.example/ # committed annotated config templates (copy to ./config/)
├── docker-compose.yml # sso-manager + proxy on one bridge net
├── docker-compose.yml # sso-manager + proxy + jump-host + openbao on one bridge net
├── setup.sh # one-command idempotent bring-up (manages ./config/ + backups)
├── bootstrap/
│ └── bootstrap.js # runs in the sso-manager container
├── sso-manager-node/ # git submodule
── proxy/ # git submodule
── proxy/ # git submodule
├── jump-host/ # git submodule
├── ldap-client/ # git submodule (enrolls Linux hosts; also the opt-in ldap-test-host fixture)
└── theta-agent/ # git submodule
```
`./setup.sh` reads the gitignored `setup.env` on first run to generate the