Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXIX · Artifact SigningKeypair

Self-managed keys and KMS — when to use your own keys, KMS integration

Advanced⏱ ~26 mingitcosign

What you'll learn

  • Generate and manage a cosign keypair with rotation and revocation discipline
  • Integrate cosign sign with AWS KMS, GCP KMS, HashiCorp Vault, or a PKCS#11 HSM
  • Identify the scenarios that justify a self-managed key over the keyless default
  • Apply the production discipline for keypair signing: rotation cadence, revocation, audit trail

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The keyless flow is the production default for most CI pipelines, but the keypair flow is not dead. The keypair flow re-enters when the team cannot rely on a public Sigstore instance, runs self-hosted CI without an OIDC provider, or has compliance requirements that mandate a customer-managed key. The production path for keypair signing is not a private key on a developer’s laptop; it is a key in a KMS.

When to use your own keys

The keyless default is the right choice for any CI provider that issues OIDC tokens, but five scenarios push the team back to keypair:

  • Air-gapped CI. The team runs CI on infrastructure that cannot reach the public Sigstore instance. Fulcio is unreachable; the keyless flow fails at the sign step.
  • Self-hosted CI without OIDC. The CI provider does not support OIDC token issuance (older Jenkins, on-prem runners without a token issuer). The keyless flow cannot anchor to an OIDC identity.
  • Compliance mandates a customer-managed key. Some regulatory regimes (FedRAMP High, certain financial frameworks) require a customer-managed key for signing materials. The keyless flow does not satisfy the control.
  • Long-lived signing identity. The team wants a stable identity independent of any CI provider. A key in a KMS, rotated on a documented cadence, satisfies the requirement.
  • Multi-region signing. The team signs in multiple regions and does not want every sign to depend on a central Sigstore instance. A regional KMS satisfies the requirement.

For each scenario, the production path is the same shape: a key in a KMS, a key reference in the CI, and a verification policy pinned to the public key.

The keypair signing flow

The keypair flow with a KMS-backed key is the same shape as the keypair flow with a local key, but the key reference is a KMS URI:

cosign sign --key awskms:///alias/cosign-key \
    image:$DIGEST

The awskms:/// prefix tells cosign to use the AWS KMS plugin. The team authenticates to KMS via the standard AWS credentials chain; the key never leaves the KMS. The verification side either uses the same KMS URI or pins the public key.

flowchart LR
    A["CI runner"] --> B["AWS credentials"]
    B --> C["KMS key"]
    C --> D["Signature"]
    A --> E["cosign sign --key awskms://..."]
    E --> D
    D --> F["Registry"]
    F --> G["Verifier"]
    G --> H["Admit"]
    G --> I["Deny"]

The same pattern applies to GCP KMS (gcpkms://), HashiCorp Vault (via the Vault plugin), Azure Key Vault, and PKCS#11 HSMs. The plugin architecture is the same; the URI prefix is the only thing that changes.

Cosign keypair lifecycle

The lifecycle of a cosign keypair has six phases:

  1. Generate. cosign generate-key-pair produces a private key and a public key. The private key is encrypted with a passphrase; the public key is published.
  2. Store. The private key is uploaded to a KMS as a customer-managed key (CMK); the passphrase is the only thing that can decrypt the on-disk copy. The local copy is deleted.
  3. Sign. cosign sign --key awskms:///alias/cosign-key is the production reference. The runner authenticates to KMS via the standard chain.
  4. Verify. cosign verify --key cosign.pub checks the signature against the published public key. The public key is the verifier’s pin.
  5. Rotate. On the documented cadence, a new keypair is generated; the new key becomes the signing key; the old key signs the transition for a grace period; the old key is then disabled.
  6. Revoke. If the key is compromised, the KMS disables the key; the CI raises an alert; the verifier policy is updated; the new key becomes the only signing identity.

Verification with a public key

The verification side of the keypair flow is the simplest shape in the Sigstore stack:

cosign verify --key cosign.pub image:$DIGEST

The command does not require Fulcio, Rekor, or an OIDC token. The verifier holds the public key; the public key is the policy. The downside is the same as the upside: the policy is a static file, not a dynamic identity. Rotation is the operational lever.

Production discipline

  1. Generate the keypair with a passphrase and store the private key in a KMS. The local copy is a backstop, not the primary store.
  2. Rotate the keypair on a documented cadence. Quarterly is a common default; the cadence depends on the compliance regime.
  3. Revoke on suspicion. A leaked key is a compromised identity; the KMS disables the key, the verifier is updated, and the audit log records the event.
  4. Pin the public key in the verifier. A wildcard verifier is not a verifier.
  5. Document the rotation cadence and the revocation procedure. The keypair flow is the long-lived key flow; the documentation is the operational deliverable.

Cross-course references

  • Git, CI/CD & GitOps — Part LXIX-03 (Keyless Signing with Fulcio) is the keyless default; LXIX-04 is the keypair fallback.
  • Git, CI/CD & GitOps — Part LIII-06 (Image Signing in CI) is the previous lesson on cosign; LXIX-04 deepens the keypair side.
  • Linux for Production Sysadmins — Part XX (KMS Operations) is the operational discipline for KMS-backed credentials.

Quiz

Knowledge check · 4 questions

  1. Q1. Which scenario is the strongest justification for using a customer-managed key in a KMS instead of the keyless default?

  2. Q2. A cosign keypair with the private key stored on a developer's laptop is an acceptable production pattern when the key is encrypted with a passphrase.

  3. Q3. Name the four KMS backends cosign integrates with via the plugin architecture.

  4. Q4. Diagnose why the team's KMS-backed signing is failing and recommend the fix.

    Team T rotates its cosign keypair quarterly. The new key is in AWS KMS; the runner assumes the awskms:///alias/cosign-key role via OIDC federation. After the rotation, every sign fails with `kms: decrypt failed`. The team confirms the key exists in KMS and the role has decrypt permission.

Passing score: 75%. Answers are checked in this browser.