Add service_type claim to decouple Container Virtual Registry from Dependency Proxy auth

What does this MR do and why?

Add a service_type claim to JWT tokens minted by ContainerProxyAuthenticationService (formerly DependencyProxyAuthenticationService) to distinguish between Container Virtual Registry and Dependency Proxy requests.

This provides defense-in-depth for cross-service access prevention:

  • Tokens for VR requests get service_type='virtual_registry'
  • Tokens for DP requests get service_type='dependency_proxy'
  • Login tokens (no scope) have no service_type claim

The service_type is determined by inspecting the scope parameter passed to the /jwt/auth endpoint by the Docker client.

Controllers now validate the service_type claim:

  • VirtualRegistries::ContainerController requires 'virtual_registry'
  • Groups::DependencyProxy::ApplicationController accepts nil or 'dependency_proxy' (backward compatible with cached login tokens)

The validation logic is implemented as a hook in JwtAuthenticatable that controllers override.

Why rename to ContainerProxyAuthenticationService?

The service now authenticates both Dependency Proxy and Container Virtual Registry requests, so the name DependencyProxyAuthenticationService no longer accurately describes its scope. The new name reflects that it serves container proxy authentication for both features.

Why not also rename DependencyProxy::AuthTokenService?

We considered renaming DependencyProxy::AuthTokenService to ContainerProxy::AuthTokenService for consistency. However, this would require creating a new ContainerProxy bounded context in config/bounded_contexts.yml. Per the bounded contexts guidelines, new contexts should only be added when introducing a new product category or extracting from an overly large context. Neither applies here.

How to test and validate locally

This is a refactor - no new behavior is introduced. We just need to verify that both Dependency Proxy for Containers and Container Virtual Registry are still working as before.

Prepare a personal access token with a read_virtual_registry + write_virtual_registry scopes

docker login gdk.test:3000
# paste the personal access token when prompted for the password
docker system prune -a -f
docker pull gdk.test:3000/flightjs/dependency_proxy/containers/alpine:latest
docker pull gdk.test:3000/virtual_registries/container/1/library/nginx:latest

References

Issue: #579774 (closed)

Edited by Radamanthus Batnag

Merge request reports

Loading