Corporate PKI (X.509)¶
When compliance mandates identity-traceable signing, sign with a leaf certificate that chains to the corporate CA. The signature carries the certificate, so verification is attributable to a named identity and chains to the CA — still fully offline (no Fulcio, no Rekor).
The signing identity¶
The signing certificate is issued by the corporate CA (or by
gapcert / step-ca against it) and
carries:
- a SAN identity (email / URI / DNS), e.g.
gapsign-ci@corp.example; - the Sigstore OIDC-issuer extension (v1
…57264.1.1or v2…57264.1.8), e.g.https://corp.example/oidc; - the code-signing extended key usage.
Sign¶
# config.yaml (signing side)
backend: cosign-x509
backend_opts:
key: ~/.config/gapsign/leaf.key # leaf private key
cert: ~/.config/gapsign/leaf.crt # leaf certificate
chain: ~/.config/gapsign/corp-ca.pem # CA chain
The signature is stored with the certificate and chain in the cosign annotations
(dev.sigstore.cosign/certificate, dev.sigstore.cosign/chain).
Verify¶
gapsign verifies: the signature under the leaf certificate's key, the digest+repository binding, that the leaf chains to the configured CA roots as a code-signing certificate, and that the SAN identity and issuer match what policy expects. Trust roots come only from your configuration — never from the signature — so an attacker's self-signed leaf or CA in the signature can never become a trust anchor.
The real cosign CLI verifies the same artifact offline:
$ cosign verify --cert-chain corp-ca.pem \
--certificate-identity gapsign-ci@corp.example \
--certificate-oidc-issuer https://corp.example/oidc \
--insecure-ignore-tlog --insecure-ignore-sct \
registry.internal/app@sha256:...
Admission¶
For an X.509 signer, the config trust: entry is the CA + identity + issuer:
trust:
mirror-x509:
ca_roots: ~/.config/gapsign/corp-ca.pem
identity: "gapsign-ci@corp.example"
issuer: "https://corp.example/oidc"
gapsign policy render emits a Kyverno keyless attestor (CA roots + exact
identity + issuer, offline). The ca_roots file must contain only certificates —
a mis-pointed private key is refused before anything is written.
The gapcert linkage¶
The two airgap-infra siblings compose: gapcert (ACME / step-ca against the
corporate CA) can issue the X.509 signing identity, and gapsign signs with it —
one gets the identity, the other signs with it.