Per-Run Pipeline Credentials
Overview
Each pipeline run checks out a Britive with its CI platform’s OIDC token. The creates a service account for that run in the target namespace, binds it to a fixed role, and returns a token that lives as long as the session. At the broker deletes the service account, which invalidates the token. No OpenShift token is stored in the CI system, and no pipeline holds standing cluster access between runs.
What this pattern gives you:
- One identity per repository and environment, proven by the CI platform’s OIDC token, not by a stored secret
- A credential per run: a new service account, bound to one role in one namespace, deleted at check-in
- Environment isolation enforced by Britive policy: the dev pipeline cannot check out a prod namespace
- An inventory of the standing access that remains in each namespace, from Resource Manager scans
How It Works
sequenceDiagram
participant GH as Pipeline job (self-hosted runner)
participant BR as Britive
participant BK as Access Broker
participant OC as OpenShift API (private)
GH->>BR: pybritive checkout with the job's OIDC token
BR->>BR: Match token sub to a service identity, apply its profile policy
BR->>BK: Checkout request (namespace, cluster, transaction ID, duration)
BK->>OC: Create ServiceAccount gha-<txn> + RoleBinding, request token
OC-->>BK: Bound token (session lifetime)
BK-->>BR: server, token, namespace, CA, expiry
BR-->>GH: Checkout response
GH->>OC: oc login --token, run the job
GH->>BR: pybritive checkin (always runs)
BR->>BK: Check-in request
BK->>OC: Delete ServiceAccount and RoleBinding (token invalid)
The building blocks:
| Component | Role |
|---|---|
| OIDC identity provider and service identities | One per repository and environment, matched on the token’s sub claim |
Resource type aro-namespace | A namespace as a Resource Manager resource: fields cluster_name, api_url, namespace; checkout and check-in scripts; a scan script |
| Resources and labels | One resource per namespace, labeled owner, env, cluster and britive-managed |
| Profile and policies | One deployer profile for all pipelines; one policy per service identity, scoped by labels to its own namespaces |
| Access Broker | Runs in the cluster or next to it, in a ; holds the only standing credential, a kubeconfig whose role can create service accounts and bind exactly one ClusterRole |
| Pipeline | Checks out at the start, checks in at the end (also on failure or cancellation) |
What It Removes and What Remains
| Removed | Remains |
|---|---|
| OpenShift tokens stored as CI secrets | The broker’s kubeconfig, scoped by RBAC: it can create service accounts and RoleBindings in opted-in namespaces and bind only the pipeline ClusterRole (resourceNames) |
| Shared service accounts reused across runs | The namespace’s built-in service accounts and bindings, which the standing-access scan reports |
| Broad, long-lived pipeline permissions | — |
Observed Behavior
Measured on Azure Red Hat OpenShift 4.21 with Access Broker 3.1:
| Behavior | Result |
|---|---|
| Checkout time | About 5 seconds from pybritive checkout to a usable token |
| Token after check-in | Rejected within 10 seconds. The service account is deleted at check-in; the API server caches successful token authentications for about 10 seconds |
| Cancelled job | Check-in still runs (if: always()); nothing is left behind |
| Cross-environment request | Denied: the dev identity cannot see the prod resource |
Design Choices
- Identity per repository and environment. CI deployment environments (for example GitHub environments) appear in the OIDC token; job-level variables do not. Map one service identity to each repository and environment pair.
- Inputs only from Britive. The checkout script receives the namespace, cluster, transaction ID and duration from Britive, never from the pipeline, so a pipeline cannot ask for a namespace its policy does not cover.
- One role for pipelines. The broker can bind a single ClusterRole. Changing what pipelines may do means changing that ClusterRole, the broker’s
bindrule and the permission variable together. - Private APIs. Runners and the broker reach the API over private networking; Britive reaches the broker through its outbound connection.
Next Steps
Last updated on