Onboarding a GitHub repo to buildkit-operator
Point a repo's image build at the hot daemons in ~25 lines of workflow. Credentials are set once at the org level, so onboarding a new repo is just dropping in the workflow below.
1. Org-level credentials (once per org)
Set the three mTLS secrets + two vars on the SocialGouv org. The /route credential is not a
shared secret: the Action mints a GitHub OIDC id_token natively (the workflow grants
permissions: id-token: write), buildd verifies it and derives repo/untrusted from the verified
claim — so there is no BUILDKIT_OPERATOR_TOKEN to distribute. --visibility selected --repos
<r1,r2,…> opts repos in one at a time (tighter); use --visibility all to let every org repo build.
Needs the
admin:orgscope:gh auth refresh -h github.com -s admin:orgfirst.
ORG=SocialGouv; REPOS=buildkit-operator-example # comma-separated as you onboard more
C=deploy/cert/.certs/client # the mTLS client material
gh secret set BUILDKIT_OPERATOR_CA --org $ORG --visibility selected --repos $REPOS < $C/ca.pem
gh secret set BUILDKIT_OPERATOR_CERT --org $ORG --visibility selected --repos $REPOS < $C/cert.pem
gh secret set BUILDKIT_OPERATOR_KEY --org $ORG --visibility selected --repos $REPOS < $C/key.pem
gh variable set BUILDKIT_OPERATOR_BUILDD_URL --org $ORG --visibility selected --repos $REPOS --body "http://135.125.57.125:8080"
gh variable set BUILDKIT_OPERATOR_GATEWAY_IP --org $ORG --visibility selected --repos $REPOS --body "57.128.55.172"
A buildd with no
oidc.providerscan still take a shared bearer (BUILDKIT_OPERATOR_TOKEN) or the break-glass admin token, passed via the Action'stoken/admin-tokeninput. Prefer OIDC in every case: a shared bearer proves who is calling but not which project they may build, so any holder can build as — and poison the cache of — any repo. The reference deployment accepts OIDC only.
To onboard another repo later, just add it to --repos on each (re-running gh secret set is fine), or
flip to --visibility all.
2. The workflow (per repo)
Drop this in as .github/workflows/build.yml and change only IMAGE. It references the org
secrets/vars, so there is nothing repo-specific to configure. Signing runs in this repo's workflow,
so the cosign signature attests this repo's identity (per-repo provenance).
name: build
on:
push:
workflow_dispatch:
permissions:
contents: read
packages: write # push to GHCR
id-token: write # mints the OIDC id_token: cosign keyless AND the /route credential
env:
IMAGE: ghcr.io/socialgouv/<repo>
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# buildx forwards this registry auth to the remote daemon, which does the --push.
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: socialgouv/buildkit-operator@v1
with:
buildd-url: ${{ vars.BUILDKIT_OPERATOR_BUILDD_URL }}
gateway-ip: ${{ vars.BUILDKIT_OPERATOR_GATEWAY_IP }} # until wildcard DNS for the gateway
ca: ${{ secrets.BUILDKIT_OPERATOR_CA }}
cert: ${{ secrets.BUILDKIT_OPERATOR_CERT }}
key: ${{ secrets.BUILDKIT_OPERATOR_KEY }}
# /route auth is the auto-minted OIDC id_token (id-token: write above; default audience
# buildkit-operator, override with oidc-audience). No shared token. For a non-OIDC buildd,
# pass token: ${{ secrets.BUILDKIT_OPERATOR_TOKEN }} or admin-token: instead.
tags: ${{ env.IMAGE }}:${{ github.sha }}
push: true
provenance: mode=max # SLSA provenance + …
sbom: true # … SBOM, generated by the daemon
sign: true # cosign keyless-sign the pushed image
# Optional proof: the signature verifies against THIS workflow's OIDC identity.
- uses: sigstore/cosign-installer@v3
- name: verify
run: |
set -eux
cosign verify "${IMAGE}:${{ github.sha }}" \
--certificate-identity-regexp "(?i)^${{ github.server_url }}/${{ github.repository }}/" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com >/dev/null
echo "✅ cosign signature verified"
Monorepo? Add name: <component> to give each image its own daemon + cache. Fork-PR isolation? Add
untrusted: true (ephemeral daemon, no cache write-back). All inputs: ci-integration.md.
Notes
- mTLS client material — the
ca/cert/keyare the daemon's CA + a client cert fromdeploy/cert/create-certs.sh(theclient/dir). They authenticate the runner to the daemon through the gateway; the daemon's cert covers*.<gateway-host>. - Reusable workflow? A
workflow_callreusable workflow would shrink the caller to ~10 lines, butcosign signfrom a reusable workflow attributes the signature to the reusable workflow's identity, not the consumer repo's — so the per-repo template above is preferred when signature provenance matters. - DNS —
gateway-ipis the escape hatch while the L4 gateway has no wildcard DNS record; drop it once*.<gateway-host>resolves.