Skip to content

Admission enforcement

Render a fail-closed Kyverno verifyImages policy from the gapsign policy source and apply it via GitOps. Kyverno then verifies signatures at admission and blocks unsigned images before a pod starts — fully offline.

Render

$ gapsign policy render -config config.yaml -o kyverno-policy.yaml
wrote kyverno-policy.yaml

The rendered ClusterPolicy:

  • sets failurePolicy: Fail — a webhook error blocks admission (fail closed);
  • emits one verifyImages rule per gapsign policy rule, with required: true, tag→digest resolution (mutateDigest / verifyDigest), and failureAction Enforce (block) for signed rules or Audit (report) for warn rules;
  • embeds each signer's public key (key mode) or CA roots + identity + issuer (X.509 mode) as the attestor;
  • ignores the transparency log and SCT (rekor.ignoreTlog / ctlog.ignoreSCT) — the airgap invariant.

Apply it the GitOps way (ArgoCD, Flux, kubectl apply); gapsign only renders.

Policy source

# policy.yaml — the single source of truth
policies:
  - match: "registry.internal/*"      # first-party
    signer: ci-kms
    namespaces: ["prod", "payments"]  # protected → Enforce (fail closed)
    require: signed
  - match: "sandbox.internal/*"
    signer: sandbox-key
    namespaces: ["dev"]
    require: warn                       # Audit-only (report, don't block)
  • match is an image-reference glob (* or a prefix/*).
  • namespaces scopes the rule; an empty list applies cluster-wide.
  • require: signed blocks; require: warn reports. A warn rule with no signer is skipped (nothing to verify).

Each signer named here must have trust material in the config trust: map, or the render fails — the rendered policy must never fail open.

Trust distribution

The rendered policy carries only public material (public keys, CA roots), so it is safe to commit to the GitOps repository. A mis-pointed private key, an empty key, or an invalid CA bundle are all refused at render time — nothing is written.

Verified against real Kyverno

The render targets Kyverno v1.12+ and is regression-tested against the real Kyverno CLI: a gapsign-signed image is admitted and an unsigned image is blocked, offline. Kyverno matches the keyless subject/issuer as exact strings.