Skip to content

Commit

Permalink
Authenticated registry mirrors: handle prefix correctly
Browse files Browse the repository at this point in the history
Pulling from a prefixed and auuthenticated registry mirror
didn't work in the past.

Let's assume the following configuration is in place:

  * registry.kube.lan is an authenticated registry using
    bearer tokens as authentication method
  * A mirror of quay.io/coreos/etcd is available at
    registry.kube.lan/quay.io/coreos/etcd
  * The docker engine has the following configuration:
    ```json
      "registries": [
         {
           "Prefix" : "quay.io",
           "Mirrors": [
              {
                "URL": "https://registry.kube.lan/quay.io"
              }
           ]
         }
      ]
    ```

With this setup in place doing:

```
docker pull quay.io/coreos/etcd:v3.1
```

Should result in:

  * Have the docker engine authenticate against `registry.kube.lan`
  * Have the authenticated docker engine pull
    `registry.kube.lan/quay.io/coreos/etcd:v3.1` without the user
    being aware of it.

The docker engine checks if a registry is authenticated by doing a
`GET` request against the `/v2/` endpoint. Without this patch the docker
engine made a request against `/prefix/v2/`; in this case it would issue
the `GET` request against `https://registry.kube.lan/quay.io/v2/`.
That results in a `404` error code, which is interpreted by the engine
as "the remote registry is not using authentication, plus it doesn't
support v2".

After the docker engine is aware of the registry being authentcated, it
will contact the authentication endpoint specified by the registry.
While doing that the docker engine will provide the following
information to the authentication service:

  * `scope`: this is the name of the registry. This patch ensures the right
    name of the registry is sent. In this case it would send `registry.kube.lan`
    instead of `registry.kube.lan/quay.io`.
  * `service`: the scope of the operatation. This patch ensures the `scope`
    sent to the authentication service uses the right repository. In this case
    it would send `repository:quay.io/coreos/etcd:pull` instead of
    `repository:coreos/etcd:pull`.

Sending a wrong `service` and `scope` would cause the authentication
service to issue a wrong bearer token (something that doesn't grant any
kind of privileges or grants them against resources different from the
ones available on the registry). Without this patch the registry would
issue a `404` code to the engine, causing it to move to the next mirror.

Signed-off-by: Flavio Castelli <fcastelli@suse.com>
  • Loading branch information
flavio committed Jul 17, 2018
1 parent b3fcbdd commit 9129064
Showing 1 changed file with 14 additions and 3 deletions.
17 changes: 14 additions & 3 deletions components/engine/distribution/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"
"net"
"net/http"
"net/url"
"path"
"strings"
"time"

"github.com/docker/distribution"
Expand Down Expand Up @@ -60,6 +63,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
if endpoint.TrimHostname {
repoName = reference.Path(repoInfo.Name)
}
repoName = strings.TrimPrefix(path.Join(endpoint.URL.RequestURI(), repoName), "/")

direct := &net.Dialer{
Timeout: 30 * time.Second,
Expand All @@ -85,7 +89,15 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), metaHeaders)
authTransport := transport.NewTransport(base, modifiers...)

challengeManager, foundVersion, err := registry.PingV2Registry(endpoint.URL, authTransport)
regURL, err := url.Parse(fmt.Sprintf("%s://%s", endpoint.URL.Scheme, endpoint.URL.Host))
if err != nil {
return nil, foundVersion, fallbackError{
err: err,
confirmedV2: foundVersion,
transportOK: false,
}
}
challengeManager, foundVersion, err := registry.PingV2Registry(regURL, authTransport)
if err != nil {
transportOK := false
if responseErr, ok := err.(registry.PingResponseError); ok {
Expand All @@ -108,7 +120,6 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
Actions: actions,
Class: repoInfo.Class,
}

creds := registry.NewStaticCredentialStore(authConfig)
tokenHandlerOptions := auth.TokenHandlerOptions{
Transport: authTransport,
Expand All @@ -131,7 +142,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
}
}

repo, err = client.NewRepository(ctx, repoNameRef, endpoint.URL.String(), tr)
repo, err = client.NewRepository(ctx, repoNameRef, regURL.String(), tr)
if err != nil {
err = fallbackError{
err: err,
Expand Down

1 comment on commit 9129064

@jamescassell
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this change, will things still work with https://registry.kube.lan/quay.io/v2/?

Please sign in to comment.