Skip to content

Add Container Virtual Registry routes and stub controller

Context

This is a series of MRs to implement Container image virtual registry: push/pull end... (#549131)

The POC that integrates everything, and from which these MRs are being extracted from, is in !209585 (closed)

What does this MR do and why?

This MR introduces the routes and the VirtualRegistries::ContainerController class that handles the download endpoints that respond to docker pull <virtual registry url>. Only routing, authentication and authorization are covered by this MR. The actual implementation of the download will be done in follow-up MRs.

Changes included:

  1. Routes (config/routes/virtual_registry.rb):

    • Manifest endpoint: GET /v2/virtual_registries/container/:id/*image/manifests/*tag_or_digest
    • Blob endpoint: GET /v2/virtual_registries/container/:id/*image/blobs/:sha
    • Proper constraints for image names, tags, and SHA digests
    • Route helpers for path generation
  2. Stub Controller (ee/app/controllers/virtual_registries/container_controller.rb):

    • JWT authentication (copied from dependency proxy pattern)
    • Feature flag validation (container_virtual_registries)
    • License validation (container_virtual_registry)
    • Permission validation (read_virtual_registry)
    • Registry existence validation
    • Returns 501 Not Implemented for both endpoints

🗒️ Implementation Notes

For the most part, Container Virtual Registry code has been closely mirroring Maven Virtual Registry code. Here, we diverge, due to this constraint discussed in the issue:

Fixed url structures. Docker clients will not use a prefix and compute accessed urls from there. Instead, it will take the host, append v2 and then append whatever we have on the docker command. Thus, we can't really target the GitLab API endpoints (/api/v4) because docker clients, will use a v2 prefix: /v2/api/v4. This doesn't look great. Instead, we're going to use the same approach as the dependency proxy: use rails controllers mounted on the correct urls.

Like dependency proxy, we'll use a Rails controller instead of an API endpoint implemented with Grape. This is the dependency proxy flow:

JwtController -> DependencyProxyAuthenticationService -> DependencyProxyForContainersController#manifest

We'll reuse the first two parts, and implement a new controller, VirtualRegistries::ContainerController:

JwtController -> DependencyProxyAuthenticationService -> VirtualRegistries::ContainerController#manifest

How to validate locally

This MR puts the routes in place, but does not yet implement the actual image download behavior. For now, we can verify that docker login works, and docker pull gets an HTTP 501 Not Implemented response.

Setup

  • Prepare a user and a ::VirtualRegistries::Container::Registry
  • Prepare a personal access token for the user, with read_virtual_registry permission
  • Enable the feature flag container_virtual_registries
  • Enable dependency proxy
current_user = User.first # root or any user with read_virtual_registry permissions
registry = ::VirtualRegistries::Container::Registry.first

docker login

docker login gdk.test:3000/virtual_registries/container/<registry_id>
Username: <type current_user.username>
Password: <paste a personal access token with read_virtual_registry permission>

Login should succeed.

docker pull

docker pull gdk.test:3000/virtual_registries/container/5/hello-world:latest
Error response from daemon: failed to resolve reference "gdk.test:3000/virtual_registries/container/5/hello-world:latest": unexpected status from HEAD request to http://gdk.test:3000/v2/virtual_registries/container/5/hello-world/manifests/latest: 501 Not Implemented

We get the 501 Not Implemented response we have in our new controller.

References

Edited by Radamanthus Batnag

Merge request reports

Loading