Appearance
plexctl signing
Synopsis
plexctl signing is the operator surface for the per-scope signing-key rotation lifecycle. The family wraps two RPCs on the signer's gRPC SignerService:
OpenRotation— start a new rotation for a scope and return the transition window (opened_at,closes_at).CloseRotation— finalise the rotation by retiring the old key and promoting the new key to active.
text
plexctl signing rotate --scope <scope> --new-key-id <id>
plexctl signing close --scope <scope> --old <id> --new <id>The signer speaks its own gRPC surface on a separate host:port from the plexsphere HTTP API, so the signing family does NOT consult the persistent --server flag. Use --signer-endpoint or the PLEXSPHERE_SIGNER_ENDPOINT environment variable instead.
This family addresses the per-Domain signing key that signs the mesh event bus. It is distinct from plexctl key rotate, which rotates the per-Node mesh key anchoring WireGuard edges; the two rotations target different aggregates and run independently.
Subcommands
plexctl signing rotate
Calls SignerService.OpenRotation to open a new rotation for a signing scope. The renderer prints the transition window (opened_at, closes_at) alongside the (scope, old_key_id, new_key_id) triple so an operator transcript names the keys involved without a follow-up query.
The leaf does not wrap the gRPC status error with fmt.Errorf — the dispatcher's exitCodeFor consumes the raw *status.Status and maps gRPC codes to exit codes per the family's contract.
plexctl signing close
Calls SignerService.CloseRotation to finalise a rotation. The server's CloseRotationResponse is empty by design, so the renderer echoes the (scope, old_key_id, new_key_id) triple back so the operator's local transcript still records which keys were involved.
Flags
plexctl signing rotate
| Flag | Type | Required | Description |
|---|---|---|---|
--scope | string | yes | Signing scope — either platform or domain:<uuid>. |
--new-key-id | string | yes | URL-safe identifier for the new key being introduced. |
--signer-endpoint | string (host:port) | no | Signer gRPC endpoint; overrides PLEXSPHERE_SIGNER_ENDPOINT. |
plexctl signing close
| Flag | Type | Required | Description |
|---|---|---|---|
--scope | string | yes | Signing scope — either platform or domain:<uuid>. |
--old | string | yes | Key id being retired. |
--new | string | yes | Key id being promoted to active. |
--signer-endpoint | string (host:port) | no | Signer gRPC endpoint; overrides PLEXSPHERE_SIGNER_ENDPOINT. |
Persistent flags inherited from root
--profile, --token-file, --output. See ../plexctl.md for the canonical list.
The persistent --server flag is not consumed by this family — it points at the plexsphere HTTP API, while signing-key rotation talks to the signer's gRPC surface. Set --signer-endpoint or PLEXSPHERE_SIGNER_ENDPOINT instead.
Exit codes
See ../plexctl.md#exit-code-taxonomy for the inherited base table. The gRPC status branches that apply to this family map as follows:
| gRPC status | Exit code | Meaning |
|---|---|---|
InvalidArgument | 2 | A flag value was rejected by the signer's input validation. |
FailedPrecondition | 1 | The signer refused the call (e.g. close against a non-open rotation, rotate against an already-open transition). |
Unauthenticated / PermissionDenied | 77 | Signer denied the caller; check the deployment's auth posture. |
Unavailable / dial failure | 1 | The signer endpoint did not accept the gRPC dial — host, port, or service-mesh sidecar misconfigured. |
--scope, --new-key-id, --old, and --new are validated client-side before the dial step, so a missing required flag surfaces as exit 2 without a network round-trip.
Output
Both subcommands honour the inherited --output selector (text / json / yaml). The text renderer emits a single-row table; JSON and YAML emit a struct verbatim:
| Subcommand | Text columns |
|---|---|
rotate | SCOPE, OLD_KEY_ID, NEW_KEY_ID, OPENED_AT, CLOSES_AT |
close | SCOPE, OLD_KEY_ID, NEW_KEY_ID |
Timestamps are emitted as RFC 3339-UTC so a forensic transcript reads identically regardless of the operator's local timezone.
Examples
Open a rotation for the platform scope
shell
export PLEXSPHERE_SIGNER_ENDPOINT="${PLEXSPHERE_SIGNER_ENDPOINT:-localhost:9443}"
plexctl signing rotate \
--scope platform \
--new-key-id platform-2026-05Close a rotation for a Domain scope
shell
plexctl signing close \
--scope domain:0190a8b8-b1c1-7b1b-8b1b-b1b1b1b1b1b1 \
--old domain-2026-04 \
--new domain-2026-05Pin a one-off endpoint
shell
plexctl signing rotate \
--signer-endpoint signer.internal:9443 \
--scope platform \
--new-key-id platform-2026-06Cross-references
../../../api/openapi/plexsphere-v1.yaml— the plexsphere HTTP API spec; signing-key rotation lives on the gRPC surface and is not represented here../key.md— sibling rotation family that targets the per-Node mesh key; pickplexctl signingfor the per-Domain signing key,plexctl keyfor the per-Node mesh key.../../../contexts/signing-rotation.md— bounded-context reference for the signing-key rotation state machine and the two-phase fan-out posture the signer uses.