Skip to content

rotate_cert_windows.py

Transactional Windows Blueprint certificate rotation with full rollback, extracted from deploy-windows.ps1 so the rollback contract is testable. Windows only.

Part of the auth-and-certs command reference.

Purpose

Performs an all-or-nothing rotation of the Blueprint certificate: it registers the new certificate on the Blueprint app, smoke-tests token acquisition, and either commits (removing the old certificate) or rolls everything back. Other machines' certificates on the Blueprint are kept in both directions. It is a module invoked by deploy-windows.ps1, not a standalone CLI entry point. See Windows Platform APIs → Two thumbprints, two purposes and Token flows.

Requirements

  • Windows, driven by deploy-windows.ps1.
  • The wrapper must, before generating the new certificate, capture the old certificate's public DER — for a non-exportable TPM key this is the only chance to grab the old public material for rollback.
  • The wrapper supplies: the old DER, the new certificate's SHA-1 thumbprint, x5t#S256, and public DER (from generate_windows_cert.py), plus callables for the Graph PATCH, the smoke test, deletion of the old certificate, and a Graph token provider, together with the .env path, MSAL cache path, and Blueprint object ID.

Usage

Invoked through the deploy wrapper rather than run directly:

pwsh scripts/deploy-windows.ps1

Options

Not a CLI. The rotation is driven by the parameters the wrapper passes to the rotate function.

Effects

The rotation runs as an ordered transaction:

  1. Read the original x5t#S256 and SHA-1 thumbprints from .env.
  2. Acquire a Graph token.
  3. Swap the new certificate DER into the Blueprint's keyCredentials, through the wrapper's callable: read the list, drop only the entries whose key material matches the old or new certificate, add the new one, and PATCH. If the read fails, nothing is sent.
  4. Rewrite the BLUEPRINT_CERT_* lines in .env to the new thumbprints (the single source of truth for the next run).
  5. Run the smoke test (acquire a fresh Agent User token end to end).
  6. On the outcome:
  7. Smoke passes → delete the old certificate from Cert:\CurrentUser\My by its SHA-1 thumbprint. The old certificate is removed only after the new one is proven to work.
  8. Smoke fails → roll back in order: swap the old DER back onto the Blueprint, restore the original thumbprints in .env, and delete the MSAL cache so the next call does not present a token signed by the now-invalid new key.

Exit behavior

Outcomes surface as typed errors that the wrapper maps to process exit codes:

  • Success — returns without error; the new certificate is live and the old one removed.
  • RotationFailed — the initial read or PATCH failed; no rollback was attempted and the old certificate is still in the local store.
  • RotationRolledBack — the PATCH succeeded but the smoke test failed; the original certificate and .env thumbprints were restored, and the MSAL cache was deleted (not restored) so a fresh cache is built on the next token acquisition.
  • ManualInterventionRequired — the smoke test failed and then the rollback (its read or its PATCH) failed too; .env and the MSAL cache are deliberately left untouched for manual triage, since the old DER is the only public material matching a working private key.

Security

Private keys never leave the certificate store; only public DER is exchanged. Invalidating the MSAL cache on rollback prevents a stale-signed token from looping on 401 after the new key is removed.

Common failures

  • Rollback after smoke failure — expected and safe; the previous certificate is restored automatically.
  • ManualInterventionRequired — re-PATCH the old DER manually; do not touch .env/MSAL until the Blueprint is consistent again.