name: inverse layout: true class: center, middle, inverse
class: center, middle, title-slide
Andrew McNamara (Red Hat) • Maia Iyer (IBM Research)
+
.footnote[ KubeCon + CloudNativeCon North America · November 10, 2026 ]
???
Andrew and Maia introduce themselves. Andrew: “I’m Andrew McNamara, SLSA maintainer, Konflux/Tekton contributor.” Maia: “I’m Maia Iyer from IBM Research, SPIFFE maintainer and Tornjak contributor.” “Today we’re talking about why workload identity in CI/CD currently has a major identity crisis.”
layout: false
Maia · Identity & Auth
“You wouldn’t ask a plumber to sign off on your electrical work.”
–
Yet in nearly every Kubernetes CI/CD pipeline running today:
ServiceAccount runs every step in the pipeline.–
???
Maia opens the talk. “Think about what happens when a pipeline runs in Kubernetes. Tekton spawns a series of pods for tasks. All of them run in the same namespace, usually under the same service account. If you give that service account an IAM role or a Cosign key, any task that gets compromised can produce any attestation it wants.”
Maia · Identity & Auth
In the cloud-native identity world, we solved machine-to-machine authentication with Workload Identity (SPIFFE/SPIRE).
We said: “No more hardcoded API keys or static credentials in Kubernetes Secrets.”
–
Workload Attestors inspect the running container:
default-tenant)pipeline-runner)prod-cluster-01)spiffe://company.org/ns/default-tenant/sa/pipeline-runner
–
service-a talking to service-b).???
Maia: “From the identity community’s perspective, SPIFFE was a huge leap forward. We eliminated static credentials. But we brought microservice-era assumptions into CI/CD. In a microservice, ServiceAccount ≈ Application. In CI/CD, ServiceAccount ≈ The entire factory, including untrusted PR checkouts, third-party package downloaders, compiler toolchains, security scanners, and release signers. Location alone no longer tells you who is calling.”
Maia & Andrew
When identity is coarse, every pipeline step becomes a potential Confused Deputy:
PipelineRun: build-and-test
├── Task 1: git-clone [SA: runner] ◄── Untrusted code / PRs
├── Task 2: fetch-deps [SA: runner] ◄── Dynamic package downloads
├── Task 3: build-container [SA: runner] ──► Needs builder authority
└── Task 4: trivy-scan [SA: runner] ──► Needs scanner authority
–
git-clone or fetch-deps.regcred or projected SA token).sa/runner, the compromised step can overwrite registry tags or sign false claims.–
???
Maia: “This isn’t hypothetical. Most modern supply chain compromises don’t break crypto; they abuse legitimate credentials running in the wrong context.” Andrew: “Let’s pull up our live cluster and demonstrate how an untrusted step silently hijacks ambient authority to overwrite a production container tag.”
layout: false
???
Andrew runs Act 1 live in the embedded terminal. Walk the audience through:
class: center, middle, inverse
layout: false
Andrew · Pipelines & Architecture
How do pipelines execute in cloud-native Kubernetes?
–
Task: Reusable definition containing steps (container images, commands, env vars).TaskRun: Execution instance that instantiates a Kubernetes Pod to run the steps.Pipeline & PipelineRun: Directed Acyclic Graph (DAG) orchestrating multiple TaskRuns.–
TaskRun.spec.taskSpec, they can execute arbitrary, unvetted binaries.git resolver: Pulls tasks from Git repositories.cluster resolver: Pulls tasks from cluster namespaces.bundles (OCI) resolver: Pulls tasks packaged as immutable OCI artifacts!???
Andrew explains Tekton primitives. “To solve the identity problem, we have to know what code is scheduled before the pod starts running. Tekton Resolvers give us exactly that hook.”
Andrew · Pipelines & Architecture
A Tekton Bundle is a Tekton Task packaged inside an OCI container image layer:
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
generateName: demo-signed-task-
namespace: default-tenant
spec:
taskRef:
resolver: bundles
params:
- name: bundle
value: registry-service.kind-registry/tekton-catalog/demo-catalog-task@sha256:ce7492...
- name: name
value: demo-catalog-task
- name: kind
value: task
–
@sha256:...).taskRef.params.bundle is immediately inspectable before any Pod is scheduled!???
Andrew: “Because the bundle is an OCI artifact pinned by digest, we can treat task definitions the same way we treat container images: we can sign them with Cosign and verify them with Kyverno at admission time.”
Andrew · Pipelines & Architecture
Kyverno intercepts the TaskRun at admission time using a CEL-based ImageValidatingPolicy:
apiVersion: policies.kyverno.io/v1beta1
kind: ImageValidatingPolicy
metadata:
name: verify-bundle-signatures
spec:
validationActions: [Deny]
matchConstraints:
resourceRules:
- apiGroups: ["tekton.dev"]
resources: ["taskruns"]
images:
- name: taskBundle
expression: >-
object.spec.taskRef.params
.filter(p, p.name == "bundle")
.map(p, p.value)
validations:
- expression: >-
images.taskBundle.map(img,
verifyImageSignatures(img, [attestors.catalogKey])
).all(valid, valid > 0)
–
trusted-task-role: prod.trusted-task-role: dev.prevent-pod-label-spoofing) ➔ Blocks pods from forging labels.???
Andrew: “Notice what’s happening here. Kyverno inspects the TaskRun before scheduling. If the bundle is signed by our trusted catalog key, Kyverno promotes the TaskRun label to ‘prod’. An anti-spoofing policy ensures pods cannot self-assign this label.”
Andrew · Pipelines & Architecture
ClusterSPIFFEID evaluates the Kyverno-verified pod labels:
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: konflux-trusted-prod
spec:
spiffeIDTemplate: >-
spiffe://konflux-ci.dev/trusted/cluster-01//
podSelector:
matchLabels:
trusted-task-role: "prod"
–
spiffe://konflux-ci.dev/trusted/cluster-01/runner/trivy-sbom-scanspiffe://konflux-ci.dev/trusted/cluster-01/runner/buildah-oci-taspiffe://konflux-ci.dev/dev/cluster-01/runner/arbitrary-script–
sa/runner, but receive completely different cryptographic identities based on admission-verified task code!
???
Andrew: “Even though all three tasks share the exact same ServiceAccount, they no longer share the same cryptographic identity. The identity is bound to the verified catalog code.”
layout: false
???
Andrew runs Act 2 live:
class: center, middle, inverse
layout: false
Maia · Identity & Auth
What did we just establish?
–
default-tenant:default was enough because the service was single-purpose.–
–
???
Maia reflects on the implications. “This is the critical conceptual pivot. In the identity world, we always say: Authentication is identity; Authorization is policy. But if the identity only says ‘Kubernetes Pod in Namespace X’, downstream services have no signal to authorize. By feeding admission-verified task roles into the SPIFFE ID hierarchy, we give downstream services the exact signal they need.”
Maia · Identity & Auth
Once tasks possess fine-grained cryptographic identities, how do we use them inside the tenant namespace?
–
regcred). Configure the OCI registry with OIDC Bearer auth matching SPIFFE SVIDs—only vetted builder tasks can initiate push sessions.
/keys JWKS endpoint without mounting static Kubernetes Secrets.
???
Maia outlines the three same-namespace patterns. “We now have three immediate use cases inside the same namespace that completely eliminate ambient secrets.”
Maia & Andrew
Zot validates bearer JWTs against SPIRE’s OIDC discovery endpoint (/keys):
{
"repositories": {
"slsa-e2e-test": {
"policies": [{
"users": ["spiffe://konflux-ci.dev/trusted/cluster-01/runner/buildah-oci-ta"],
"actions": ["read", "create"]
}]
}
}
}
HTTP 403 Forbidden.HTTP 202 Accepted.–
trivy-sbom-scan can access the vulnerability feed.???
Andrew explains Zot’s access control policy: “Notice that we don’t need dockerconfigjson secrets in the namespace anymore. Zot accepts the SPIFFE JWT as an OIDC bearer token and checks if the subject is the approved builder task.”
Andrew · Pipelines & Architecture
Each task produces attestations matching its specific domain:
buildah-oci-ta): Signs SBOM (https://spdx.dev/Document/v2.3)trivy-sbom-scan): Signs CVE report (https://aquasecurity.github.io/trivy/report/v1)–
package policy.cve
# Rule: Vulnerability reports MUST be signed by an authorized scanner
deny[msg] {
attestation := input.attestations[_]
attestation.predicateType == "https://aquasecurity.github.io/trivy/report/v1"
# Check certificate identity
not startswith(attestation.certificate.uri,
"spiffe://konflux-ci.dev/trusted/cluster-01/runner/trivy-sbom-scan")
msg := sprintf("CVE scan signed by unauthorized role: %s", [attestation.certificate.uri])
}
–
???
Andrew: “This is the separation of duties punchline. A signature from the cluster isn’t enough. Conforma verifies that the certificate identity matches the role authorized to make that claim.”
layout: false
???
Andrew runs Act 3 live:
class: center, middle, inverse
layout: false
Andrew · Pipelines & Architecture
Does securing task identities protect the entire pipeline? Not if tasks share a disk.
–
PersistentVolumeClaim (PVC) across tasks in a PipelineRun.git-clone writes source $
ightarrow$ build compiles binary $
ightarrow$ package builds container.Task A (build) ──────► [ Shared PVC Workspace ] ◄────── Task B (untrusted test)
│
▼ (tampered files)
Task C (package & sign) ──► Cryptographically valid MALWARE!
–
???
Andrew: “Identity on the control plane is useless if your data plane is compromised. If tasks share a PVC, any task can alter the binaries before they are packaged. Trusted Artifacts replace shared PVCs with immutable OCI storage.”
Maia & Andrew
Build-time tasks in default-tenant must never possess release authority.
–
managed-tenant).–
Downstream consumers verifying a Verification Summary Attestation (VSA) need proof that the entire release pipeline was governed:
trusted-pipeline-role: release-authorityattach-summary-attestations) match!spiffe://konflux-ci.dev/release/demo-app/slsa-e2e-release-dual-gated
???
Maia and Andrew explain dual-gating: “In the release namespace, we don’t just ask if the task is attach-summary-attestations. We ask: is this task running inside an authorized, policy-governed release pipeline? Both conditions must be met simultaneously.”
layout: false
???
Andrew runs Act 4 live:
Maia & Andrew
–
github.com/arewm/slsa-konflux-examplekubecon-na-2026-your-cis-mistaken-identity)
???
Maia and Andrew deliver the closing thoughts.
class: center, middle, inverse
Andrew McNamara (amcnamar@redhat.com) • Maia Iyer (miyer@redhat.com)
github.com/arewm/presentations
github.com/arewm/slsa-konflux-example
layout: false
???
Full uninterrupted demonstration arc from pre-flight baseline to final Rekor verification.