Posted on June 26, 2026 by André Martins (Cilium maintainer and Software Engineer, Isovalent at Cisco) and Feroz Salam (Cilium Security Team and Security Engineer, Isovalent at Cisco)
CNCF projects highlighted in this post
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:
- CI credentials can push to our development image registry (
quay.io/cilium/*-ci) and are available to CI builds. Even if a CI workflow is compromised somehow, these credentials cannot push to production image tags. - Production credentials sit behind the
releaseenvironment, which requires an explicit maintainer approval before a workflow run can touch them. No fork, no feature branch, and no CI build can reach those secrets. Only tag-triggered release builds that a maintainer has approved can.
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:
- Auditing and rotating credentials and permissions across the GitHub organization.
- When necessary, carrying out incident investigation and audits.
- Monitoring for patterns in our security issues and industry developments in order to propose mitigations and controls in areas where our security posture is weak.
Additional layers
A few smaller things worth mentioning:
- Tag immutability. Once a GitHub release is published, the tags and assets attached to it can’t be modified. The setting lives in the repository’s Settings → Releases page.
- DCO sign-off enforcement. Every commit must carry a
Signed-off-by line. Our maintainers-little-helper config blocks merges with adont-merge/needs-sign-offlabel until a sign-off is present. - Third-party security audits. We’ve been audited by ADA Logics, and we maintain a published threat model.
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:
- No SLSA provenance. Every
docker/build-push-actioncall setsprovenance: false. We sign images with Cosign, but we don’t generate SLSA build provenance attestations. Consumers can verify who signed an image, but not how it was built. Adoptingslsa-framework/slsa-github-generator(or at minimum enabling BuildKit-native provenance) is on the list. - No dependency review at PR time. We rely on Renovate’s
vulnerabilityAlertsto flag known-vulnerable dependencies, but that’s reactive. Wiring in actions/dependency-review-action would catch malicious or vulnerable new dependencies before they merge. - No
govulncheckin CI. We fuzz and we lint, but we don’t yet run Go’s official vulnerability scanner, which checks whether our code actually calls vulnerable functions rather than just whether a vulnerable package shows up in go.sum. - 68 internal @main references. A bunch of conformance and scale-test workflows reference
cilium/cilium/.github/actions/set-commit-status@main, which is a mutable branch ref. It’s lower risk than a third-party tag, but inconsistent with our SHA-pinning policy. The plan is to move all of our composite actions out of cilium/cilium into a dedicated repository, which removes the need for @main here.
A few smaller items in the same audit:
- No OpenSSF Scorecard workflow for continuous supply chain health monitoring.
- Our
SECURITY-INSIGHTS.ymlexpired in January 2025 and hasn’t been updated. (We actually noticed this while writing this post.) - No
go mod verifystep to validate vendor directory integrity against go.sum checksums.
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.
















