Skip to content

Send registry tokens only to the token service's own registry - #576

Merged
andrew merged 2 commits into
git-pkgs:mainfrom
simonchrz:fix/registry-token-scope
Oct 24, 2026
Merged

andrew merged 2 commits into
git-pkgs:mainfrom
simonchrz:fix/registry-token-scope

Conversation

@simonchrz

Copy link
Copy Markdown
Contributor

Tightens which registries get a bearer token fetched with configured credentials, and bounds the token caches.

  • A token fetched from a token service the proxy has credentials for went to the challenging registry if that registry had any configured credentials, or shared the token service's registrable domain. The first rule handed a token minted from one registry's credentials to an unrelated registry the proxy also has a key for; the second treated every tenant on shared domains such as jfrog.io, azurecr.io or pkg.dev as one site. Such a token now only goes to a registry on the token service's own host and port, to one configured with the same credentials as the token URL, or to Docker Hub (registry-1.docker.io/index.docker.io with auth.docker.io) and GitLab.com (registry.gitlab.com with gitlab.com). Anonymous tokens are unaffected. GHCR, Harbor, Artifactory, ACR, Quay and Artifact Registry serve their token endpoint from the registry host, so they keep working; a self-hosted registry with its token service on another host needs the same credentials configured for both URLs, as the docs now show.
  • The token request asked for whatever scope the challenge named. The proxy only pulls, so it now always asks for repository:<repo>:pull for the repository in the request path.
  • Challenges were remembered per /v2/<repo> and never dropped, and tokens were only pruned of expired entries. Challenges are now kept per registry host, both caches have a size limit, and a token is reused for at most an hour.

Tests cover a registry with other credentials, the pull scope, the host matching (including shared-domain tenants), and the cache limits.

After a 401 the transport fetches a token from the challenge's realm,
using credentials configured for that realm, and sends it to the host
that issued the challenge. It trusted that host if it had any configured
credentials, even unrelated ones, or shared the realm's registrable
domain. The second rule makes every tenant on a shared domain such as
jfrog.io, azurecr.io or pkg.dev the same site, and the first hands a
token minted from one registry's credentials to another registry the
proxy happens to have a key for.

A credentialed token now goes only to a registry on the realm's own
host and port, to one configured with the same credentials as the
realm, or to Docker Hub and GitLab.com, whose registries use a token
service on another host. Anonymous tokens are unaffected.

The scope in the token request also came from the challenge, so a
registry could ask for push access or for other repositories. The proxy
only reads, so it now always asks for pull access to the repository in
the request path.
The transport remembered a challenge for every /v2/<repository> it was
ever challenged on and never forgot one, so a long-running proxy, or a
metadata document naming many registries, grew the map without limit.
Tokens were only pruned of expired entries, and the expiry came from
the token service.

Challenges are now kept per registry host, holding only the realm and
service, and the pull scope for a request is built from its path, so
pulling many repositories from one registry keeps one entry. Both
caches have a size limit, evicting an arbitrary challenge or the token
that expires soonest, and a token is reused for at most an hour,
whatever lifetime the token service claims.
@andrew
andrew merged commit 9ef99e2 into git-pkgs:main Oct 24, 2026
6 checks passed
@simonchrz simonchrz added the breaking Changes behaviour users rely on; needs a minor release label Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Changes behaviour users rely on; needs a minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants