BIPI
BIPI

Securing GitHub Actions: OIDC, Pinned Actions, and Reusable Workflows

Digital Engineering

GitHub Actions is now the build system for most of the software industry, which makes it one of the most valuable supply chain targets in existence. We walk through the three patterns that actually move the security needle: OIDC for cloud access, SHA-pinned actions, and reusable workflows that centralize policy.

By Arjun Raghavan, Security & Systems Lead, BIPI · August 23, 2023 · 9 min read

#github-actions#ci/cd-security#oidc#supply-chain#reusable-workflows

GitHub Actions ate the CI market in about four years. It is fast, free for open source, and dead simple to adopt. It is also a sprawling, third-party-code-eating attack surface that most teams configure with the same care they give their cron jobs.

The codecov bash uploader compromise was a wakeup call. So was the tj-actions/changed-files incident pattern that keeps recurring. The defenses are well known. The hard part is rolling them out across hundreds of repositories.

OIDC for cloud access, not static secrets

The single biggest improvement is replacing static cloud credentials with OIDC tokens. GitHub Actions can mint a short-lived JWT for every workflow run, and AWS, GCP, and Azure can all federate that JWT into temporary credentials. No long-lived access key in a secret, no rotation problem, no leaked credential blast radius.

  • AWS: configure an IAM role with a trust policy on token.actions.githubusercontent.com, use AssumeRoleWithWebIdentity
  • GCP: configure Workload Identity Federation pointed at the GitHub OIDC issuer
  • Azure: configure a federated credential on a managed identity, scope to the repo and branch
  • Pin the trust policy to specific repos, branches, and environments, never use wildcards

The trust policy is the security control. A wildcard on the subject claim lets any workflow in your org assume the role. Scope it tightly to repo:org/name:ref:refs/heads/main or to a specific environment.

Pin actions by commit SHA, not by tag

Every uses: line in a workflow is a third-party dependency. Tags are mutable. A tag that pointed at safe code yesterday can point at malicious code today, and your workflow will happily pull it in. Pin every action by full commit SHA, and use Dependabot or Renovate to update the SHA with a PR that includes a diff.

If your workflows reference actions by tag, you have outsourced the trust decision to whoever can push to that tag.

Reusable workflows for policy

Reusable workflows let you write the deploy pipeline once and have every repo call it. That is a productivity win, but the security win is bigger. You can enforce signing, SBOM generation, dependency scanning, and OIDC patterns inside the reusable workflow, and no individual repo can bypass them by editing their local file.

  1. Create a .github repo in your org with reusable workflows for build, test, and deploy
  2. Embed cosign signing, syft SBOM generation, and trivy scanning inside the reusable workflow
  3. Require all production deploys to use the reusable workflow, enforce via branch protection or org policy
  4. Audit the calling pattern monthly, repos that bypass the reusable workflow are the risk surface

The permissions block

Every workflow should declare permissions explicitly at the top. The default GITHUB_TOKEN has more access than most workflows need. Drop it to read-only and grant write only where required. permissions: contents: read, plus id-token: write for OIDC, plus packages: write for image pushes, is a typical minimal set.

Self-hosted runners are a sharp tool

Self-hosted runners give you access to private networks but introduce a class of attacks that hosted runners do not have. Persistent runners can be poisoned across jobs. PR workflows from forks can execute on your runner if you do not gate them. If you use self-hosted runners, make them ephemeral, isolate them per workload, and never run untrusted PRs on them without explicit approval.

Closing

GitHub Actions security is not exotic. OIDC, SHA pins, reusable workflows, and tight permissions are the four patterns that handle most of the risk. Roll them out across your org as a platform program, not as repo-by-repo hygiene, and you close the most common attack paths in modern CI.

Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.