For AI agents: a markdown representation of this page is available at https://container-registry.com/docs/2.16/administration-manual/authentication-management/federated-robot-accounts/create-a-federated-robot-account/index.md. The site index is at https://container-registry.com/llms.txt.

Create a Federated Robot Account

A federated robot account looks like any other system robot account. It has a name, an expiration, and permissions on projects. What it does not have is a secret. Instead it carries claim rules, and any token from its identity provider whose claims satisfy those rules authenticates as this account.

Before You Start

  • The federated identity provider is connected.
  • You have a real token from the workload, decoded, in front of you. Claim rules are compared as exact strings, and the fastest way to write one that never matches is to copy a value out of a document rather than out of a token. Anything that decodes a JWT will do, including jwt.io for a token you are willing to paste there, or jq -R 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson' <<<"$TOKEN" locally.

Create the Account

  1. Go to the Administration tab.
  2. Select Robot Accounts, then click New Robot Account.
  3. Give the robot a name and an expiration, and a description if it helps whoever finds it later.
  4. Turn on Use federated robot account.
  5. Under Select Trusted Issuer, choose the provider whose tokens this account accepts.
  6. Look at Inherited Claims. These are the claim rules set on the provider itself, shown read-only. They apply to this account too, so there is no reason to repeat them. The issuer and audience are checked against the provider and are never claim rules.
  7. Under Add Claims, add one row per rule: a claim path, and the value it must have.
  8. Set the projects and permissions the same way as for any system robot account. Permissions to create or update robot accounts are dropped from a federated robot account.
  9. Step through with Next, then click Finish.

No secret is shown at the end, because the account does not authenticate with one. That is the point of the account. The workload authenticates with a token it fetches for itself.

How Claim Rules Are Matched

When a token arrives, Container Registry validates it against the provider, then looks for the federated robot account it belongs to.

  • Every rule on an account has to match. Rules are ANDed. A token carrying extra claims is fine; a token missing one the rules ask for is not.
  • Values are compared as exact strings, after surrounding whitespace is trimmed. There is no wildcard, no prefix match and no regular expression. A rule on sub matches one subject.
  • Nested claims are addressed with dots. A Kubernetes token’s kubernetes.io.namespace is the namespace key inside the kubernetes.io object.
  • A claim holding a list matches if any entry matches.
  • The provider’s own rules apply too. Rules set on the provider, shown as Inherited Claims, have to match before any account is considered.
  • The most specific account wins. If several accounts match, the one with the most rules is chosen, so a narrow account beats a broad one. When two match with the same number of rules, the one created first is used.
  • An account with no rules never matches. Creating one costs nothing and grants nothing.

Within one provider, no two accounts may carry an identical set of rules. Two identical accounts would make the choice between them arbitrary, so the second is refused.

If the provider publishes a claims_supported list, claim paths are restricted to it, compared case-insensitively. A path outside the list is refused with claim_path '<path>' is not in the trusted issuer's claims_supported list, and the provider’s discovery document is where to fix that. iss and aud are refused as claim paths in every case, because they belong to the provider.

Which Claims to Write Rules On

The claims worth using are the ones that name the workload, rather than the ones that describe the run. Pin the repository, the project path or the service account. A rule on a commit SHA or a run ID matches exactly one build and then never matches again.

Kubernetes

ClaimExample
subsystem:serviceaccount:production:image-puller
kubernetes.io.namespaceproduction
kubernetes.io.serviceaccount.nameimage-puller

GitHub Actions

ClaimExample
subrepo:acme/web:ref:refs/heads/main
repositoryacme/web
repository_owneracme
refrefs/heads/main

GitLab CI

ClaimExample
subproject_path:acme/web:ref_type:branch:ref:main
project_pathacme/web
ref_pathrefs/heads/main

gitlab.com publishes a claims_supported list without namespace_path, so a rule on it is refused even though the token carries it.

A rule on repository alone gives every branch and every workflow in that repository the account’s permissions. Adding ref narrows it to one branch. How far to go is a question about what the account may do: an account with pull permission on one project is worth less to an attacker than one that can push.

Worked Example

A production cluster pulls images with the image-puller service account in the production namespace. The Kubernetes provider is already connected, with the cluster’s issuer and the registry hostname as the audience.

Create a robot account, turn on Use federated robot account, select that provider, and add one rule:

sub = system:serviceaccount:production:image-puller

Give it pull permission on the projects that cluster deploys from, and save. Every pod running under that service account can now pull, with no imagePullSecret anywhere in the manifests. A pod in a different namespace, or under a different service account, gets a token whose sub does not match, no account is found, and the pull is refused.

Changing or Removing an Account

Editing the rules takes effect on the next token presented. There is no secret to revoke and nothing cached on the workload side, so tightening a rule locks out the workloads that no longer match as soon as their current token expires, and deleting the account does the same. This is the cheapest part of the feature: access ends when the account changes, not when every holder of a secret has been found.

Next