github.com/oam-dev/kubevela@v1.9.11/pkg/utils/registries/secret_authenticator.go (about)

     1  /*
     2  Copyright 2023 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package registries
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"fmt"
    23  	"net/http"
    24  	"net/url"
    25  
    26  	"github.com/google/go-containerregistry/pkg/authn"
    27  	"github.com/google/go-containerregistry/pkg/name"
    28  	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
    29  )
    30  
    31  // SecretAuthenticator provides helper functions for secret authenticator operations
    32  type SecretAuthenticator interface {
    33  	Options() []Option
    34  
    35  	Auth(ctx context.Context) (bool, error)
    36  
    37  	Authorization() (*authn.AuthConfig, error)
    38  }
    39  
    40  type secretAuthenticator struct {
    41  	auths    DockerConfig
    42  	insecure bool // force using insecure when talk to the remote registry, even registry address starts with https
    43  }
    44  
    45  // NewSecretAuthenticator creates a secret authenticator
    46  func NewSecretAuthenticator(imageRegistry *ImageRegistry) (SecretAuthenticator, error) {
    47  
    48  	if imageRegistry == nil {
    49  		return &secretAuthenticator{}, nil
    50  	}
    51  
    52  	sa := &secretAuthenticator{
    53  		insecure: false,
    54  	}
    55  
    56  	// force insecure if imageRegistry has Insecure
    57  	sa.insecure = imageRegistry.Insecure
    58  	if imageRegistry.Insecure {
    59  		sa.insecure = true
    60  	}
    61  
    62  	auth := fmt.Sprintf("%s:%s", imageRegistry.Auth.Username, imageRegistry.Auth.Password)
    63  
    64  	entry := DockerConfigEntry{
    65  		Username: imageRegistry.Auth.Username,
    66  		Password: imageRegistry.Auth.Password,
    67  		Email:    imageRegistry.Auth.Email,
    68  		Auth:     base64.StdEncoding.EncodeToString([]byte(auth)),
    69  	}
    70  
    71  	sa.auths = map[string]DockerConfigEntry{}
    72  	if imageRegistry.UseHTTP {
    73  		sa.auths[fmt.Sprintf("http://%s", imageRegistry.Registry)] = entry
    74  	} else {
    75  		sa.auths[fmt.Sprintf("https://%s", imageRegistry.Registry)] = entry
    76  	}
    77  	return sa, nil
    78  }
    79  
    80  func (s *secretAuthenticator) Authorization() (*authn.AuthConfig, error) {
    81  	for _, v := range s.auths {
    82  		return &authn.AuthConfig{
    83  			Username: v.Username,
    84  			Password: v.Password,
    85  			Auth:     v.Auth,
    86  		}, nil
    87  	}
    88  	return &authn.AuthConfig{}, nil
    89  }
    90  
    91  func (s *secretAuthenticator) Auth(ctx context.Context) (bool, error) {
    92  	for k := range s.auths {
    93  		return s.AuthRegistry(ctx, k)
    94  	}
    95  	return false, fmt.Errorf("no registry found in image-registry")
    96  }
    97  
    98  func (s *secretAuthenticator) AuthRegistry(ctx context.Context, reg string) (bool, error) {
    99  	url, err := url.Parse(reg) // in case reg is unformatted like http://docker.index.io
   100  	if err != nil {
   101  		return false, err
   102  	}
   103  
   104  	options := make([]name.Option, 0)
   105  	if url.Scheme == "http" || s.insecure {
   106  		options = append(options, name.Insecure)
   107  	}
   108  
   109  	registry, err := name.NewRegistry(url.Host, options...)
   110  	if err != nil {
   111  		return false, err
   112  	}
   113  
   114  	_, err = transport.NewWithContext(ctx, registry, s, http.DefaultTransport, []string{})
   115  	if err != nil {
   116  		return false, err
   117  	}
   118  
   119  	return true, nil
   120  }
   121  
   122  func (s *secretAuthenticator) Options() []Option {
   123  	options := make([]Option, 0)
   124  
   125  	options = append(options, WithAuth(s))
   126  	if s.insecure {
   127  		options = append(options, Insecure)
   128  	}
   129  
   130  	return options
   131  }