Git, CI/CD & GitOpsLXIX · Artifact SigningKeypair
Self-managed keys and KMS — when to use your own keys, KMS integration
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
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:
- Generate.
cosign generate-key-pairproduces a private key and a public key. The private key is encrypted with a passphrase; the public key is published. - 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.
- Sign.
cosign sign --key awskms:///alias/cosign-keyis the production reference. The runner authenticates to KMS via the standard chain. - Verify.
cosign verify --key cosign.pubchecks the signature against the published public key. The public key is the verifier’s pin. - 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.
- 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
- Generate the keypair with a passphrase and store the private key in a KMS. The local copy is a backstop, not the primary store.
- Rotate the keypair on a documented cadence. Quarterly is a common default; the cadence depends on the compliance regime.
- 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.
- Pin the public key in the verifier. A wildcard verifier is not a verifier.
- 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
Q1. Which scenario is the strongest justification for using a customer-managed key in a KMS instead of the keyless default?
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.
Q3. Name the four KMS backends cosign integrates with via the plugin architecture.
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.