opschain admin encryption reencrypt
Included from Basic tier
Rewrites every at-rest envelope that is not sealed under the current key —
the v2 SystemService.ReencryptAtRest write. Server-side, the run:
- Refuses by name when any stored envelope references a key this
server does not carry (
<table>.<column> holds N envelope(s) under key <id> — this server does not carry that key), before touching a row: list the key inOPSCHAIN_PREVIOUS_KEYSon every replica and rerun. - Takes the cluster-wide lock (a PostgreSQL advisory lock; a second concurrent run anywhere in the estate is refused as already in progress).
- Resumes an unfinished run for the same target key (status
partialorfailed) or opens a new progress row. - Selects pending rows set-wise per column (
ORDER BY ctid/rowidkeyset cursor,LIMIT --batch-size), decrypts under the ring, re-encrypts under the current key and writes each batch in one transaction, guarded by the value it read (a row changed under the run is skipped and picked up by the next pass). Counts land in the progress row after every batch — never a value. - On a clean full pass with nothing pending, retires every other
registered key (
retired_at,retired_by = <run id>): they may then be removed fromOPSCHAIN_PREVIOUS_KEYSon every replica. - Records the
api:encryption:reencryptaudit event with the run id, target key id, status and counts.
The run is idempotent: a converted row no longer matches the
selection, so a rerun finds nothing to do and answers completed with
converted 0.
Flags
| Flag | Meaning |
|---|---|
--batch-size <n> | Rows per transaction (default 500 server-side, capped at 5000). |
--limit <n> | Stop after this many rows; the run stays partial and the next invocation resumes it (0 = run to completion). Use it to spread a very large estate over several windows. |
--server <url> | Server base URL (default: the active context / OPSCHAIN_SERVER). |
--auth-token <token> | Admin bearer token override (default: your opschain login session, then $OPSCHAIN_ADMIN_TOKEN, then the token stored by opschain admin login). |
Under -o json / -o yaml the run document is printed verbatim (id,
target_key_id, status, started_at, updated_at, finished_at,
converted, failed, skipped, resumed, columns[],
retired_key_ids, error); the exit code still reflects the status.
Run statuses
| Status | Meaning | Exit |
|---|---|---|
completed | A full pass found nothing left; superseded keys retired. | 0 |
partial | --limit stopped the run; rerun to resume. | 1 |
completed_with_failures | failed rows could not be decrypted under any configured key (the count is the latest pass's, not a running sum); no key is retired while they remain. | 1 |
failed | A statement error stopped the run (error names it); rerun to resume. | 1 |
Exit codes
| Code | Meaning |
|---|---|
| 0 | The run completed. |
| 1 | The run is partial or failed, the run was refused (missing key, already in progress, no encryption configured), the request failed, or the token was rejected. |
| 2 | Usage error — a negative flag, no server or no credential resolvable. |
Examples
opschain admin encryption reencrypt
opschain admin encryption reencrypt --batch-size 1000 --limit 200000
opschain admin encryption reencrypt -o json | jq '.status, .retired_key_ids'
See also
opschain docs cli/admin-encryption-status— the census before and after;pendingmust read 0 and the old keyretired.- The encryption key rotation runbook in the operations runbooks — the rotation drill.