Skip to content
Registry StackDocsv0.46.0

Rotate Registry Evidence signing keys

For the operator

View as Markdown

You run a candidate that signs through a Transit signer, as in Configure Transit signing for Registry Evidence. Move it to a successor key version without a gap in verification, then retire the predecessor.

Rotate the Transit key, read its metadata, and convert the successor key version’s public PEM:

Terminal window
vault write -f transit/keys/evidence-signing/rotate
vault read -format=json transit/keys/evidence-signing > "<operator-review-path>/evidence-key.json"
Terminal window
jq -r '.data.keys["<successor-version>"].public_key' "<operator-review-path>/evidence-key.json" \
| rstack evidence jwk from-pem - --output-dir "<target>/public-keys"
wrote <target>/public-keys/<successor-thumbprint>.jwk.json (kid <successor-thumbprint>)

Keep the predecessor’s file. A deployment target cannot author a published-key overlap or a signing-key denylist (the bundle carries publishedPublicJwkFiles: [] and revokedKeyIds: []), so rotation relies on overlap trust that consumers hold, set up as in Manage verifier trust. Give consumers both keys as one set:

Terminal window
rstack evidence jwks --output "<overlap.jwks.json>" \
"<target>/public-keys/<predecessor-thumbprint>.jwk.json" \
"<target>/public-keys/<successor-thumbprint>.jwk.json"
wrote <overlap.jwks.json>

Confirm every consumer trusts the successor before you switch the signer.

In target.yaml, set signer.keyVersion to the successor key version and signer.publicJwkFile to the successor’s file. Allow both versions in the proxy policy, for example "key_version" = ["12", "13"], and keep min_encryption_version at or below the predecessor while replicas still sign with it. Then package; package runs the fixtures:

Terminal window
rstack evidence package "<project>" --target "<target>/target.yaml" --output "<successor-candidate>"
Package digest: sha256:<package-digest>
Package: <successor-candidate>/bundle

Install the bundle at the runtime’s package.root, then activate the authority and check:

Terminal window
rstack evidence runtime authority activate --runtime-config "<successor-candidate>/runtime.yaml" \
--document "<successor-candidate>/compiled-authority.yaml"
rstack evidence runtime check --runtime-config "<successor-candidate>/runtime.yaml" \
--require-runtime-dependencies
ACTIVATED sha256:<authority-revision> sha256:<authority-digest> sequence=<n>
Evidence package sha256:<package-digest> passed check (<count> requirements)

The successor’s public key is part of the package, so the activation records a new history entry. Running it again for the same candidate, for example after fixing a refused check, fails and reports that this authority revision is already active; continue with the check.

Restart every replica, confirm readiness, and verify one synthetic response against the overlap trust set. Missing or mismatched signing material refuses startup.

Wait for the longest assertion validity plus verifier clock skew after the last instant any replica could sign with the predecessor. Then remove the old version from the proxy policy and raise the key’s min_encryption_version to the successor; the runtime refuses a pinned version below it:

Terminal window
vault write transit/keys/evidence-signing/config min_encryption_version=<successor-version>

Ask consumers to drop the predecessor from their trust set.

Raise min_encryption_version past the compromised version, or remove the proxy identity’s sign capability, at once. Distribute its thumbprint through the emergency channel so consumers deny it, then deploy a checked successor or keep the service unavailable. Do not edit bundle bytes to add a denylist.

For a compromised caller-token issuer key, add its kid to authentication.oidc.revokedKeyIds in target.yaml, package, and restart.

Operate the Registry Evidence audit log