-
Notifications
You must be signed in to change notification settings - Fork 879
Authentication on private registry #541
Comments
@matleh there are unfortunate discrepancies between the official, docker operated index (hence API documentation) and what lives in the open-source registry. That being said, I would rather encourage you to mimick the standalone behavior of the registry (in that mode, it doesn't need tokens from the index, and you are supposed to implement your own authentication means, say, using nginx auth). Furthermore, you will likely not be able to use the official docker client against the official index with a custom registry. I guess it depends on what you want to achieve. |
@dmp42 thanks for you answer. I am not sure whether I understand everything. The documentation gives the impression, that Docker is striving for a distributed architecture with a more or less clear divide of responsibilities between index, registry and docker client. The index is responsible for authentication and to know what exists and where it exists. The registries are responsible to store the images and contact the index to see if a request is allowed. The docker client first contacts the index and is then redirected to the right registry for the particular repository... That architecure does make sense to me (even though is has some rough edges) and appears open for everybody to operate either a registry or both an index and registry. But after I digged deeper, I get the impression that this architecture and this openness is not really where the real implementation is heading to (maybe because the Docker Hub is the main business model of Docker Inc.?). That is understandable from a business perspective but regrettable from an Open-Source perspective. But on the other hand, all this code code is there - it is possible to give a index_endpoint to the registry, it is possible to do "docker login some.private.registry", the code is there for this token handling an everything ... Are these just relicts from the past? To me it looks like there are only two "officially" supported scenaries: (I know there is also quay.io, but that is more or less just a variation of (1)) (1) has the disadvantages (2) has the disadvantages I want to be able to use a docker registry to distribute commercial software to customers. That is, I want the registry to be publicly available but have access to the repositories restricted to customers (and be able to create new customers ad hoc). As far as I can see, that kind of setup is currently not supported. I will have a look into what can be done with nginx auth, which you suggested. |
Just gonna leave this one here: https://github.com/docker/docker-registry/blob/master/contrib/nginx.conf If you want to use the registry to distribute software, it is completely possible to roll your own authentication system in front of the registry. It's not built into the open source registry as you have noted, and others have had to write their own authentication server in front of it. However, if you just want end users to have the ability to retrieve images, then you can limit everything but GET requests with auth_basic inside nginx. That way, customers can view and retrieve images via |
I made good progress today writing some authentication system in front of the registry using nginx and ngx_http_auth_request_module. Thanks for your suggestions. The only problem I see with this, is that the authentication server does not know which image-ids belong to which repositories, so it has to allow GETing of all images to everybody who is allowed to GET any repository. For our current setup, that might be tolerable (at least only known customers have access to the images and without having access to the repository one has to guess image-ids), but it would be nice to be able to close this security hole... Maybe I will have a look, if I can hook into the registry to gain access to this information. |
Well, after I spend a considerable amount of time implementing access control with nginx and everything looked very nice, today came the disenchantment. It looks like access control with Basic Auth is broken with current versions of docker (I am on arch-linux which has docker version 1.2). The first request to the registry is made with Authorization:Basic but after that, docker switches to using Authorization:Token (even if no token is provided in the response from the registry) which breaks access control checking based on Basic Auth information. Looks like I can throw away my work of the last days and have to fork the docker-registry to implement the access control right within the registry itself. Any other ideas or did I misunderstand/misuse anything? |
@matleh do you run standalone? I need infos about how you launch your registry and your registry configuration in order to help you. |
I run the "registry" image ( I have nginx as a reverse proxy before that with the following configuration:
There is a custom access-control application running on http://127.0.0.1:8999 which uses the username and password in the Authorization header and the requested URL to check if the request is allowed. As you may see in the nginx configuration, I found a workaround for this problem: my access-control application hijacks the X-Docker-Token header and uses it to identify following requests. Since the registry does not check the X-Docker-Token in standalone mode, this should work (did not have time for extensive testing, yet). But I wouldn't mind if I could do without that. |
This is somewhat annoying; I was planning on implementing auth on my own registry as well. I think the problem here lies with docker; if it doesn't receive an auth token from the registry it should continue to use basic auth instead. I'm still ok with docker-registry not handling auth on its own but it should always be clear how to implement it for those who need it. That depends on reliable behavior from the docker client. |
@jdiaz5513 simple auth on top of the registry should be straightforward: https://github.com/docker/docker-registry/blob/master/contrib/nginx.conf Now, you are right, this is a problem with docker, and we plan on changing that. |
@dmp42 as for my experience of the last days, the ngnx.conf you linked to does not work any more, precisely for the reasons I wrote about above. |
@shin- (or @bacongobbler if you have time) can you look into this and confirm that docker 1.2 works with the latest registry and proposed nginx simple auth config (or if it doesn't, investigate why)? @matleh thanks |
All right, what I wrote only is true when docker-registry is not running over HTTPS. If docker-registry runs over HTTPS, docker just sends Basic Authorization headers with every request. For anyone who reads this - be aware that to use docker-registry over HTTPS, one needs a "real" SSL certificate - self-signed certificates do not work and there is no way to make docker accept them for testing and development purposes, besides installing the test-CA certificate on the system that runs docker. (see moby/moby#2687) |
As advertised in the past, we do not support authentication over HTTP. If docker tries to send credentials over HTTP, then it is a bug and it needs to be fixed, but very clearly we have no intention to support non-HTTPS auth. |
But if you want to have docker registry in High Availability mode you will have following schema: Frontend: HAproxy ... HAproxy Auth : Nginx reverse proxy ... Nginx reverse proxy App: Docker registry ... Docker registry Storage : Distributed storage So for HAproxy we have three strategy : And having SSL decode is not CPU-free, having feature to have docker auth over http will simplify HA setup. It's not really a security issue if network behind HAproxy is a local network. |
@tangicolin I don't think this is a problem in your setup, since it is docker and not the docker-registry who refuses to do basic Auth over http. So the haproxy can be the ssl endpoint. |
Pretty sure i'm running into the same or related issue -
Results in:
and nginx logs show:
so you can see it switches at the last two http requests to giving 401s, possibly related to other reports of it 'switching' to use Token auth or something like that? |
@adamhadani are you running the registry standalone? Can you copy your registry launch command and/or configuration? Thanks |
@adamhadani are you sure that the communication happens over HTTPS? Are you sure, Nginx only listens on port 443? You nginx.conf would be helpful, too. |
Here's the nginx site config (this is a template populated in an Ansible deploy, final values are guaranteed to be valid). This template is virtually identical to the example file (https://github.com/docker/docker-registry/blob/master/contrib/nginx_1-3-9.conf) minus the port 80 redirect. I am not listening at all on port 80 (verified this, nginx default site is deactivated as well) so I don't assume this is the problem i'm seeing.
As for the docker-registry, i'm using the config_example file (https://github.com/docker/docker-registry/blob/master/config/config_sample.yml) and passing in the docker environment vars:
the registry seems to work fine btw when I just hit it directly via port 5000. My problems seem to be around the usage of HTTP Basic Auth via nginx proxy. |
Some more info. doing some packet sniffing, looks like where things go wrong happens after docker-registry returns back this 'token' thing in response header, e.g the response to the 'PUT /v1/repositories/myapp/ HTTP/1.0' part
After this response, the next request coming out of docker client has a much shorter 'Authorization' http header which triggers the 401 assumably. I can't see any other authentication-related http header in there either:
|
With the risk of getting ahead of myself, I looked around the docker_registry code. Inside https://github.com/docker/docker-registry/blob/master/docker_registry/index.py, there's a generate_headers function which seem to generate the WWW-Authenticate: Token ... stuff. |
@adamhadani No, docker will not work, if it does not get a X-Docker-Token header (at least in the version 1.2.0 that I use). I had to include it in the response again after I tried to remove it, because docker started to complain.
|
That is correct. The correct way to use auth over a private registry is to docker login on that private registry, then push the image normally. |
Can I close this or is there anything that's still unclear regarding private registry auth? |
The inconsistent behaviour over HTTP and HTTPS is not really resolved and the lack of documentation is neither. |
When pushing to a private registry over HTTP, do you not get this message? I'll look into adding a note for the HTTPS stuff in our docs.
|
Thanks for replies, going to try these suggestions now and report back with findings |
OK, so got it to work using some combination of the feedback provided here. I'm gonna report my steps and some points of interest in the hope this helps other people who might come across this issue and perhaps provide pointers for how to improve documentation / make behaviour more consistent. Pushing to a private repo which is using HTTPS and Basic Auth
on the nginx proxy logs this command causes the following stream of requests, notice the 401 on the POST:
So a few things worth mentioning that are probably worth documenting (I've gone over a few blog posts and documentation pages and wasn't able to 'deduce' this, so its not clear at all to most people I assume, which is a shame since otherwise setting up a private docker repo is very useful and was pretty straight forward):
|
Basic auth only works for https. Thus to make https works few things that help me:
after this, I can do docker pull and docker push |
After setting up with nginx auth (following https://github.com/docker/docker-registry/blob/master/contrib/nginx/nginx.conf and https://github.com/docker/docker-registry/blob/master/contrib/nginx/docker-registry.conf) to a socket file, the following magic worked (Fedora 20, nginx 1.4.7, docker-registry 0.8.1, docker-io 1.3.0):
It's not ideal because the USER and PASS are exposed in the tags, but it's the only way I've found. I hope it helps research this issue. |
@bacongobbler thoughts? |
I am facing issue with docker client to connect to registry. I have the following:
I am using a CA certificate to enable SSL and that works fine with curl command too... Not sure if this is due to x509 certificate?? |
@paturuv The specific issue you are talking about is likely that you are not fully chaining all the certs. I just went through this issue today when setting up a private registry using a ssl cert that has an intermediate one. I had to add the bundled ssl cert to the cert that was for me so that docker would resolve the full chain. In order to do this you can do this:
And then use the generated cert as the cert that nginx serves up. |
@hibooboo2 could you please elaborate how you fixed the issue? Where is the |
I'm still batling with this one, docker-registry 0.9.1, docker 1.5.0 and Apache HTTPd 2.4 I used easy_install --user "docker-registry==0.9.1" Initial request came with
Successive came with
HTTPd front didn'f find Authorization:Basic and didn't forward the push request. With docker-registry image, started using docker run, I still have Authorization:Basic presented back. What's difference between docker-registry image and docker-registry via pip/easy_install ? Thanks |
@olibob The certs i am talking about are not in the boot2docker vm they are in the nginx setup that does the reverse proxy to provide authentication to the registry. |
I am implementing a private docker-index, taking some guidance from http://docs.docker.com/reference/api/hub_registry_spec/. It seems to me that this documentation is not in line with the current implementation of the docker-registry (not sure about docker itself).
The docs talk about a cookie being used for communication between docker and docker-registry. Since docker-registry 0.7 cookies are no longer used (so says the changelog).
It looks like docker just reuses the token from the docker-index for each call it has to make to the registry during a "pull" or "push". But that means, docker has to use a token with "access=write" to GET different resources before it PUTs the image data. The registry sends a 401 for any GET request which is made using a token with "access=write". The "push" still seems to work, but I am not sure about the consequences of these 401 (and some 409) responses.
Maybe I misunderstand something about the interaction between docker, registry and index?
A possible workaround could be to have the registry accept "access=write" tokens for GET requests (or to generalize: "read" is only valid for GET, "write" is valid for GET, PUT and POST and "delete" is valid for GET, PUT, POST and DELETE).
Still the question remains at what time the index can invalidate a token. The docs say that a token is invalidated when the registry uses it to check the access rights. But since the registry has to use the same token a couple of times it seems like we can currently only assign a static TTL to all tokens and invalidate them after that timespan.
@samalba, I was told that you are the go-to-authority for everything related to the registry: what do you think?
The text was updated successfully, but these errors were encountered: