k8s.io/kubernetes@v1.29.3/test/e2e_node/plugins/gcp-credential-provider/provider.go (about) 1 /* 2 Copyright 2022 The Kubernetes 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 // Originally copied from pkg/credentialproviders/gcp 18 package main 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "io" 25 "net/http" 26 27 credentialproviderv1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1" 28 ) 29 30 const ( 31 maxReadLength = 10 * 1 << 20 // 10MB 32 ) 33 34 var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io", "*.pkg.dev"} 35 36 // HTTPError wraps a non-StatusOK error code as an error. 37 type HTTPError struct { 38 StatusCode int 39 URL string 40 } 41 42 var _ error = &HTTPError{} 43 44 // Error implements error 45 func (h *HTTPError) Error() string { 46 return fmt.Sprintf("http status code: %d while fetching url %s", 47 h.StatusCode, h.URL) 48 } 49 50 // TokenBlob is used to decode the JSON blob containing an access token 51 // that is returned by GCE metadata. 52 type TokenBlob struct { 53 AccessToken string `json:"access_token"` 54 } 55 56 type provider struct { 57 client *http.Client 58 tokenEndpoint string 59 } 60 61 func (p *provider) Provide(image string) (map[string]credentialproviderv1.AuthConfig, error) { 62 cfg := map[string]credentialproviderv1.AuthConfig{} 63 64 tokenJSONBlob, err := readURL(p.tokenEndpoint, p.client) 65 if err != nil { 66 return cfg, err 67 } 68 69 var parsedBlob TokenBlob 70 if err := json.Unmarshal(tokenJSONBlob, &parsedBlob); err != nil { 71 return cfg, err 72 } 73 74 authConfig := credentialproviderv1.AuthConfig{ 75 Username: "_token", 76 Password: parsedBlob.AccessToken, 77 } 78 79 // Add our entry for each of the supported container registry URLs 80 for _, k := range containerRegistryUrls { 81 cfg[k] = authConfig 82 } 83 return cfg, nil 84 } 85 86 func readURL(url string, client *http.Client) (body []byte, err error) { 87 req, err := http.NewRequest("GET", url, nil) 88 if err != nil { 89 return nil, err 90 } 91 92 req.Header = http.Header{ 93 "Metadata-Flavor": []string{"Google"}, 94 } 95 96 resp, err := client.Do(req) 97 if err != nil { 98 return nil, err 99 } 100 defer resp.Body.Close() 101 102 if resp.StatusCode != http.StatusOK { 103 return nil, &HTTPError{ 104 StatusCode: resp.StatusCode, 105 URL: url, 106 } 107 } 108 109 limitedReader := &io.LimitedReader{R: resp.Body, N: maxReadLength} 110 contents, err := io.ReadAll(limitedReader) 111 if err != nil { 112 return nil, err 113 } 114 115 if limitedReader.N <= 0 { 116 return nil, errors.New("the read limit is reached") 117 } 118 119 return contents, nil 120 }