Files
web-terminal/deploy/scripts/gen-capability-key.sh
Yaojia Wang aa1912b962 feat(relay): Phase1 waves A2-E — server entry, shared-store data plane, agent runtime, deploy artifacts
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).
2026-07-06 16:13:34 +02:00

68 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# RELAY-PHASE1 · E (TASK E) — P5 capability-token keypair (Ed25519).
#
# STAGING TEMPLATE. One Ed25519 keypair underpins the whole authz split:
#
# CONTROL-PLANE SIGNS ──(mints capability tokens with the PRIVATE key, B6 token-mint)──▶
# RELAY VERIFIES
# The CP admin API (POST /accounts, /pairing-codes) ALSO verifies operator "manage" tokens with
# the SAME public key. So the public key is deployed to BOTH processes; the private key lives ONLY
# where tokens are minted (the B6 mint), never on the relay, never committed.
#
# The public key is printed in TWO encodings of the SAME raw 32 bytes (the split is encoding-only):
# CAPABILITY_SIGN_PUBKEY_B64 raw 32B, standard base64 -> control-plane env (env.ts base64ToBytes)
# RELAY_AUTH_VERIFY_PUBKEY raw 32B, base64url (no pad) -> relay env (loadVerifyKeyFromEnv)
# These MUST be the SAME key (PLAN §3 linchpin). This script prints both from one keypair so they
# cannot drift.
#
# The PRIVATE key is written PKCS#8 PEM to a 0600 file for the B6 mint to import (WebCrypto Ed25519).
# It is NEVER printed and NEVER placed in relay.env / control-plane.env.
#
# Config via ENV only:
# KEY_DIR output dir for the private key (default /etc/relay/capability)
#
# Verify (syntax): bash -n deploy/scripts/gen-capability-key.sh
set -euo pipefail
KEY_DIR="${KEY_DIR:-/etc/relay/capability}"
PRIV="${KEY_DIR}/capability-sign.key.pem"
command -v openssl >/dev/null 2>&1 || { echo "FATAL: openssl not found on PATH." >&2; exit 3; }
umask 077
mkdir -p "${KEY_DIR}"
if [[ -f "${PRIV}" ]]; then
echo "WARN: ${PRIV} already exists — reusing it (delete it to rotate). Rotating INVALIDATES every" >&2
echo " minted token AND requires re-deploying the public key to BOTH processes." >&2
else
openssl genpkey -algorithm ed25519 -out "${PRIV}"
fi
chmod 600 "${PRIV}"
# Raw 32-byte Ed25519 public key = last 32 bytes of the SPKI DER.
PUB_STD_B64="$(openssl pkey -in "${PRIV}" -pubout -outform DER | tail -c 32 | openssl base64 -A)"
# base64url of the SAME bytes, padding stripped (decodeBase64UrlBytes tolerates missing padding).
PUB_B64URL="$(printf '%s' "${PUB_STD_B64}" | tr '+/' '-_' | tr -d '=')"
cat <<SUMMARY
P5 capability keypair ready.
PRIVATE key (B6 token-mint only; 0600; NEVER commit / NEVER on the relay):
${PRIV}
Put the SAME public key in BOTH env files (they are one key, two encodings):
# control-plane.env
CAPABILITY_SIGN_PUBKEY_B64=${PUB_STD_B64}
# relay.env
RELAY_AUTH_VERIFY_PUBKEY=${PUB_B64URL}
Sanity check they decode to the same 32 bytes:
diff <(openssl pkey -in "${PRIV}" -pubout -outform DER | tail -c 32 | xxd -p) \\
<(printf '%s' "${PUB_STD_B64}" | openssl base64 -d -A | xxd -p) && echo OK
SUMMARY