Skip to main content

Kubernetes Workload Attestor

The Kubernetes attestor identifies workloads by querying the Kubernetes API for the pod that owns the requesting process.

Configuration

Enable the Kubernetes attestor in the WorkloadAttestation section:

section: WorkloadAttestation
schema: v1
spec:
kubernetes:
enabled: true
includeAnnotationPrefixes:
- "example.com/"
FieldDefaultDescription
kubernetes.enabledtrueEnable or disable Kubernetes attestation
kubernetes.includeAnnotationPrefixes[]Annotation key prefixes to include as attributes. Empty means no annotations. When applied via Managed Configuration, changes propagate live without a restart.
kubernetes.sigstoreOptional. Configures Sigstore image-signature verification. See Sigstore Image Verification below.

Attributes

The following attributes are collected for workloads running in Kubernetes-based platforms (e.g. k8s) and can be used in path templates, JWT custom claims, and X.509 Subject customization. Some attributes are restricted to specific surfaces — see the Notes column.

Kubernetes AttributePath Template VariableNotes
Pod Image Countkubernetes.pod.image_countNumber of containers in the pod. E.g. 1
Pod Init Image Countkubernetes.pod.init_image_countNumber of init containers in the pod. E.g. 0
Pod Namekubernetes.pod.name
Namespacekubernetes.pod.namespace
Pod UIDkubernetes.pod.uid
Pod Node Namekubernetes.pod.node.name
Pod Ownerkubernetes.pod.ownerOwner of the pod, formatted as Type:Name. E.g. ReplicaSet:my-replicaset-5cfd45f6c9. See note below.
Pod Owner UIDkubernetes.pod.owner_uidUID of the pod's owner. E.g. 316ea285-b878-4d20-a9fe-2e1c79b0f083. See note below.
Service Accountkubernetes.pod.service_account
Pod Container Image Namekubernetes.pod.container.<container_name>.image.nameOne entry per container in the pod. Not available in path templates.
Pod Container Image IDkubernetes.pod.container.<container_name>.image.idOne entry per container in the pod. Not available in path templates.
Pod Init Container Image Namekubernetes.pod.init_container.<container_name>.image.nameOne entry per init container in the pod. Not available in path templates.
Pod Init Container Image IDkubernetes.pod.init_container.<container_name>.image.idOne entry per init container in the pod. Not available in path templates.
Pod Labelkubernetes.pod.label[<label_key>]One entry per label on the pod
Pod Annotationkubernetes.pod.annotation[<annotation_key>]One entry per allowlisted annotation on the pod
Container Namekubernetes.container.nameDisabled by default. See below.
Container Image Namekubernetes.container.image.nameDisabled by default. See below.
Container Image IDkubernetes.container.image.idDisabled by default. See below.
Image Signature Subjectkubernetes.image.signature.subjectEmitted only when Sigstore verification succeeds. See note below.
Image Signature Issuerkubernetes.image.signature.issuerEmitted only when Sigstore verification succeeds. See note below.
Image Signature Valuekubernetes.image.signature.valueEmitted only when Sigstore verification succeeds. See note below.
Image Signature Log IDkubernetes.image.signature.log_idEmitted only when Sigstore verification succeeds. See note below.
Image Signature Log Indexkubernetes.image.signature.log_indexEmitted only when Sigstore verification succeeds. See note below.
Image Signature Integrated Timekubernetes.image.signature.integrated_timeEmitted only when Sigstore verification succeeds. See note below.
Image Signature Signed Entry Timestampkubernetes.image.signature.signed_entry_timestampEmitted only when Sigstore verification succeeds. See note below.
Pod owner attributes

kubernetes.pod.owner and kubernetes.pod.owner_uid are derived from the pod's OwnerReferences. If there are multiple entries, the last owner in OwnerReferences is used.

Label and annotation keys with special characters

Pod label and pod annotation keys containing forward slashes (/) or dashes (-) require Trust Domain Server version 0.28.0 or newer. On earlier versions, configuration using these keys will fail synchronization, and the server will remain on its previous configuration.

Annotation allowlist

Pod annotations are emitted only for keys matching an allowlisted prefix. Configure prefixes via kubernetes.includeAnnotationPrefixes in the WorkloadAttestation managed configuration section. For example, to expose the annotation example.com/my-annotation:

section: WorkloadAttestation
schema: v1
spec:
kubernetes:
includeAnnotationPrefixes:
- "example.com/"
Enabling container attributes

Container attributes must be enabled by setting includeContainerAttributes: true in the relevant platform block (e.g. k8s, istio) of the spirl-system Helm values.

Workload container vs. pod container attributes

The kubernetes.container.* attributes describe the container running the attested workload. To access attributes of other containers in the same pod, use the kubernetes.pod.container.<container_name>.* attributes instead.

Image signature attributes

kubernetes.image.signature.* attributes are emitted only when the agent successfully verifies the workload's container image against your configured Sigstore trust policy. Verification is opt-in and requires the kubernetes.sigstore block in WorkloadAttestation.

Sigstore Image Verification

The Kubernetes attestor can additionally verify Sigstore signatures on a workload's container image and expose the verified signature metadata as attestation attributes. Trust policies can then condition SVID issuance on who signed the image: For example, by specifying that production workloads must run an image signed by your release CI workflow.

Why Verify Image Signatures

Container registries are a supply-chain entry point. Attackers have published malicious images on Docker Hub under names that mimic real projects, hoping these images are pulled into production clusters. Sigstore mitigates this class of attack by letting image publishers cryptographically sign their images, and consumers verify those signatures before trusting the image. This applies equally to public images and to images your own CI builds for internal use.

When the agent verifies a signature, it records who signed it, which OIDC provider vouched for them, and proof from the Rekor transparency log that the signature was created while the signing certificate was valid. Trust policies can use these attributes to decide whether to issue an SVID at all, and what privileges that SVID carries.

Sigstore Attributes

When verification succeeds, the agent emits:

AttributeTypeDescription
kubernetes.image.signature.subjectstringIdentity that signed the image (e.g. a CI workflow URL or signer email)
kubernetes.image.signature.issuerstringOIDC issuer that vouched for the signer
kubernetes.image.signature.valuestringBase64-encoded signature bytes
kubernetes.image.signature.log_idstringIdentifier of the Rekor instance that logged the entry
kubernetes.image.signature.log_indexuint64Monotonic index of the entry within that Rekor instance
kubernetes.image.signature.integrated_timeuint64Unix timestamp at which Rekor recorded the entry
kubernetes.image.signature.signed_entry_timestampstringRekor's signed inclusion promise for the entry
Gate on presence

These attributes are left out (omitted) whenever verification fails — see Failure Behavior. A missing subject is not a denial signal; it just means the agent did not produce a successful verification. Trust policies should require these attributes to be present in order to grant the privileges that depend on them.

Using Sigstore Attributes in Policy

The subject and issuer attributes are the primary handles for trust decisions. Use them together to pin both the signer and the IdP that issued their identity:

AttributeHow it's useful in a trust policy
subjectSpecify who must have signed the image — e.g. require a specific release CI workflow, not an arbitrary developer or unrelated workflow in the same org.
issuerPair with subject to also pin which IdP vouched for the signer — e.g. only accept identities issued by your corporate OIDC provider.
log_idRequire entries from a specific Rekor instance — e.g. only accept signatures logged in your private Rekor, not the public one.
integrated_timeEnforce recency — reject SVIDs whose images were signed before a known cutoff (e.g. a key-rotation event), or too long ago to be a fresh build.
log_indexReject entries below a cutoff index — useful for invalidating everything logged before a known incident without rotating the entire Rekor instance.
valueRarely used in policy directly. Most useful as an audit record of which signature was honored when the SVID was issued.
signed_entry_timestampRarely used in policy directly. Most useful as an audit artifact you can re-verify offline to prove the entry was in the log at issuance time.

Sigstore Configuration

Enable Sigstore verification under the kubernetes block of the WorkloadAttestation section:

section: WorkloadAttestation
schema: v1
spec:
kubernetes:
enabled: true
sigstore:
enabled: true
allowedIdentities: # Required.
# OIDC issuer URL → list of allowed subjects. Globbing supported in both.
"https://token.actions.githubusercontent.com":
- "https://github.com/myorg/myrepo/.github/workflows/release.yaml@refs/heads/main"
- "https://github.com/myorg/*/.github/workflows/release.yaml@refs/heads/main"
rekorURL: https://rekor.sigstore.dev # Optional, defaults to this.
skipProvenance: false # Optional, defaults to this.
skipTransparencyLog: false # Optional, defaults to this.
FieldDefaultDescription
sigstore.enabledRequired when the sigstore block is present. See enabled below.
sigstore.allowedIdentitiesRequired when enabled: true. Map of OIDC issuer URLs to allowed subjects. See allowedIdentities below.
sigstore.rekorURLhttps://rekor.sigstore.devRekor instance to use. See rekorURL below.
sigstore.skipProvenancefalseWhen false, a SLSA provenance attestation is also required. See skipProvenance below.
sigstore.skipTransparencyLogfalseWhen false, signatures are checked against Rekor. See skipTransparencyLog below.

Hot configuration reloads are supported. When applied via Managed Configuration, changes propagate live without an agent restart.

enabled

Set to true to turn on Sigstore verification. Required whenever the sigstore block is present — there is no implicit default.

allowedIdentities

A map of allowed OIDC issuer URLs to the list of subjects allowed under each. Must contain at least one issuer with at least one subject.

Patterns use globs rather than regular expressions, because it's much harder to write a glob that accidentally matches everything than it is to leave a regex unanchored:

  • * matches any sequence of characters, including none.
  • ? matches exactly one character.
  • The pattern is anchored: it must match the entire string.
  • Character classes, alternation, and other regex syntax are not supported.

To accept any subject from a given issuer, use ["*"]. Avoid this on a public issuer such as GitHub Actions — it allows any GitHub workflow in any organization to sign images you'll trust.

Anchor hostname patterns

A pattern like https://*.github.com* (note the trailing *) matches https://anything.github.com.attacker.example — almost certainly not what you want. Anchor the suffix: https://*.github.com/..., or omit the trailing wildcard.

rekorURL

The Rekor transparency-log instance the agent queries when verifying signatures. Defaults to the public Sigstore Rekor at https://rekor.sigstore.dev. Override only if you run your own instance. Must be an HTTPS URL.

skipProvenance

Controls whether the agent additionally verifies a SLSA provenance attestation after signature verification. See Provenance Attestations below for what provenance is and why it matters.

When false (default), a valid provenance attestation must exist and be signed by an identity matching allowedIdentities. If provenance verification fails, the entire kubernetes.image.signature.* attribute set is rejected for that image.

When true, the provenance step is skipped. Use this for images that are signed (cosign sign) but don't have provenance — common outside highly regulated environments.

skipTransparencyLog

Controls whether signatures are verified against the Sigstore transparency log (Rekor).

When false (default), the agent checks Rekor to confirm the signature was created while the signing certificate was still valid. This is required for keyless signing with short-lived Fulcio certificates, which is the most common Sigstore setup.

When true, the Rekor check is skipped. Use this only if your images are signed with long-lived keys, or if you cannot reach the public Rekor and have configured a private instance via rekorURL.

warning

Setting skipTransparencyLog: true causes verification to fail for keyless-signed images. Only set it if you are not using keyless signing.

Provenance Attestations

A provenance attestation is a separate signed statement, stored alongside the image, that records facts about how the image was built — which commit, which CI workflow, which build runner. It's signed by your build system's identity (e.g. GitHub Actions), not by a developer.

Even if an attacker pushes a tampered image to your registry, they cannot forge the provenance from your CI signing identity. By default, the agent verifies both the signature and the provenance attestation against allowedIdentities before emitting any signature attributes. If your images are signed but do not have provenance, set skipProvenance: true.

Image publishers produce signatures with cosign sign and provenance with cosign attest; consumers verify them with cosign verify and cosign verify-attestation.

Operational Notes

Failure Behavior

Sigstore verification is fail-open with respect to attestation. If verification fails for any reason — image not signed, signature does not match allowedIdentities, Rekor unreachable, network timeout, missing provenance — the workload's attestation still succeeds, but the kubernetes.image.signature.* attributes are omitted and a warning is logged.

This is intentional: a transient Rekor outage should not take down credential issuance for every workload. The implication is the same as the warning above — trust policies must require these attributes to be present, not check them for a "valid" flag.

Templates are an exception. If a path template, X.509 SVID template, or JWT claim references a kubernetes.image.signature.* attribute and that attribute is absent, SVID issuance fails with a missing-attribute error rather than producing a malformed SVID. Reference these attributes from templates only on workloads where Sigstore verification is expected to succeed.

Verification Caching

Successful verifications are cached per image (by digest) with a 5-minute TTL. Failures are never cached.

Practical implications:

  • After publishing a new image, verification happens on the first attestation and is then served from cache for ~5 minutes.
  • If you tighten allowedIdentities to revoke a previously trusted signer, in-flight cached results may persist for up to 5 minutes. The cache is dropped when central config is reloaded.

Registry Authentication

The agent authenticates to private registries using node-level IAM credential helpers (GCR, ECR, ACR) — whatever the underlying node's instance role is allowed to pull, the agent can pull.

imagePullSecrets are not supported

Workloads pulling images via imagePullSecrets will have Sigstore attributes omitted. The failure is logged, but as a generic registry auth error from the underlying pull — not as an explicit "imagePullSecrets not supported" diagnostic. Full imagePullSecrets support requires the agent to read namespaced Secrets and is not yet available. Confirm your image-pull path uses node-level IAM credentials before relying on Sigstore attributes in trust policy.

Multiple Signatures

When an image has more than one valid signature matching allowedIdentities, only the first is used to populate attributes. A log line is emitted when this occurs.

Observability

When Sigstore attributes are not appearing as expected:

  1. Check the agent logs for warnings naming the image — every verification failure logs a reason.
  2. Inspect the Sigstore metrics described below to confirm the agent is attempting verification on the image you expect, and to see why it failed.
  3. Confirm registry credentials — if the agent cannot pull image metadata, verification cannot run.

The agent emits the following Prometheus metrics. Every metric carries an attestor label (e.g. k8s) so dashboards and alerts can be scoped to a single attestor.

MetricKey LabelsWhat it measures
spirl_agent_sigstore_image_verification_totalresult
attestor
Counter of verification attempts, classified by result
spirl_agent_sigstore_image_verification_duration_secondsresult
attestor
Histogram of how long each verification took, classified by result
spirl_agent_sigstore_signature_countattestorHistogram of valid signatures found per image — recorded only on successful verification
spirl_agent_sigstore_verification_cache_totalresult
attestor
Counter of cache lookups, where result is hit or miss

The result label on the two _image_verification_* metrics takes one of:

ValueMeaning
verifiedVerification succeeded
not_signedImage had no Sigstore signatures
identity_mismatchSignature did not match allowedIdentities
network_errorRegistry or Rekor network failure
timeoutVerification did not complete within the agent's deadline
cancelledContext cancelled (typically the workload disconnected)
errorAny other failure

As the cache fills, signature-count and verification-duration observations naturally fall in inverse proportion to the rise in cache_total{result="hit"} — a cache hit short-circuits the verification path.