Skip to content

SRE-904: Split token minting from the Renovate run - #99

Merged
TimDiekmann merged 5 commits into
mainfrom
sre-904/renovate-job-split
Aug 10, 2026
Merged

SRE-904: Split token minting from the Renovate run#99
TimDiekmann merged 5 commits into
mainfrom
sre-904/renovate-job-split

Conversation

@claude

@claude claude Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Requested by Tim Diekmann · Slack thread

SRE-904

Before

housekeeping-dependencies.yml runs everything in one job that holds permissions: id-token: write. A compromised package pulled in by the install-renovate composite action — or a compromise in Renovate itself — executes in the same job that can authenticate to Vault as ci-renovate. For the lifetime of the run it could ask Vault Transit to sign fresh App JWTs for the hash-dependencies App and mint new installation tokens of its own choosing, well beyond the single token the workflow hands to Renovate. npm ci --ignore-scripts from the committed lockfile (SRE-901) keeps install-time code out, but runtime dependency code still runs next to the OIDC permission.

After

Two jobs with disjoint privileges:

  • mint-token is the only job with id-token: write, and it installs nothing — it runs only the existing github-app-token composite action (vault-action + the curl/openssl token.sh, unchanged) plus one openssl enc step. No npm, no node_modules, so no dependency code ever executes next to the Vault credential.
  • renovate has no id-token permission at all (actions: read, contents: read only — what the cache download and run already used). The worst a compromised dependency can reach here is the one installation token it was going to be handed anyway: valid for an hour, scoped to the calling repository. It can no longer trade that position up into fresh Vault-signed tokens.

lint.yml also installs the Renovate dependency tree but never held id-token: write, so there is nothing to split there; it instead gets an explicit permissions: contents: read so its dependency-installing job runs with a read-only GITHUB_TOKEN rather than whatever the default grant allows.

How the token crosses the job boundary

GitHub silently drops masked secret values from job outputs, so the plaintext token cannot be passed between jobs — which is exactly the property we lean on: the mint job encrypts the token (openssl enc -aes-256-cbc -pbkdf2 -salt, passphrase from the new RENOVATE_TOKEN_ENC_KEY secret) and exposes only the ciphertext as a job output. The Renovate job's first step decrypts it and immediately ::add-mask::es the plaintext before any other code runs. Job outputs are visible to anyone who can read the run — this repo is public — so ciphertext is also what makes the handoff safe to expose at all. Round-trip of the exact encrypt/decrypt commands was verified with a dummy token.

Before merging: create the secret

One new org-level Actions secret (I cannot create it):

  • Name: RENOVATE_TOKEN_ENC_KEY
  • Value: generate with openssl rand -base64 32
  • Scope: the org repos that run these Renovate workflows (this repo plus every caller of the reusable workflow)

Until it exists, the mint-token job fails fast at the Encrypt token step (${ENC_KEY:?}), without having handed anything to Renovate.

Caller-side changes required

housekeeping-dependencies.yml is a reusable workflow (on: workflow_call), and its secrets: block deliberately uses explicit passthrough rather than secrets: inherit (see the existing CF_ACCESS_STAGE_CLIENT_SECRET note). RENOVATE_TOKEN_ENC_KEY is declared required: true the same way, so every caller must add one line next to its existing CF_ACCESS_STAGE_CLIENT_SECRET passthrough:

    secrets:
      CF_ACCESS_STAGE_CLIENT_SECRET: ${{ secrets.CF_ACCESS_STAGE_CLIENT_SECRET }}
      RENOVATE_TOKEN_ENC_KEY: ${{ secrets.RENOVATE_TOKEN_ENC_KEY }}

A caller that omits it fails at dispatch (consistent with the existing design). Callers that use secrets: inherit (if any) need no change beyond the org secret being scoped to their repo. This PR touches no other repos; caller updates should land after the org secret exists and this merges.

Comment thread .github/workflows/housekeeping-dependencies.yml Outdated
Comment thread .github/workflows/lint.yml Outdated
Comment thread .github/workflows/housekeeping-dependencies.yml
@claude
claude Bot marked this pull request as ready for review August 10, 2026 12:16
@claude
claude Bot requested a review from TimDiekmann August 10, 2026 12:16
@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes CI privilege boundaries and introduces a new org secret required for all reusable-workflow callers; misconfiguration blocks Renovate until secrets are wired, but the design reduces Vault exposure during dependency execution.

Overview
Splits the centralized Renovate workflow into two jobs so Vault OIDC (id-token: write) never runs alongside install-renovate / npm dependency code.

The new mint-token job only runs github-app-token plus AES-256-CBC encryption of the installation token and exports ciphertext as a job output. renovate depends on it, decrypts and masks the token as its first step, then runs the existing cache + Renovate steps with actions: read / contents: read only (no id-token). Workflow-level permissions are cleared to {}; callers must pass the new required secret RENOVATE_TOKEN_ENC_KEY alongside the existing Cloudflare secret.

lint.yml gets an explicit contents: read grant so its Renovate-related install runs with a read-only GITHUB_TOKEN.

Reviewed by Cursor Bugbot for commit cd6717d. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e100524. Configure here.

Comment thread .github/workflows/housekeeping-dependencies.yml
@TimDiekmann
TimDiekmann added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit b7a5d7f Aug 10, 2026
9 checks passed
@TimDiekmann
TimDiekmann deleted the sre-904/renovate-job-split branch August 10, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants