License Key Rotation
This document covers operational key rotation for Alexandria EE license signing keys.
When to rotate
Rotate the signing key in any of these situations:
- Annual cadence — recommended practice to limit the blast radius of an undetected key leak.
- Suspected key compromise — rotate immediately if the private key may have been exposed (leaked in CI logs, committed to version control, exfiltrated from an operator machine).
- Key custodian change — when the employee or role responsible for license issuance changes, issue a new keypair under the new custodian's control and retire the previous key after the migration window closes.
Two rotation modes
Hot rotation (gradual migration)
Used for planned rotations, annual cadence, or custodian handoffs.
- Issue a new keypair alongside the old one.
- Add the new public key to
TrustedKeysin all deployed binaries. - Re-issue new licenses under the new key; existing licenses signed under the old key continue to verify (both keys are trusted).
- After all customers have received their new license, remove the old key from
TrustedKeysand redeploy.
Hot rotation has zero customer downtime but requires a two-phase deploy.
Cold rotation (immediate revocation)
Used when the private key is believed to be compromised.
- Generate a new keypair.
- Remove the old key from
TrustedKeysand add only the new key — deploy immediately. - Re-issue all customer licenses under the new key.
- Communicate the new licenses to customers; their old licenses will fail verification once the new binaries roll out.
Cold rotation is disruptive (customers' existing licenses stop working until they receive the replacement) but eliminates the window during which an attacker could issue fraudulent licenses.
Step-by-step procedure
Step 1 — Generate the new keypair
alex-license rotate --keygen-only --kid-new <new-id>
Output (example):
kid: prod-2025
pub: <base64url-encoded ed25519 public key>
priv: <base64url-encoded ed25519 private key>
Save the priv value in a secure location (password manager, HSM, encrypted file on an air-gapped machine). The pub value is placed in the binary.
Step 2 — Add the new public key to TrustedKeys
For a non-production binary (dev / staging), edit api-go/internal/license/keys_embedded.go:
add("prod-2025", "<pub value from step 1>")
For a production binary built with -tags prod, the key is injected at build time via environment variables. Set ALEXANDRIA_PROD_TRUSTED_KID and ALEXANDRIA_PROD_TRUSTED_KEY_PEM in your CI secret manager and rebuild. See api-go/internal/license/keys_embedded_prod.go for details.
For a hot rotation, keep the old entry alongside the new one until all licenses have been migrated.
Step 3 — Build and deploy binaries with both keys (hot rotation only)
gcloud builds submit --config cloudbuild.yaml
Verify the new binaries start and the old licenses still verify before proceeding.
Step 4 — Re-issue licenses under the new key
alex-license rotate \
--kid-old prod-2024 \
--kid-new prod-2025 \
--priv-old @/path/to/old.priv \
--priv-new @/path/to/new.priv \
--blob @/path/to/customer.blob \
> customer_new.blob
The payload (tier, seats, expiry, entitlements) is preserved exactly. Only the signing key changes. Distribute customer_new.blob to the customer.
If --priv-new is omitted, alex-license rotate generates a one-time keypair and prints the new public key to stderr with a warning. This is useful for emergency re-issuance when you have not yet saved the new private key to a secure location, but it requires you to immediately add the new pub key to TrustedKeys and redeploy.
Step 5 — Remove the old key and redeploy (hot rotation only)
Once all customers report successful license verification with their new blob, remove the old key entry:
- From
keys_embedded.go: delete theadd("prod-2024", …)line. - From the prod build: remove the old
ALEXANDRIA_PROD_TRUSTED_KID/ALEXANDRIA_PROD_TRUSTED_KEY_PEMsecrets and set them to the new values.
Rebuild and redeploy.
Signing-key custody
Today, private keys are managed as files on operator machines or as CI secrets. This is acceptable for current scale but carries the risk of key loss if the machine is destroyed without a backup, or key compromise if the secret store is breached.
Future hardening (planned, not yet implemented): migrate signing-key operations to a Hardware Security Module (HSM) or a cloud KMS (e.g., Google Cloud KMS, AWS CloudHSM). The alex-license sign and rotate commands will be updated to accept a KMS key reference instead of a raw private-key file. Until then, treat the private key file as equivalent to a root CA private key — minimal exposure, encrypted storage, offline when not in use.