RELAY-PHASE1 Wave A2/B/C/D/E (12-agent workflow, all tsc-clean, 314/314 tests pass): - A2: control-plane server.ts entry + boot/redis.ts revocation-bus wiring + start script. - B1: relay-run shared-store EnforceDeps (relay-auth ports over the SAME Postgres+Redis as P3). - B2: registry-backed MtlsVerifier (verifyAgentCert, fail-closed, INV14). - B3: store-backed RouteResolver (subdomain->hostId). - B4: Redis relay:revocations subscriber -> tunnel teardown (INV12). - B5: main-phase1.ts production entry (public bind, real TLS, async-mTLS prefetch bridge) + staging /auth/mint. - B6 (PARTIAL): relay-web operator login + browser DPoP; proof offered via term.dpop.<b64u> subprotocol. - C: agent dist/cli.js build (esbuild) + runTunnel run-loop + CliDeps. - D1: same-origin static serve of relay-web/public from the browser WSS. - E: systemd units + gen-ca/gen-capability-key/issue-tls-cert scripts + deploy/RUNBOOK.md. Adversarial review: all hard invariants PASS. Follow-ups (B7): close DPoP-subprotocol read on browser-server (blocks browser connect); rate-limit /auth/mint (F1); wire activeSessionCount (F2); scrub error logs (F5). Excludes unrelated public/style.css (concurrent iOS job).
53 lines
2.2 KiB
Desktop File
53 lines
2.2 KiB
Desktop File
# RELAY-PHASE1 · E (TASK E) — control-plane (P3) systemd unit. STAGING TEMPLATE.
|
|
#
|
|
# Runs the P3 admin/registry/CA/pairing API (control-plane/src/server.ts, added in A2) on the
|
|
# loopback admin port (CP_BIND_HOST/CP_BIND_PORT in the env file). It is NEVER exposed publicly —
|
|
# the security group keeps 8080 loopback-only; operators reach it via SSH tunnel.
|
|
#
|
|
# INSTALL (adjust the placeholder paths to your VPS):
|
|
# 1) clone the repo to /opt/web-terminal (or edit --prefix below)
|
|
# 2) install: sudo cp deploy/systemd/relay-control-plane.service /etc/systemd/system/
|
|
# 3) put the filled env at /etc/relay/control-plane.env (0600, owned by the service user)
|
|
# 4) sudo systemctl daemon-reload && sudo systemctl enable --now relay-control-plane.service
|
|
#
|
|
# The env file supplies PG_URL/REDIS_URL/CAPABILITY_SIGN_PUBKEY_B64/CA_* /BASE_DOMAIN (see .env.example).
|
|
|
|
[Unit]
|
|
Description=web-terminal rendezvous-relay CONTROL PLANE (P3)
|
|
Documentation=file:///opt/web-terminal/docs/PLAN_RELAY_PHASE1.md
|
|
# Postgres + Redis run under Docker Compose (deploy/docker-compose.yml); wait for docker + network.
|
|
After=network-online.target docker.service
|
|
Wants=network-online.target
|
|
Requires=docker.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
# Dedicated non-root service user (create once: sudo useradd --system --home /opt/web-terminal relay).
|
|
User=relay
|
|
Group=relay
|
|
WorkingDirectory=/opt/web-terminal
|
|
# Secrets/config come ONLY from the env file (INV9 — no secrets inline in the unit).
|
|
EnvironmentFile=/etc/relay/control-plane.env
|
|
# /usr/bin/env resolves npm via PATH (works for NodeSource /usr/bin/npm and nvm shims alike).
|
|
# Runs the "start" script (control-plane/package.json -> tsx src/server.ts).
|
|
ExecStart=/usr/bin/env npm --prefix /opt/web-terminal/control-plane start
|
|
Restart=always
|
|
RestartSec=3
|
|
# Give in-flight requests / graceful SIGTERM (server.ts closes the http listener + pg/redis) time.
|
|
TimeoutStopSec=20
|
|
KillSignal=SIGTERM
|
|
|
|
# --- hardening (INV9: shrink the blast radius around the CA + capability material) ---
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=full
|
|
ProtectHome=true
|
|
ProtectControlGroups=true
|
|
ProtectKernelTunables=true
|
|
RestrictSUIDSGID=true
|
|
# The CA/capability material under /etc/relay is READ-ONLY to this service.
|
|
ReadOnlyPaths=/etc/relay
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|