Connect a Federated Identity Provider
Connecting a provider is how Container Registry learns which issuer to trust. It is done once per issuer and audience pair, by a system administrator, before any federated robot account can be created against it.
Connecting a provider grants nothing on its own. It says that tokens from this issuer are worth looking at. Which of them become which account is decided by the claim rules on each federated robot account.
Prerequisites
- System administrator access to Container Registry.
- An issuer that signs JSON Web Tokens and publishes its public keys as a JWKS. GitHub Actions, GitLab CI and any Kubernetes API server all qualify out of the box.
- The issuer string and the audience value your workloads will use. Both have to match the tokens exactly, so take them from a real token rather than from documentation.
- For discovery mode, network access from Container Registry to the issuer’s OpenID configuration URL over HTTPS.
Discovery Mode or Manual Mode
The two modes differ in where Container Registry gets the issuer’s keys.
Discovery mode is the default and the one to use when the issuer is reachable from Container Registry. You give it the Discovery URL, usually the issuer with /.well-known/openid-configuration appended. Container Registry reads that document and fills in the issuer, the JWKS URI, the supported algorithms and the supported claims itself. Key rotation at the provider is then picked up on its own.
Manual mode covers the issuer that Container Registry cannot reach: a cluster on a private network, a local k3d or kind cluster, an air-gapped environment. You paste the issuer’s OpenID configuration document, from which the issuer, the supported claims and the signing algorithms are read, and the JWKS. No fetch is attempted. On a Kubernetes cluster both come from the API server:
kubectl get --raw /.well-known/openid-configuration
kubectl get --raw "$(kubectl get --raw /.well-known/openid-configuration | jq -r .jwks_uri)"The trade is maintenance. Nothing refreshes a pasted JWKS, so every key rotation at the issuer is an edit here, and a cluster rebuilt from scratch signs with new keys and needs the new set pasted in.
Fields
| Field | Description |
|---|---|
| Name | A label for this provider, unique across all providers. Lowercase, starting with a letter, up to 64 characters, with letters, numbers and the separators ., _ and -. |
| Description | Free text. Worth using to say which cluster or which organization this is. |
| Discovery URL | The OpenID configuration URL, conventionally the issuer plus /.well-known/openid-configuration. Container Registry reads the endpoints, the signing keys and the supported claims from it. |
| Manual Mode | Skips remote validation and uses the JWKS you provide instead. |
| Issuer | The expected iss claim. Shown read-only: read from the discovery document in discovery mode, and from the pasted OIDC configuration in manual mode. Tokens from a different issuer are rejected. |
| Audience (required) | The value tokens must carry in aud. Tokens addressed elsewhere are rejected. |
| JWKS URI | Where the public signing keys are published. Derived from the discovery document. |
| OIDC Configuration | The issuer’s OpenID configuration document, pasted in. Required in manual mode. |
| JWKS | The key set itself, pasted in. Required in manual mode. |
| Supported Claims | The claims this issuer publishes, from claims_supported. Claim rules are restricted to this list, so an issuer that publishes a short list limits what you can write rules against. An issuer that publishes no list at all, as a Kubernetes API server does, restricts nothing. |
| Add Claims | Optional claim rules on the provider itself. Every token from this provider has to satisfy them on top of the rules on the robot account, and robot accounts show them as Inherited Claims. |
The supported signing algorithms are read from id_token_signing_alg_values_supported and are not shown in the form.
Both the issuer and the audience are required, and both are set once on the provider rather than on each robot account. iss and aud are never claim rules: a claim rule on either is refused with 400 Bad Request. The issuer and audience pair has to be unique across system and project level. A second provider with the same pair is refused with trusted issuer with issuer '<issuer>' and audience '<audience>' already exists. The same issuer with a different audience is accepted, which is how one cluster serves two registries or two environments: a token goes to the provider whose issuer and audience it carries.
The audience has to equal the token’s aud exactly, scheme included: a token requested for https://registry.example.com does not match the audience registry.example.com. When aud is a list, one matching entry is enough. The audience is an agreed identifier and nothing more. It does not have to resolve, and it does not have to be a URL. Using the registry hostname makes it obvious who a token was minted for, which is why the examples do that.
Connect the Provider
- In the left navigation pane, select Administration.
- Click Trusted Issuers, then New Trusted Issuer. The UI calls a connected federated identity provider a trusted issuer.
- Enter a name, and the discovery URL of the issuer. To paste the configuration instead, turn on Manual Mode and fill in OIDC Configuration and JWKS.
- Enter the Audience. The Issuer is filled in for you.
- Click OK.
To change a provider later, select it from the same list. Apart from its claim rules, only the description, and in manual mode the JWKS, can change. The name, the issuer, the audience, the mode and the discovery URL are fixed once the provider is saved, so a different issuer or audience means a new provider. A provider that federated robot accounts still use cannot be deleted; delete those accounts first.
JWKS Caching and Rotation
In discovery mode, Container Registry caches the fetched key set rather than refetching it on every authentication. The cache lasts as long as the JWKS response’s Cache-Control: max-age says, or one hour when the provider sends none, and the endpoint is fetched at most once every five minutes. Editing and saving the provider forces a fresh fetch into the shared cache, though a running core service can keep serving its in-memory copy for up to 15 minutes. That cache is what makes provider-side key rotation something to plan rather than something to do at the same instant everywhere.
- Publish the new key alongside the old one. While both are in the JWKS, tokens signed by either validate.
- Wait for the cache to expire and the new set to be fetched.
- Once the cache has refreshed and every token signed with the old key has expired, remove the old key.
Rotating without that overlap causes authentication failures for tokens signed with the new key until the cache catches up. GitHub and GitLab handle this for you. A self-managed issuer is yours to sequence.
If a fetch fails, Container Registry keeps using the last key set it fetched and logs a warning. That fallback does not expire, so an unreachable endpoint does not stop federated authentication by itself; it only stops new keys from arriving. Authentication fails outright only for a provider whose keys were never fetched.
Which Providers Work
Anything that issues signed JWTs and publishes a JWKS. In practice that covers:
- GitHub Actions
- GitLab CI
- Kubernetes 1.34 and newer, through service account tokens
- FluxCD
A Kubernetes cluster needs work on the node side as well, because the kubelet is what fetches the token and presents it. See Kubernetes Workloads.
API
Everything on this page is also available over the API, under /api/v2.0/trusted-issuers. POST /api/v2.0/trusted-issuers creates a provider. In discovery mode the required fields are name, audience and openid_config_url; in manual mode they are name, audience, issuer and jwks_keys, with offline_validation set to true. POST /api/v2.0/trusted-issuers/openid-config with an openid_config_url, and POST /api/v2.0/trusted-issuers/jwks with a jwks_uri, fetch an issuer’s published metadata before you register it, which is the quickest way to confirm an issuer is reachable at all. Claim rules are added with POST /api/v2.0/trusted-issuers/{id}/claims.
Next
- Create a Federated Robot Account, so tokens from this provider map to permissions.
- Troubleshooting Federated Robot Accounts, when a token is rejected.