Signing & identity
A signer is the cryptographic identity used to sign an attestation. In policy, the signer is what gets evaluated against a functionary: the policy's declaration of who is allowed to sign for a given step.
The verifier's question is always:
Does the signer of this evidence match a trusted functionary for this step?
Signers in the cilock binary
The cilock binary registers the following signer providers:
| Signer | Type | When to pick it |
|---|---|---|
fulcio | Keyless (Sigstore) | CI runs in a hosted system with an OIDC token (GitHub Actions, GitLab CI). Default for most teams. |
spiffe | Keyless (SPIFFE/SPIRE) | Workloads in a SPIFFE-enabled mesh that already have SVID identities. |
kms/aws | Cloud KMS | Long-lived AWS-managed identity, HSM-backed keys. |
kms/gcp | Cloud KMS | Long-lived GCP-managed identity. |
kms/azure | Cloud KMS (Azure Key Vault) | Long-lived Azure-managed identity. |
vault | HashiCorp Vault | Vault-issued signing keys. |
vault-transit | HashiCorp Vault Transit engine | Centralized signing-as-a-service via Vault Transit. |
file | Local key file | Local development, CI without OIDC. Not recommended for production releases. |
debug-signer | Debug | Development and integration testing. |
For the full decision tree, see Choose a signer.
Keyless signing: Fulcio and SPIFFE
Fulcio is the Sigstore certificate authority. It issues short-lived signing certificates tied to CI identity by exchanging a CI runtime's OIDC token (e.g. the id-token GitHub Actions provides) for a certificate valid for a few minutes, long enough to sign, short enough that there's nothing meaningful to steal. No long-lived private key to manage.
SPIFFE/SPIRE is the alternative for workloads inside a service mesh. Identity is encoded as a SPIFFE ID URI on the certificate (e.g. spiffe://example.com/step1). Witness/cilock policies can require functionaries by SPIFFE URI directly, see the policy SPIFFE example.
KMS signers (URI scheme)
KMS signers use a URI-based reference scheme borrowed from Sigstore Cosign:
- AWS:
awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-...(note the triple slash) Also supports key ID, alias name, alias ARN, and custom endpoints (e.g. localstack) viaawskms://[endpoint]/[ID/ALIAS/ARN]. - GCP:
gcpkms://projects/$PROJECT/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY/cryptoKeyVersions/$KEY_VERSION. ThecryptoKeyVersions/$VERSIONsuffix (and itsversions/$VERSIONshorthand) is optional and resolves to the key's primary version when omitted. - Azure Key Vault:
azurekms://<vault-name>.vault.azure.net/<key>[/<key-version>]. The host segment is specifically the vault's DNS name, not an arbitrary URI.
Authentication uses each cloud provider's standard credential resolution. A KMS reference URI can also be used as a publickeyid in a policy, so the verifier knows to fetch the public key from the KMS service. For air-gapped verification, a base64-encoded PEM public key can be embedded in the policy directly.
What the verifier checks
When cilock verify runs against a policy, it checks identity by asking:
- Is the signature valid for the envelope?
- Does the signer's certificate or public key match a trusted functionary for this step?
- For X.509 functionaries: do the certificate constraints (commonname, dnsnames, emails, organizations, SPIFFE URIs, trusted roots) match?
For long-term integrity, verifying a years-old signature whose certificate has long since expired, see Timestamping.