secretsmgr handbook
Editor sign-in

Onboard a machine (CI, a service)

A machine is a principal like any other. What differs is how it gets its first key, since no human is present to approve it.

Preferred: cloud KMS custody (phase 2)

The workload proves its identity to your cloud provider, through workload identity federation from your CI system or an instance role, and the cloud decrypts the private key for it. No key material sits on the runner's disk.

secretsmgr voucher issue --principal-name ci-deploy-prod \
    --custody kms --ttl 15m

# in the pipeline, once:
secretsmgr enroll request --name ci-deploy-prod \
    --custody kms --kms-key projects/acme/locations/…/cryptoKeys/secretsmgr \
    --voucher "$SECRETSMGR_VOUCHER"

A voucher is a single-use, short-lived, signed permission slip that lets one machine add itself to the member list without a human on the call. It grants no access to anything: a machine that enrolls with a voucher can read nothing until someone runs grant for it.

Two cloud settings that undo all of this

When you configure workload identity federation, get these right:

  • Use an audience value unique to this deployment. A generic one lets a token minted for some other service be replayed at yours.
  • Match the subject exactly and anchored. A pattern like repo:acme/* means that any newly created repository in your organization can impersonate the trusted one, and creating a repository is usually not a privileged act.

The client refuses known-generic audiences and prints the expanded subject rule for you to read before it will proceed.

Fallback: file custody

If you have no KMS, a machine can hold a plain key file. This is supported so nobody is locked out of adopting the tool, and it is made awkward on purpose. The vault policy must spell out asserted-file-machine-explicit; no default and no --force flag gets you there, so the choice always shows up in a code review. And secretsmgr report file-custody lists every machine in a protected vault still holding a file key, and fails the pipeline it runs in, so the exception stays visible instead of being forgotten.