cesanta / docker_auth

Authentication server for Docker Registry 2
Apache License 2.0
1.27k stars 304 forks source link

Token issued with empty actions when "*" requested and "pull" allowed #248

Open rzerda opened 5 years ago

rzerda commented 5 years ago

Hello,

I'm trying to run this webUI for Docker Registry with docker_auth in anonymous read mode.

My acl contains this:

- actions: ['*']
  match: {account: '', name: catalog, type: registry}
- actions: ['pull']
  match: {ip: 172.16.0.0/12}

registry, docker_auth and webUI containers are in the same 172.16/12 network.

WebUI asks for token "registry:catalog:*" and receives it ok, but when it asks for "repository:testrepo/testrepo2:*", it receives a token with empty actions and then receives HTTP 401 for registry request GET /v2/testrepo/testrepo2/tags/list. When I change allowed actions to "*" in the second element of acl, eveything works.

Issue may be fixed on both ends, but I'm not sure witch way is better:

rojer commented 5 years ago

can you post both requests, as logged by docker_auth, in here for reference? i'm afraid i still don't quite understand what the two requests look like.

rzerda commented 5 years ago

Sure, here it is:


I0304 04:22:26.697024       1 server.go:217] Authn static  -> true, map[], <nil>
I0304 04:22:26.698026       1 acl.go:116] { * registry catalog} matched {"Match":{"account":"","type":"registry","name":"catalog"},"Actions":["*"],"Comment":"access to image catalog (for web UI)"} (Comment: %!s(*string=0xc42011adc0))
I0304 04:22:26.698632       1 server.go:239] Authz static ACL { * registry catalog} -> [*], %!s(<nil>)
I0304 04:22:26.724245       1 server.go:329] New token for {:@172.17.0.4 [{registry catalog [*]}]} map[]: {"iss":"Test auth","sub":"","aud":"Docker Registry","exp":1551674246,"nbf":1551673336,"iat":1551673346,"jti":"8848343205205713016","access":[{"type":"registry","name":"catalog","actions":["*"]}]}
I0304 04:22:26.761559       1 server.go:371] Auth request: {:@172.17.0.4 [{repository testrepo/testrepo [*]}]}
I0304 04:22:26.762597       1 server.go:217] Authn static  -> true, map[], <nil>
I0304 04:22:26.763542       1 acl.go:116] { * repository testrepo/testrepo} matched {"Match":{"ip":"172.16.0.0/12"},"Actions":["pull"],"Comment":"Allow docker internal network (for web UI)"} (Comment: %!s(*string=0xc42011af10))
I0304 04:22:26.764306       1 server.go:239] Authz static ACL { * repository testrepo/testrepo} -> [], %!s(<nil>)
I0304 04:22:26.776109       1 server.go:329] New token for {:@172.17.0.4 [{repository testrepo/testrepo [*]}]} map[]: {"iss":"Test auth","sub":"","aud":"Docker Registry","exp":1551674246,"nbf":1551673336,"iat":1551673346,"jti":"4247362744326423396","access":[{"type":"repository","name":"testrepo/testrepo","actions":[]}]}```
paspo commented 5 years ago

I have the same problem. I'll try to explain:

what I want to achieve

I want a registry which is read-only (no push) for the public (say any unauthenticated user) and read-write for any authenticated user.

the base problem

With the aforementioned configuration, when you curl your registry anonymously like so:

curl -i https://my.docker.registry.domain.com/v2/_catalog

you obtain a 401 result code with an extra header

HTTP/2 401 
server: nginx
date: Tue, 30 Apr 2019 16:58:16 GMT
content-type: application/json; charset=utf-8
content-length: 145
docker-distribution-api-version: registry/2.0
www-authenticate: Bearer realm="https://my.docker.registry.domain.com/auth",service="The Docker Registry",scope="registry:catalog:*"
x-content-type-options: nosniff
strict-transport-security: max-age=31536000; preload

{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}

that you should follow to obtain a token. I completely understand that, from the user perspective, you are unauthenticated and so you should not do this fake-authentication in order to get to the content; but from the registry-container's perspective, every request should have a token, because ACLs management is delegated to the auth-container.

When you use a client like this, everything works ok, probably because this client is handling the authentication header.

possible solutions

I'm not sure that we can solve this in both ends. We should have a registry configuration that allows unauthenticated readonly access, without requesting the auth token. And this is, IMHO, the preferred solution. But I don't think that we can solve this issue from the auth side: if it's "unauthenticated access" an authenticator is useless...

A possible solution is from the client side: if the client receives the www-authenticate header, it should honor it.

I'm exploring a new solution: I have a proxy in front of these containers, so I'm trying to inject the token header if it's not present. I'll report on this when I'm done.

a note about my setup

In my case, I have 3 docker containers:

paspo commented 5 years ago

The header-injection test wasn't a good idea: for every (anonymous) request, this was passed to a "middle" container that:

That was expensive.

So I simply found another registry-webUI that does the job.

More details here