This is the third and final post in a series on how Cilium hardens its CI/CD pipeline. Part 1 covered access control and Part 2 covered dependency hardening. This post covers the last layer: keeping CI and production credentials isolated, signing and attesting every release, and the gaps we’re still working to close.

Protecting credentials

We assume any individual layer can fail. If a CI workflow ever gets compromised, it’s important the attacker can’t reach anything that matters.

Strong defaults

By default our GITHUB_TOKENs are scoped to minimal read permissions on contents and packages. Workflows that need anything more have to opt in explicitly, so a workflow that forgets to declare permissions doesn’t end up with broad org-wide write access.

We keep two distinct sets of registry credentials behind separate GitHub protected environments:

Worst-case, in a CI compromise, the attacker can publish a malicious -ci image. They cannot publish to quay.io/cilium/cilium:v1.x.x or docker.io/cilium/cilium:v1.x.x. The credentials simply aren’t on the runner.

Every actions/checkout call also sets persist-credentials: false, so the GITHUB_TOKEN never ends up in the runner’s git config where a later step could grab it.

Signing and attesting what we ship

Every container image we release (cilium, operator-*, hubble-relay, clustermesh-apiserver) is signed with Sigstore Cosign using keyless OIDC. There are no long-lived signing keys for anyone to steal.

A reusable composite action handles the signing pipeline:

.github/actions/cosign/action.yaml
- name: Install Cosign
  uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1

- name: Generate SBOM
  uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
  with:
    artifact-name: sbom_${{ inputs.sbom_name }}.spdx.json
    output-file: ./sbom_${{ inputs.sbom_name }}.spdx.json
    image: ${{ inputs.image_tag }}

- name: Sign Container Image
  shell: bash
  run: cosign sign -y "${{ inputs.image }}"

- name: Attach SBOM Attestation
  shell: bash
  run: |
    cosign attest -y \
      --predicate "./sbom_${{ inputs.sbom_name }}.spdx.json" \
      --type spdxjson \
      "${{ inputs.image }}"

This runs for every release image build and for our Helm chart OCI artifacts. Verification instructions are in the Cilium docs.

Release builds also run inside protected environments (release, release-tool, release-helm) so production registry credentials are gated behind environment protection rules. You can’t trigger a release build from a fork or a feature branch.

The Cilium security team

If you’ve ever reported a security issue to the project (via GitHub security advisories or security@cilium.org), you’ve already interacted with Cilium’s Security Team. Beyond triaging vulnerability reports, the team also runs the operational side of supply chain security:

Additional layers

A few smaller things worth mentioning:

What we’re still working on

We audited our .github/ directory against current best practices (OpenSSF Scorecard, SLSA, StepSecurity recommendations) and turned up a number of real gaps. The bigger ones:

A few smaller items in the same audit:

If any of these look like a good first issue, please send a PR.

GitHub’s 2026 Actions security roadmap and how it maps to what we do

In April 2026, GitHub published their Actions security roadmap describing platform-level changes across three layers: ecosystem, attack surface, and infrastructure. Reading it felt like validation of problems we’ve been working around for years, and a real signal that the platform is finally catching up to what large open source projects need. Here’s how it maps to what we do today.

Dependency locking: making SHA pinning first-class

We pin every action by SHA and lean on Renovate to keep those pins current, but we still have a blind spot for transitive references. GitHub’s planned dependencies: section in workflow YAML would lock all direct and transitive dependencies by commit SHA, with hash verification before execution starts. That closes the gap.

Policy-driven execution: centralizing what we enforce per-file today

We restrict who can trigger workflows (Ariane’s allow-list), which events are allowed (per-workflow configuration), and who can approve releases (protected environments). All of that is currently encoded across dozens of YAML files plus a custom bot, and auditing the full picture means reading every file.

GitHub’s planned workflow execution protections, built on rulesets, would let us define those controls centrally at the org level: which actors can trigger workflows, which events are permitted, which repositories the rules apply to. We could prohibit pull_request_target org-wide except for the workflows where we’ve intentionally designed a safe two-phase checkout, instead of relying on code review and CODEOWNERS to enforce it.

Scoped secrets: closing the implicit inheritance gap

CI vs. production credential isolation is one of our strongest controls, but within a given environment, secrets are still scoped pretty broadly: any workflow running in that environment can access them.

Scoped secrets would let us bind credentials to specific workflow paths, branches, or even individual reusable workflows. A release credential could be restricted not just to the release environment but to the specific release.yaml workflow file, so a new workflow added to that environment (by accident or by an attacker) wouldn’t inherit the credentials. 

The roadmap also separates secret management from repository write access. GitHub plans to move secret management into a dedicated custom role, which lines up with the least-privilege principle we already apply to workflow permissions but can’t currently apply to secret administration.

Native egress firewall

GitHub’s planned native egress firewall would restrict outbound network access from GitHub-hosted runners. It runs outside the runner VM at L7, so it’s immutable even if an attacker gets root inside the runner. Organizations would define allowed domains, IP ranges, and HTTP methods, and anything else gets blocked.

For Cilium it’s less critical than the rest. Our most security-sensitive workflows already run with credential isolation and least-privilege permissions, which limits what a compromised step could do even with unrestricted network access. Building an accurate egress allow-list would be a significant chunk of work. Public preview is expected in 6 to 9 months, so we’ll evaluate then.

Actions data stream: making CI observable

Our workflows produce logs, but we don’t have centralized telemetry for them. If a workflow starts behaving oddly (resolving unexpected dependencies, running longer than usual, making strange network calls), we’d have to notice it manually.

Actions Data Stream would deliver near real-time execution telemetry to external systems (S3, Azure Event Hub), covering workflow execution details, dependency resolution patterns, and eventually network activity.

The point

Supply chain security is mostly the practice of repeatedly asking “what if this thing I trust gets compromised?” and adding a layer that limits the blast radius when it does.

We’ve tried to build defense in depth: access controls so only trusted people can trigger builds, pinned digests so a compromised tag can’t reach us, least-privilege permissions so a rogue action can’t exfiltrate secrets, credential isolation so CI can never touch production, and signatures so users can verify what they’re running.

None of this makes us invulnerable. But security by obscurity isn’t really a thing, and the inverse is also true: the more open source projects share their defenses openly, the higher the collective bar for attackers. We’ve shown you ours, including the parts that aren’t great yet. If you’re running CI/CD for an open source project and you’ve solved something we haven’t, open an issue, write your own post, or come tell us on Slack. The open source supply chain is only as strong as its weakest project, and the only way to strengthen it is together.

André Martins is a Cilium maintainer and Software Engineer, Isovalent at Cisco. Feroz Salam is a member of the Cilium Security Team and a Security Engineer, Isovalent at Cisco. Find Cilium on GitHub and join the community on Slack.