forked from bai/curriculum-project-hub
feat: secure organization provider credentials
This commit is contained in:
+43
-4
@@ -14,13 +14,52 @@ sudo BASE=/srv/curriculum-project-hub \
|
||||
```
|
||||
|
||||
On a clean host the first invocation creates
|
||||
`/srv/curriculum-project-hub/.secrets/platform.env` with every supported
|
||||
production key and exits with status 78. Fill every required blank, set
|
||||
`CPH_BIN` to an executable compatible `cph`, keep the file mode at `0600`, and
|
||||
run the same command again. No systemd unit is installed until configuration,
|
||||
`/srv/curriculum-project-hub/.secrets/platform.env` and a random root-owned
|
||||
`secret-keyring.json`, then exits with status 78. Copy the keyring to a
|
||||
separately protected recovery location before continuing; it must not live only
|
||||
on this host or in the ordinary database/workspace backup. Fill every required
|
||||
environment blank, set `CPH_BIN` to an executable compatible `cph`, keep both
|
||||
source files root-only at mode `0600`, and run the same command again. No
|
||||
systemd unit is installed until configuration,
|
||||
paths, Node, bubblewrap, `socat`, `cph --version`, PostgreSQL connectivity and directory
|
||||
ownership all pass preflight.
|
||||
|
||||
The service account cannot read the keyring source. The installed unit uses
|
||||
systemd `LoadCredential` to materialize a read-only `cph-secret-keyring` for the
|
||||
running service. Hub refuses production startup if this credential is missing,
|
||||
malformed, or does not contain its declared active key. Provider credentials
|
||||
are configured through the Organization admin connection API, never through
|
||||
process-global `ANTHROPIC_*` variables; preflight rejects those legacy settings.
|
||||
|
||||
Rotate the local KEK only from the controlled host console. The command first
|
||||
atomically adds a new active key while retaining every previous key, then
|
||||
authenticates and rewraps every stored Provider DEK, writes redacted org audit
|
||||
events, and verifies the complete set again:
|
||||
|
||||
```sh
|
||||
sudo bash -c '
|
||||
set -euo pipefail
|
||||
systemctl stop cph-hub.service
|
||||
set -a
|
||||
. /srv/curriculum-project-hub/.secrets/platform.env
|
||||
set +a
|
||||
node /srv/curriculum-project-hub/hub/dist/deployment/rotate-secret-kek.js \
|
||||
--keyring-file /srv/curriculum-project-hub/.secrets/secret-keyring.json
|
||||
systemctl start cph-hub.service
|
||||
'
|
||||
```
|
||||
|
||||
The CLI refuses to rotate while `cph-hub.service` is active; stopping the only
|
||||
writer prevents a concurrent BYOK version from being appended under the old
|
||||
in-memory keyring. A PostgreSQL transaction advisory lock excludes a second
|
||||
rotation and is released automatically if the CLI or host crashes. The
|
||||
operation is therefore rerunnable after interruption: old and new keys remain
|
||||
in the atomically replaced keyring, so partially rewrapped rows stay
|
||||
decryptable. It also refuses success while any envelope still names a
|
||||
non-active KEK. Back up the updated keyring to the separate recovery location
|
||||
and complete a restore preflight before considering old-key retirement. The
|
||||
pilot deliberately does not auto-delete previous keys.
|
||||
|
||||
The deployment path also runs `npm run audit:production` from the locked clean
|
||||
install before building or restarting the service. A current high or critical
|
||||
production advisory therefore blocks deployment instead of becoming a warning
|
||||
|
||||
Reference in New Issue
Block a user