github.com/moby/docker@v26.1.3+incompatible/daemon/containerd/resolver.go (about) 1 package containerd 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "net/http" 8 9 cerrdefs "github.com/containerd/containerd/errdefs" 10 "github.com/containerd/containerd/remotes" 11 "github.com/containerd/containerd/remotes/docker" 12 "github.com/containerd/containerd/version" 13 "github.com/containerd/log" 14 "github.com/distribution/reference" 15 registrytypes "github.com/docker/docker/api/types/registry" 16 "github.com/docker/docker/dockerversion" 17 "github.com/docker/docker/pkg/useragent" 18 "github.com/docker/docker/registry" 19 ) 20 21 func (i *ImageService) newResolverFromAuthConfig(ctx context.Context, authConfig *registrytypes.AuthConfig, ref reference.Named) (remotes.Resolver, docker.StatusTracker) { 22 tracker := docker.NewInMemoryTracker() 23 24 hosts := hostsWrapper(i.registryHosts, authConfig, ref, i.registryService) 25 headers := http.Header{} 26 headers.Set("User-Agent", dockerversion.DockerUserAgent(ctx, useragent.VersionInfo{Name: "containerd-client", Version: version.Version}, useragent.VersionInfo{Name: "storage-driver", Version: i.snapshotter})) 27 28 return docker.NewResolver(docker.ResolverOptions{ 29 Hosts: hosts, 30 Tracker: tracker, 31 Headers: headers, 32 }), tracker 33 } 34 35 func hostsWrapper(hostsFn docker.RegistryHosts, optAuthConfig *registrytypes.AuthConfig, ref reference.Named, regService registryResolver) docker.RegistryHosts { 36 var authorizer docker.Authorizer 37 if optAuthConfig != nil { 38 authorizer = authorizerFromAuthConfig(*optAuthConfig, ref) 39 } 40 41 return func(n string) ([]docker.RegistryHost, error) { 42 hosts, err := hostsFn(n) 43 if err != nil { 44 return nil, err 45 } 46 47 for i := range hosts { 48 if hosts[i].Authorizer == nil { 49 hosts[i].Authorizer = authorizer 50 isInsecure := regService.IsInsecureRegistry(hosts[i].Host) 51 if hosts[i].Client.Transport != nil && isInsecure { 52 hosts[i].Client.Transport = httpFallback{super: hosts[i].Client.Transport} 53 } 54 } 55 } 56 return hosts, nil 57 } 58 } 59 60 func authorizerFromAuthConfig(authConfig registrytypes.AuthConfig, ref reference.Named) docker.Authorizer { 61 cfgHost := registry.ConvertToHostname(authConfig.ServerAddress) 62 if cfgHost == "" { 63 cfgHost = reference.Domain(ref) 64 } 65 if cfgHost == registry.IndexHostname || cfgHost == registry.IndexName { 66 cfgHost = registry.DefaultRegistryHost 67 } 68 69 if authConfig.RegistryToken != "" { 70 return &bearerAuthorizer{ 71 host: cfgHost, 72 bearer: authConfig.RegistryToken, 73 } 74 } 75 76 return docker.NewDockerAuthorizer(docker.WithAuthCreds(func(host string) (string, string, error) { 77 if cfgHost != host { 78 log.G(context.TODO()).WithFields(log.Fields{ 79 "host": host, 80 "cfgHost": cfgHost, 81 }).Warn("Host doesn't match") 82 return "", "", nil 83 } 84 if authConfig.IdentityToken != "" { 85 return "", authConfig.IdentityToken, nil 86 } 87 return authConfig.Username, authConfig.Password, nil 88 })) 89 } 90 91 type bearerAuthorizer struct { 92 host string 93 bearer string 94 } 95 96 func (a *bearerAuthorizer) Authorize(ctx context.Context, req *http.Request) error { 97 if req.Host != a.host { 98 log.G(ctx).WithFields(log.Fields{ 99 "host": req.Host, 100 "cfgHost": a.host, 101 }).Warn("Host doesn't match for bearer token") 102 return nil 103 } 104 105 req.Header.Set("Authorization", "Bearer "+a.bearer) 106 107 return nil 108 } 109 110 func (a *bearerAuthorizer) AddResponses(context.Context, []*http.Response) error { 111 // Return not implemented to prevent retry of the request when bearer did not succeed 112 return cerrdefs.ErrNotImplemented 113 } 114 115 type httpFallback struct { 116 super http.RoundTripper 117 } 118 119 func (f httpFallback) RoundTrip(r *http.Request) (*http.Response, error) { 120 resp, err := f.super.RoundTrip(r) 121 var tlsErr tls.RecordHeaderError 122 if errors.As(err, &tlsErr) && string(tlsErr.RecordHeader[:]) == "HTTP/" { 123 // server gave HTTP response to HTTPS client 124 plainHttpUrl := *r.URL 125 plainHttpUrl.Scheme = "http" 126 127 plainHttpRequest := *r 128 plainHttpRequest.URL = &plainHttpUrl 129 130 return http.DefaultTransport.RoundTrip(&plainHttpRequest) 131 } 132 133 return resp, err 134 }