Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate or Interface Docker Registry #2316

Closed
mikehaertl opened this issue Aug 17, 2017 · 30 comments · Fixed by #16510
Closed

Integrate or Interface Docker Registry #2316

mikehaertl opened this issue Aug 17, 2017 · 30 comments · Fixed by #16510
Labels
type/proposal The new feature has not been accepted yet but needs to be discussed first. type/upstream This is an issue in one of Gitea's dependencies and should be reported there
Milestone

Comments

@mikehaertl
Copy link

I know, this may be completely out of scope for this project. But I still try:

It would be cool if gitea could provide support for a docker registry.

Full integration is probably very unlikely to ever being added. But it would already help if we could interface with a standalone registry running in some container. The core features should be:

  • Authentication against shared user base
  • Authorization with shared repository permissions
  • Simple instructions for how to set up the above
@lunny
Copy link
Member

lunny commented Aug 17, 2017

Don't know how to implement a docker registry. It seems some similar with git with lfs.

@lunny lunny added the type/proposal The new feature has not been accepted yet but needs to be discussed first. label Aug 17, 2017
@mikehaertl
Copy link
Author

Well, it's not about implementing the registry itself. That's already done and there's even a docker image for it. Details here: https://docs.docker.com/registry/

But the registry by default doesn't do any authentication/authorization. So the task would be to somehow make it use giteas userbase.

It can't be too difficult, because even the Gitlab guys managed to do this 😛 . There's some documentation here:

https://docs.docker.com/registry/deploying/#more-advanced-authentication

A viable option would probably what they call "delegated authentication".

@lunny
Copy link
Member

lunny commented Aug 17, 2017

OK. I see. Maybe you can change the title, it's some confusing! 😄

@lunny lunny added this to the 1.x.x milestone Aug 17, 2017
@mikehaertl mikehaertl changed the title Docker Registry Integrate or Interface Docker Registry Aug 17, 2017
@mikehaertl
Copy link
Author

This could probably be very helpful: https://github.com/cesanta/docker_auth

@bkcsoft
Copy link
Member

bkcsoft commented Aug 24, 2017

GitLab manages Authentication and Authorization by tightly coupling it to the main GitLab application itself https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/container_registry. Which isn't something that Gitea would wanna do.

However, we do have an API that could be used for checking if a user has access to a certain repo. So writing a standalone daemon (or nginx mod) would be fairly straight forward.

@mikehaertl
Copy link
Author

However, we do have an API that could be used for checking if a user has access to a certain repo. So writing a standalone daemon (or nginx mod) would be fairly straight forward.

Sounds good. I'm just not (yet) an expert on nginx modules, so if anyone can provide a simple example or even better a full tutorial on how to set this up this would be very helpful. Maybe it could even be added to the documentation? Could be a nice use case example for what you can do with the API ...

@techknowlogick
Copy link
Member

@mikehaertl / @bkcsoft I've used the cesanta registry software mentioned above, and it has the ability to call an external binary to see if a specific user has access to push/pull/etc.. a specific image to/from the docker registry. That software would then need a way to authenticate with Gitea which could be added via PR to that software, it already can authn against GitHub, Google, and others.

@mikehaertl
Copy link
Author

Sounds perfect and should not be too hard to implement. We should also open an issue at cesenta then. Maybe leave this open in case we need to add extra permissions to allow/disallow registry access fora
user from gitea?

@bkcsoft / @lunny Is the API documented somewhere? Couldn't find any docs.

@lunny
Copy link
Member

lunny commented Sep 3, 2017

visit https://docs.gitea.io and see the top sub menu API

@mikehaertl
Copy link
Author

mikehaertl commented Sep 4, 2017

Nice, thanks. So the /repos/{username}/{reponame} API request should do what we want, right? Just want to make sure, that we don't miss anything.

{
  "admin": true,
  "pull": true,
  "push": true
}

@bkcsoft
Copy link
Member

bkcsoft commented Sep 4, 2017

@mikehaertl yeah pretty much. Have the binary login as a user, then check if pull: true for authorization 🙂

@mikehaertl
Copy link
Author

Hmm, after having a closer look I'm not quite sure, how this would work. I'm not really good at reading Go code, but from looking at the source of cesenta's Authenticator interface, there's also a password involved:

https://github.com/cesanta/docker_auth/blob/master/auth_server/authn/authn.go

This sounds reasonable as usually you have to enter a password when you want to push/pull to/from a private docker registry. OTOH they also provide authentication via Github. Not sure how this works from a user perspective though.

@techknowlogick Could you maybe help clarify, how authentication works via a third party API? Is there a password involved?

@techknowlogick
Copy link
Member

@mikehaertl For third party authentication, they have various files in that authn directory that connect to various authentication providers. So there are various options, 1. complete #27 to add an Oauth provider to Gitea and then you have the GitHub provider in cesanta that you can re-use (this option requires work for both projects). Option 2. create a new provider in cesanta that uses user/pass that is sent to it, and it queries the Gitea api (via basic auth) to see if the credentials are valid. Note for option 2 you may run into issues if you have third party auth enabled in Gitea (for example LDAP, Oauth w/ GitLab or GitHub, SMTP, etc..)

Then after you've authenticated (via option 1, or 2 above), you can use an external binary that queries the API to see if a user has authorization to access a specific repo.

@mikehaertl
Copy link
Author

@techknowlogick I see, thanks. Personally I'd say that option 1) (OAuth2 based authentication) is the most solid then and we should wait for #27.

I still wonder how all this works from a user perspective. I.e. when using docker to pull an image from your private repo, how does authentication work? If you're on the command line, redirecting to Github's authentication authorization page is not an option. And entering the github password isn't either (as stated here).

So how does the OAuth token from Github reach cesenta in the CLI case?

@techknowlogick
Copy link
Member

@mikehaertl You'll have to first auth via web browser to GitHub, then it'll give you a temp pass to use in command line. In the link to the file you sent (the example configuration for the cesanta docker registry), one line down it'll give you more in depth detail on how the auth works.

@mikehaertl
Copy link
Author

Oh, right, I see now, thanks. It's not as tightly integrated as Gitlab but still acceptable I think.

@lunny
Copy link
Member

lunny commented Jun 8, 2018

Now I think this feature is necessary and not very difficult to implement. We could create a new tab named containers or something like that, which could be configed on repository setting, the registry auth information. And at first, we could support the standard registry https://hub.docker.com/_/registry/ and the Golang SDK https://github.com/docker/distribution/tree/master/registry

@bkcsoft
Copy link
Member

bkcsoft commented Jun 17, 2018

@lunny I really don't think that injecting containers into Gitea makes sense. Setting up registry has to be done separately anyhow. Providing a way to authenticate a user makes sense though...

@lunny
Copy link
Member

lunny commented Jun 19, 2018

@bkcsoft, in my mind, the new tab only a UI to retrieve the docker tags from registry. You could set up a global registry URL or specify one on repository setting. Then the container tags could be retrieved and listed on repository tab.

@DblK
Copy link
Member

DblK commented Jun 19, 2018

For my personal usage I use this as docker registry:
http://port.us.org/

Authentification is done by an ldap server, configured both in gitea and portus

@sphrak
Copy link
Contributor

sphrak commented Jul 23, 2018

I thought I might aswell drop my $0.02 here.
I believe that one might take the external issues/wiki route initially, to allow a user to specify a external registry for convenience reasons on a repository, which simply redirects the user to say portus -- then later, one could integrate authentication and maybe also be able to list images available in the registry related to a particular repository.

Not entirely sure about the latter part if it could even be done. But if I understood @bkcsoft correctly I agree that gitea itself should be a yet another docker registry™, since gitea is not a one stop shop like gitlab has become, I do however believe it should allow for linking to external tools like it already does with external issues, external wikis etc.

@XVilka
Copy link

XVilka commented Sep 26, 2019

@DblK problem with Portus is Ruby. Unlike Go applications, like Gitea itself, updating and deploying it is not that painless. Having a similar application, but with the ease and speed of Go would be a killer feature.

@alexanderadam
Copy link

@DblK problem with Portus is Ruby. Unlike Go applications, like Gitea itself, updating and deploying it is not that painless.

@XVilka actually it is‽ A simple docker pull should do, as most applications are available as Docker image anyway.

But if the language a tool is written in is relevant for you, you could also simply use Harbor

But IMHO the discussion of external tools is offtopic here and doesn't actually help in the actual gitea issue.

@onnenon
Copy link

onnenon commented Oct 30, 2019

I feel that Harbor would be a better fit for a container registry. Written in Go, and can be easily deployed to any Linux environment. It is also maintained by the CNCF as an incubating project. The API interface seems robust enough that you could easily manage/view/link a project in Harbor to a Gitea instance.

@arnemileswinter
Copy link

Adding my 2 cents, I have just stumbled upon this project:
https://github.com/vouch/vouch-proxy
which has added gitea as an oauth2 source 13 days ago

I am thinking it should be possible to put nginx proxying a docker-registry, but using vouch as an authentication provider which in turn delegates to the gitea instance via oauth2 flow

@lafriks
Copy link
Member

lafriks commented Nov 19, 2019

We could probably implement docker oauth tokens so that gitea could be one to issue tokens so that docker image registry rights could be managed from gitea.

@arnemileswinter
Copy link

arnemileswinter commented Nov 27, 2019

So far i like the hint by @bkcsoft the best. Securing a docker registry by proxying authentication was not so difficult from my tinkering - just have to make sure to respond with correct headers that the docker cli can reason with.
Specifically in case of a non-authorized user you would return a 401 status code, in case of a non-authenticated user return a WWW-Authenticate header in conjunction.

Role management should be doable in this scenario, by checking whether the logged in user has either read or write access to the repo. This should play nicely with Organizations as well, I think.

With Gitea being upstream of a docker registry, the source would not be polluted with docker specifc stuff. It would still be nice to have a generic solution that the community can easily leverage.

Regarding OP's request on a sample configuration:

However, we do have an API that could be used for checking if a user has access to a certain repo. So writing a standalone daemon (or nginx mod) would be fairly straight forward.

Sounds good. I'm just not (yet) an expert on nginx modules, so if anyone can provide a simple example or even better a full tutorial on how to set this up this would be very helpful. Maybe it could even be added to the documentation? Could be a nice use case example for what you can do with the API ...

This is something I've jammed together with stackoverflow and docker's own documentation on proxying auth requests to an authority

events {
    worker_connections  1024;
}

http {
  upstream docker-registry {
    server registry:5000;
  }
  upstream auth-service {
    server auth-service:80;
  }

  ## Set a variable to help us decide if we need to add the
  ## 'Docker-Distribution-Api-Version' header.
  ## The registry always sets this header.
  ## In the case of nginx performing auth, the header is unset
  ## since nginx is auth-ing before proxying.
  map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
    '' 'registry/2.0';
  }

  server {
      listen 443 ssl;

      # SSL
      ssl_certificate /certs/domain.crt;
      ssl_certificate_key /certs/domain.key;
      # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
      ssl_protocols TLSv1.1 TLSv1.2;
      ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
      ssl_prefer_server_ciphers on;
      ssl_session_cache shared:SSL:10m;

      # disable any limits to avoid HTTP 413 for large image uploads
      client_max_body_size 0;
      # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
      chunked_transfer_encoding on;

      location = /check-creds {
          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;

          # There is no need to send an entire request-body to the securing authority
          proxy_pass_request_body off;
          proxy_set_header Content-Length "";

          proxy_pass http://auth-service/check-creds;
      }

      # Docker clients use the /v2 API route to communicate with a registry
      location /v2 {
          # This is the important bit here!
          auth_request /check-creds;

          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;

          add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;

          proxy_pass http://docker-registry;
      }
  }
}

@jamesorlakin
Copy link
Contributor

Some update on this - I was playing around with token authentication on the official v2 registry and managed to integrate a small server in Gitea using its authentication and permission functions as a proof of concept using inspiration from this guide.

image

However, I've later found out that tags and images can't be deleted easily so I'm not sure how GitLab and Docker EE have managed that bit. I was hoping for a decoupled system that could automatically produce API calls to the registry to delete an image repository when the Gitea repo was deleted. Alas, finding this quirk out has somewhat reduced my interest in finishing it 😕 .

There have been PRs open on Docker here and there on the issue but no real substantial progress. I agree wholehartedly with this comment - it's weird not to have a delete feature out of the box.

@majewsky
Copy link

I was hoping for a decoupled system that could automatically produce API calls to the registry to delete an image repository when the Gitea repo was deleted.

With the reference implementation of docker-registry, this is pretty much impossible. To "delete a repository", you have to delete all manifests (i.e. all the images) stored in it. But there is no API call for listing those manifests in the docker-registry API (i.e., the OCI Distribution API). So if you want that kind of integration, you're wandering into in-house API territory and end up tightly coupling your registry implementation of choice to Gitea (or whatever helper daemon ends up translating the delete-repo event from Gitea into a series of deletions in the registry).

I experienced this first-hand when implementing my own registry. My registry's gimmick is that it isolates customers into their own storage backends (mostly because it makes billing a lot easier for us). I initially implemented that by spawning one docker-registry (i.e. the reference implementation from the Docker team) per customer. So I only had to provide the auth logic and then reverse-proxy registry API requests into the respective backend registry. This works great for docker pull and docker push, but once you get to stuff like deletion of entire repos or garbage collection, having to go through the rather bare-bones registry API became more and more unbearable, and I ended up throwing away the docker-registry fleet and implementing the API in its entirety myself (which isn't particularly hard if you have a reasonably firm grasp on the concepts involved).

I have a hopeful message for you, though. The registry API spec is very much in flux right now since it was donated from Docker to the OCI team. Now is the right time to make sure your usecases are being considered in the further evolution of the spec, so checkout https://github.com/opencontainers/distribution-spec. opencontainers/distribution-spec#22 in particular might be pertinent to the "delete a repo in the registry when the repo is deleted in Gitea" usecase.

@jamesorlakin
Copy link
Contributor

Thank you @majewsky. I forgot to update this where I opened a formal issue there to try and get the ball rolling on a PR that was worked on for well over a year, but never get merged and then got shut with the distribution-spec move. I believe some of the work there was general API/tags improvements as well - what's officially implemented right now just seems bizarre and not thought out at all!

opencontainers/distribution-spec#114 if anybody's interested. I don't see it moving though. 🙂

@guillep2k guillep2k added the type/upstream This is an issue in one of Gitea's dependencies and should be reported there label Apr 25, 2020
@lunny lunny modified the milestones: 1.x.x, 1.17.0 Mar 30, 2022
@go-gitea go-gitea locked and limited conversation to collaborators Apr 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type/proposal The new feature has not been accepted yet but needs to be discussed first. type/upstream This is an issue in one of Gitea's dependencies and should be reported there
Projects
None yet