Ecstaticloud
Initializing0%
Ecstaticloud Logo
Back to Insights
DevSecOpsOctober 10, 2026

Zero-Trust Supply Chains: Securing Kubernetes CI/CD Pipelines with Sigstore and SLSA

Discover how combining Sigstore's cryptographic signing with SLSA framework standards eliminates supply chain vulnerabilities in modern Kubernetes deployment pipelines. This deep-dive explores actionable architectural patterns for guaranteeing artifact provenance from source code commit to production cluster deployment.

In modern cloud-native architectures, the software supply chain has emerged as the path of least resistance for sophisticated threat actors. Attack vectors have evolved from brute-forcing edge perimeters to tampering with third-party dependencies, compromising CI/CD runners, and injecting malicious binaries directly into container registries.

Traditional perimeter-based pipeline security—where code is trusted simply because it originated from an internal Jenkins server or GitHub Actions runner—is fundamentally flawed. To secure Kubernetes production workloads, modern DevSecOps requires a Zero-Trust Supply Chain Model: a paradigm where every artifact, container image, configuration file, and binary must cryptographically prove its identity, lineage, and integrity before being scheduled onto a cluster.

This deep-dive architectural post explores how to pair Sigstore—the Linux Foundation’s open-source standard for code signing—with the SLSA (Supply-chain Levels for Software Artifacts) security framework to establish end-to-end, non-falsifiable artifact provenance from code commit to Kubernetes execution.


The Supply Chain Threat Matrix in Kubernetes

Containerized applications deployed to Kubernetes rely on layers of implicit trust:

  1. Source Code Trust: Assuming Git commits reflect intended developer changes without commit spoofing or malicious PR approvals.
  2. Build System Trust: Assuming CI workers (ephemeral nodes, self-hosted runners) are uncompromised and haven't altered binaries during compilation.
  3. Registry Trust: Assuming the OCI registry hasn't suffered tag mutability attacks or credential leaks that swap safe images with malicious payloads.
+------------------+      +------------------+      +------------------+      +--------------------+
|  Source (Git)    | ---> |  CI Build Node   | ---> |   OCI Registry   | ---> | Kubernetes Cluster |
|                  |      |                  |      |                  |      |                    |
| [Attack Vectors] |      | [Attack Vectors] |      | [Attack Vectors] |      | [Attack Vectors]   |
| - Account Takeover      | - Poisoned Cache |      | - Tag Swapping   |      | - Bypassing Review |
| - Unsigned Commits      | - Secrets Leak   |      | - Stale Digests  |      | - Direct Pod Exec  |
+------------------+      +------------------+      +------------------+      +--------------------+

A Zero-Trust Supply Chain removes implicit trust from every stage of this pipeline. Every artifact pushed to a registry must carry a cryptographic attestation and signature that answers three critical questions at runtime:

  • Who built this image? (Identity verified via OIDC)
  • Where and how was it built? (SLSA provenance attested by a trusted build engine)
  • Has it been tampered with post-build? (Cryptographic digest verification)

The Core Blueprint: SLSA Framework

SLSA (Supply-chain Levels for Software Artifacts) is a security framework that defines incremental levels of software supply chain integrity. Rather than measuring vulnerabilities inside code, SLSA measures the resilience of the software generation pipeline itself.

                   SLSA LEVEL 3
                 +---------------------------------------------+
                 | - Isolated Ephemeral Build Environments     |
                 | - Non-falsifiable Provenance Generation     |
                 | - Cryptographically Signed Metadata          |
                 +---------------------------------------------+
               SLSA LEVEL 2
             +-------------------------------------------------+
             | - Authenticated Build Service                   |
             | - Signed Provenance Produced by Build Engine    |
             +-------------------------------------------------+
           SLSA LEVEL 1
         +-----------------------------------------------------+
         | - Automated Build Process                           |
         | - Basic Provenance Metadata Generated               |
         +-----------------------------------------------------+

To achieve SLSA Build Level 3 (the enterprise production standard), pipelines must satisfy two strict criteria:

  1. Isolated Build Environments: The build executed on dedicated, ephemeral hardware where developer code cannot tamper with the provenance generation process.
  2. Non-Falsifiable Provenance: Provenance metadata must be produced by the build platform (e.g., GitHub Actions engine, Tekton pipeline controller), not by user scripts within the build step.

The cryptographic engine: Sigstore

Sigstore simplifies the complex public key infrastructure (PKI) historically required for cryptographic signing. Instead of managing long-lived, high-risk private GPG or RSA keys that risk leakage, Sigstore uses ephemeral, keyless signing.

Sigstore consists of three core components:

                  +-----------------------------------+
                  |      OIDC Identity Provider       |
                  |   (GitHub, GitLab, Google)        |
                  +-----------------+-----------------+
                                    |
                                    | Short-lived JWT Token
                                    v
+---------------+  Public Key Request  +-------------------+  x509 Cert  +---------------+
|  Cosign CLI   | -------------------> |  Fulcio Root CA   | ----------> |  Cosign CLI   |
+-------+-------+                      +-------------------+             +-------+-------+
        |                                                                        |
        | Sign Digest                                                            | Log Entry /
        v                                                                        | Proof
+---------------+                                                        +-------v-------+
| OCI Registry  |                                                        | Rekor Public  |
|  (Image/Attr) |                                                        | Log (Merkle)  |
+---------------+                                                        +---------------+

1. Fulcio (Ephemeral Certificate Authority)

Fulcio issues short-lived (typically 20-minute) X.509 PKI certificates. Instead of binding certificates to persistent domain names, Fulcio binds them to OpenID Connect (OIDC) identities provided by build systems (e.g., https://github.com/login/oauth issuing identity repo:ecstaticloud/api-service:ref:refs/heads/main).

2. Rekor (Immutable Transparency Log)

Rekor functions as an append-only, tamper-evident ledger built on a Merkle tree (similar to Certificate Transparency logs). When Cosign signs an artifact, the signature, public key, and metadata are published to Rekor. This guarantees that signing events are searchable, auditable, and impossible to retroactively forge or alter without breaking the tree hash.

3. Cosign (Artifact Signing & Verification)

Cosign handles container image signing, key management, and artifact storage within OCI registries. Cosign leverages OCI specs to store signatures, SLSA attestations, and Software Bill of Materials (SBOMs) alongside container manifests as distinct OCI artifacts.


Architecture: End-to-End Keyless Pipeline

The following end-to-end architecture demonstrates a secure pipeline using GitHub Actions (as an isolated builder), Sigstore/Cosign (for signing/attestation), and Kyverno (for Kubernetes policy enforcement).

[ Developer ] --( Git Push )--> [ GitHub Actions Workflow ]
                                       │
                                       ├─► Builds Multi-Arch Docker Image
                                       ├─► Obtains GitHub OIDC Token
                                       ├─► Requests Short-Lived Cert from Fulcio
                                       ├─► Signs Image Digest via Cosign
                                       ├─► Generates SLSA v1.0 Attestation
                                       ├─► Pushes Image + Attestation to Registry
                                       └─► Logs Cryptographic Proof to Rekor
                                                                │
                                                                ▼
                                                   [ OCI Registry (GHCR/GAR) ]
                                                                │
                                                                ▼
[ K8s Deployment Manifest Applied ] ------------> [ Kyverno Admission Controller ]
                                                                │
                                                                ├─► Intercepts Pod Creation Request
                                                                ├─► Queries Rekor & Registry for Signatures
                                                                ├─► Validates Ephemeral Cert against Fulcio Root
                                                                ├─► Verifies SLSA Provenance Predicate
                                                                │
                                     [ ALLOW / DENY Deployment based on Policy ]

Hands-On Implementation

Phase 1: Keyless Signing and SLSA Attestation in CI

The following GitHub Actions workflow compiles a Go application, builds an OCI image, generates an in-toto SLSA attestation, and signs the image using Cosign keyless mode.

name: Secure Build & Attestation Pipeline

on:
  push:
    branches: [ "main" ]
    tags: [ "v*.*.*" ]

permissions:
  contents: read
  packages: write
  id-token: write # Required for fetching OIDC token for Keyless Sigstore

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    outputs:
      image-digest: ${{ steps.build-image.outputs.digest }}
      image-ref: ${{ steps.build-image.outputs.ref }}
    
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Install Cosign
        uses: sigstore/cosign-installer@v3.3.0

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Metadata for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
          tags: type=sha,format=long

      - name: Build and Push OCI Image
        id: build-image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Sign Image Digest (Keyless)
        env:
          TAGS: ${{ steps.meta.outputs.tags }}
          COSIGN_EXPERIMENTAL: "1"
        run: |
          # Sign using the ephemeral OIDC token issued to this job execution
          cosign sign --yes \
            -a "repo=${{ github.repository }}" \
            -a "sha=${{ github.sha }}" \
            -a "workflow=${{ github.workflow }}" \
            ${{ steps.meta.outputs.tags }}@${{ steps.build-image.outputs.digest }}

  generate-slsa-provenance:
    needs: build-and-sign
    permissions:
      actions: read
      id-token: write
      packages: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0
    with:
      image: ghcr.io/${{ github.repository }}
      digest: ${{ needs.build-and-sign.outputs.image-digest }}
      registry-username: ${{ github.actor }}
    secrets:
      registry-password: ${{ secrets.GITHUB_TOKEN }}

What Happens Here?

  1. OIDC Token Issuance: The job requests an OIDC token from GitHub (id-token: write).
  2. Keyless Signing: cosign sign exchanges this token with Fulcio for an ephemeral X.509 certificate, signs the immutable image digest (sha256:...), writes the signature to GHCR, and logs the proof entry into Rekor.
  3. SLSA Generator Execution: The official slsa-framework/slsa-github-generator runs as an isolated reusable workflow. Because it runs separately from the user build code, it creates a non-falsifiable in-toto SLSA attestation predicate linked directly to the build execution context.

Phase 2: In-Cluster Enforcement with Kyverno

Creating signed images means little if Kubernetes accepts unsigned, arbitrary images. We enforce trust at runtime using an admission controller.

Below is a production-grade Kyverno ClusterPolicy that intercepts pod deployments in the production namespace. It verifies that:

  1. The container image was signed by Cosign via keyless Sigstore.
  2. The identity embedded in the certificate matches our specific GitHub repository and workflow.
  3. A valid SLSA v1.0 provenance attestation exists and was generated by the trusted SLSA generator.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-zero-trust-supply-chain
  annotations:
    policies.kyverno.io/title: Enforce Sigstore & SLSA Provenance
    policies.kyverno.io/subject: Pod, Deployment
    policies.kyverno.io/description: >-
      Blocks any pod deployment whose image lacks keyless Sigstore signatures 
      or valid SLSA Build Level 3 provenance from the official repository.
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: verify-image-signature-and-slsa-provenance
      match:
        any:
        - resources:
            namespaces:
              - production
            kinds:
              - Pod
              - Deployment
      verifyImages:
        - imageReferences:
            - "ghcr.io/ecstaticloud/*"
          mutateDigest: true
          verifyDigest: true
          required: true
          keyless:
            rekor:
              url: https://rekor.sigstore.dev
            issuer: "https://token.actions.githubusercontent.com"
            subject: "https://github.com/ecstaticloud/*"
          attestations:
            - predicateType: https://slsa.dev/provenance/v1
              attestors:
                - entries:
                    - keyless:
                        issuer: "https://token.actions.githubusercontent.com"
                        subject: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v1.9.0"
              conditions:
                all:
                  - key: "{{ builder.id }}"
                    operator: Equals
                    value: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v1.9.0"

Technical Edge Cases & Operational Hardening

Transitioning to a Zero-Trust supply chain introduces real-world edge cases that demand careful architectural planning.

1. Multi-Arch Builds and Digest Instability

When building images for multi-architecture clusters (e.g., linux/amd64 and linux/arm64), Docker creates an OCI Image Index (Manifest List) that points to platform-specific image manifests.

  • The Pitfall: Signing individual platform manifests directly instead of the Index root digest breaks multi-arch deployment validation in Kubernetes.
  • The Architecture Solution: Always target the manifest index digest during the cosign sign and verification phase.
# Correct: Target the manifest list digest directly
cosign sign --yes ghcr.io/ecstaticloud/api-service@sha256:index_digest_hash...

2. Air-Gapped / Private Kubernetes Environments

Public Sigstore infrastructure relies on rekor.sigstore.dev and fulcio.sigstore.dev. If your Kubernetes cluster operates in a highly restricted or air-gapped environment (e.g., PCI-DSS, FedRAMP):

  • Solution: Deploy a private instance of the Sigstore Scaffold (Fulcio, Rekor, Trillian) inside your internal networking boundary.
  • Configure Cosign and admission controllers (Kyverno or Sigstore Policy Controller) to trust your private internal Certificate Authority (CA) root instead of the public Fulcio CA.
# Pointing Kyverno to a Private Sigstore Infrastructure
keyless:
  rekor:
    url: https://rekor.internal.ecstaticloud.com
  roots: |
    -----BEGIN CERTIFICATE-----
    <INTERNAL_FULCIO_ROOT_CA_PEM>
    -----END CERTIFICATE-----

3. Ephemeral Runner Secrets Exposure

OIDC keyless signing relies on the JWT identity token generated by the CI runner. If a rogue step in your build workflow exposes this token before cosign sign executes, an attacker with real-time access could sign an arbitrary binary during the token's active lifetime.

  • Mitigation: Strict separation of build and sign stages using dedicated, isolated build jobs. Never expose the raw id-token to untrusted user scripts or unpinned third-party CI actions.

Verifying Supply Chain Integrity at Runtime

To verify that your supply chain policies are functioning before enforcing them in production, execute manual verifications via the cosign CLI:

# Verify Keyless Signature against Public Rekor Log
cosign verify \
  --certificate-identity-regexp="https://github.com/ecstaticloud/.*" \
  --certificate-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/ecstaticloud/api-service:sha-f82a912

# Inspect Raw SLSA Provenance Attestation Payload
cosign verify-attestation \
  --type https://slsa.dev/provenance/v1 \
  --certificate-identity-regexp="https://github.com/slsa-framework/.*" \
  --certificate-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/ecstaticloud/api-service:sha-f82a912 | jq '.payload | @base64d | fromjson'

If an attacker modifies a single layer of a container image post-build, the SHA-256 digest shifts, immediately invalidating the cryptographic relationship with the Signature in Rekor. The Kubernetes Admission Controller blocks deployment instantly:

Error from server (Forbidden): admission webhook "validate.kyverno.svc" denied the request: 
[verify-image-signature-and-slsa-provenance] failed: image ghcr.io/ecstaticloud/api-service:latest 
failed signature verification: no matching signatures found in Rekor entry for digest sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Architectural Summary Checklist

Implementing a complete Zero-Trust Kubernetes Supply Chain requires hardening at each layer:

| Pipeline Stage | Security Control | Technology Stack | | :--- | :--- | :--- | | Commit | Enforce commit signing via SSH/GPG keys | Git / GitHub Enterprise | | Build | Ephemeral, isolated builders with minimal permissions | GitHub Actions / Tekton | | Identity | Short-lived identity assertions via OIDC | Fulcio / OIDC Providers | | Signing | Keyless artifact & digest signing | Cosign | | Provenance | Isolated Level 3 in-toto SLSA attestation | SLSA Framework | | Audit Log | Immutable, append-only cryptographic logging | Rekor | | Runtime Enforcement| Mandatory admission verification before Scheduling | Kyverno / Policy Controller |

By replacing long-lived signing keys with keyless OIDC authentication via Sigstore, and enforcing SLSA Level 3 build provenance directly inside Kubernetes Admission Control, you transform your pipeline from a target into a fortress. Trust is no longer assumed—it is cryptographically proven at every step of the journey to production.