#!/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 <