github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/image/distributionutil/repository.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package distributionutil 16 17 import ( 18 "context" 19 "fmt" 20 "net" 21 "net/http" 22 "net/url" 23 "path/filepath" 24 "strings" 25 "time" 26 27 distribution "github.com/distribution/distribution/v3" 28 dockerRegistryClient "github.com/distribution/distribution/v3/registry/client" 29 "github.com/docker/distribution/reference" 30 dockerAuth "github.com/docker/distribution/registry/client/auth" 31 dockerTransport "github.com/docker/distribution/registry/client/transport" 32 "github.com/docker/docker/api/types" 33 "github.com/docker/docker/dockerversion" 34 dockerRegistry "github.com/docker/docker/registry" 35 "github.com/docker/go-connections/tlsconfig" 36 ) 37 38 func NewRepository(ctx context.Context, authConfig types.AuthConfig, repoName string, config registryConfig, actions ...string) (distribution.Repository, error) { 39 tlsConfig := tlsconfig.ServerDefault() 40 tlsConfig.InsecureSkipVerify = config.Insecure 41 42 rurlStr := strings.TrimSuffix(config.Domain, "/") 43 if !strings.HasPrefix(rurlStr, "https://") && !strings.HasPrefix(rurlStr, "http://") { 44 if !config.NonSSL { 45 rurlStr = "https://" + rurlStr 46 } else { 47 rurlStr = "http://" + rurlStr 48 } 49 } 50 51 rurl, err := url.Parse(rurlStr) 52 if err != nil { 53 return nil, err 54 } 55 56 direct := &net.Dialer{ 57 Timeout: 30 * time.Second, 58 KeepAlive: 30 * time.Second, 59 DualStack: true, 60 } 61 62 // TODO(dmcgowan): Call close idle connections when complete, use keep alive 63 base := &http.Transport{ 64 Proxy: http.ProxyFromEnvironment, 65 DialContext: direct.DialContext, 66 TLSHandshakeTimeout: 10 * time.Second, 67 TLSClientConfig: tlsConfig, 68 // TODO(dmcgowan): Call close idle connections when complete and use keep alive 69 DisableKeepAlives: true, 70 } 71 if err := dockerRegistry.ReadCertsDirectory(base.TLSClientConfig, filepath.Join(dockerRegistry.CertsDir(), rurl.Host)); err != nil { 72 return nil, err 73 } 74 modifiers := dockerRegistry.Headers(dockerversion.DockerUserAgent(ctx), nil) 75 authTransport := dockerTransport.NewTransport(base, modifiers...) 76 77 challengeManager, err := dockerRegistry.PingV2Registry(rurl, authTransport) 78 if err != nil { 79 return nil, err 80 } 81 // typically, this filed would be empty 82 if authConfig.RegistryToken != "" { 83 passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken} 84 modifiers = append(modifiers, dockerAuth.NewAuthorizer(challengeManager, passThruTokenHandler)) 85 } else { 86 scope := dockerAuth.RepositoryScope{ 87 Repository: repoName, 88 Actions: actions, 89 Class: "image", 90 } 91 92 creds := dockerRegistry.NewStaticCredentialStore(&authConfig) 93 tokenHandlerOptions := dockerAuth.TokenHandlerOptions{ 94 Transport: authTransport, 95 Credentials: creds, 96 Scopes: []dockerAuth.Scope{scope}, 97 ClientID: dockerRegistry.AuthClientID, 98 } 99 tokenHandler := dockerAuth.NewTokenHandlerWithOptions(tokenHandlerOptions) 100 basicHandler := dockerAuth.NewBasicHandler(creds) 101 modifiers = append(modifiers, dockerAuth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) 102 } 103 104 tr := dockerTransport.NewTransport(base, modifiers...) 105 repoNameRef, err := reference.WithName(repoName) 106 if err != nil { 107 return nil, err 108 } 109 110 return dockerRegistryClient.NewRepository(repoNameRef, rurl.String(), tr) 111 } 112 113 type existingTokenHandler struct { 114 token string 115 } 116 117 func (th *existingTokenHandler) Scheme() string { 118 return "bearer" 119 } 120 121 func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error { 122 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token)) 123 return nil 124 }