Redirecting to docker registry with nginx
Asked Answered
S

2

6

All I would like to do is control the top endpoint (MY_ENDPOINT where users will login and pull images. The registry and containers are being hosted (DOCKER_SAAS), so all I need is a seemingly simple redirect. Concretely, where you would normally do:

docker login -u ... -p ... DOCKER_SAAS
docker pull DOCKER_SAAS/.../...

I would like to allow:

docker login -u ... -p ... MY_ENDPOINT
docker pull MY_ENDPOINT/.../...

And even more optimally I would prefer:

docker login MY_ENDPOINT
docker pull MY_ENDPOINT/.../...

where the difference in the last item is that the endpoint contains a hashed version of the username and password, which is set into an Authorization header (using Basic) - so the user doesn't even need to worry about username and password, just their URL. I've tried a proxy_pass as we are already doing for basic packaging (using HTTPS), but that fails with a 404 (in part because we do not handle /v2 - do I need to redirect that through, also?). This led me to https://docs.docker.com/registry/recipes/nginx/, but this seems to only be pertinent if you are hosting the registry. Is what I am trying to do even possible?

Scintillometer answered 30/3, 2021 at 4:20 Comment(2)
doesn't the password get save? Are you able to achieve what you want without the nginx proxy? You want to disable password? You trying to reverse proxy to docker registry? when u proxy pass to docker what happen? Why you don't handle /v2?Hypotrachelium
Hi Justin - I did a couple of setups like this but if you don't mind I need some more details about the DOCKER_SAAS. If you don't mind drop a message on twitter @linux_lenny or discord. Happy to help. Have a lot to share about a proxied registry.Jackfruit
D
1

This simple config works both with GitHub and Amazon ECR:

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_set_header Authorization "Basic ${NGINX_AUTH_CREDENTIALS}";
        proxy_pass https://registry.example.com;
    }
}

${NGINX_AUTH_CREDENTIALS} is a placeholder for actual hash that Docker uses to authenticate. You can get it from $HOME/.docker/config.json after using docker login once:

{
    "auths": {
        "registry.example.com": {
            "auth": "THIS STRING"
    }
}

Since proxy injects/replaces authentication header, there is no need to use docker login, just pull using the address of the proxy instead of registry address.

Why 404?

I had several 40X errors trying to test the proxy to GitHub with curl:

  • bad credentials - 404, not 401 or 403 as it normally is.
  • GET /v2/_catalog - 404 (not supported on GitHub yet, in backlog). Use GET /v2/repo_name/image_name/tags/list instead.
  • curl without -XGET - 405, it gives response anyway but to get 200 you need to explicitly use GET (-XGET)

Despite all that docker pull worked flawlessly from the beginning, so I recommend using it for testing.

How to handle /v2/

location / matches everything, including /v2/, so there is no particular need for that in proxy.

Displant answered 2/4, 2021 at 8:57 Comment(3)
This is what I already tried - and I get a 404Scintillometer
@JustinPihony what's the SAAS provider then? I'll see if I can make it working with it. Or if it's not possible for me to try it, I can share how I came up to this config and debugged problems.Displant
@JustinPihony, also how do you check if it's working? With docker pull ... I hope?Displant
K
1

It sounds like there is also an Nginx or similar reverse-proxy-server in front of the DOCKER_SAAS. Does the infrastructure look like this?

[MY_ENDPOINT: nginx]  <--> ([DOCKER_SAAS ENDPOINT: ?] <--> [DOCKER_REGISTRY])

My guess is that since the server [DOCKER_SAAS ENDPOINT: ?] is apparently configured with a fixed domain name, it expects exactly that domain name in the request header (e.g. Host: DOCKER_SAAS.TLD). So the problem is probably that when proxying from [MY_ENDPOINT: nginx] to [DOCKER_SAAS ENDPOINT: ?] the wrong Host header is sent along, i.e. by default the host header MY_ENDPOINT.TLD is sent along, but it should be DOCKER_SAAS.TLD instead. E.g.:

upstream docker-registry {
  server DOCKER_SAAS.TLD:8443;
}

server {
  ...
  server_name MY_ENDPOINT.TLD;

  location / {
    proxy_pass https://docker-registry/;
    proxy_set_header Host DOCKER_SAAS.TLD; # set the header explicitly
    ...
  }
}

or

server {
  ...
  server_name MY_ENDPOINT.TLD;

  location / {
    proxy_pass https://DOCKER_SAAS.TLD:8443/;
    proxy_set_header Host DOCKER_SAAS.TLD; # set the header explicitly
    ...
  }
}

Regarding this:

And even more optimally I would prefer: docker login MY_ENDPOINT

This could be set on the proxy server ([MY_ENDPOINT: nginx]), yes. (The Authorization: "Basic ..." can be dynamically filled with the respective token extracted from the MY_ENDPOINT, and so on). However, the docker CLI would still ask for a username and password anyway. Yes, the user can enter dummy values (to make the CLI happy), or this would also work though:

docker login -u lalala -p 123 MY_ENDPOINT

But this would be inconsistent, and would rather confuse the users, imho. So better let it be...

Kabob answered 6/4, 2021 at 10:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.