mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor files
This commit is contained in:
298
vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go
generated
vendored
Normal file
298
vendor/k8s.io/kubernetes/pkg/credentialprovider/gcp/metadata.go
generated
vendored
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package gcp_credentials
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||
)
|
||||
|
||||
const (
|
||||
metadataUrl = "http://metadata.google.internal./computeMetadata/v1/"
|
||||
metadataAttributes = metadataUrl + "instance/attributes/"
|
||||
dockerConfigKey = metadataAttributes + "google-dockercfg"
|
||||
dockerConfigUrlKey = metadataAttributes + "google-dockercfg-url"
|
||||
serviceAccounts = metadataUrl + "instance/service-accounts/"
|
||||
metadataScopes = metadataUrl + "instance/service-accounts/default/scopes"
|
||||
metadataToken = metadataUrl + "instance/service-accounts/default/token"
|
||||
metadataEmail = metadataUrl + "instance/service-accounts/default/email"
|
||||
storageScopePrefix = "https://www.googleapis.com/auth/devstorage"
|
||||
cloudPlatformScopePrefix = "https://www.googleapis.com/auth/cloud-platform"
|
||||
googleProductName = "Google"
|
||||
defaultServiceAccount = "default/"
|
||||
)
|
||||
|
||||
// Product file path that contains the cloud service name.
|
||||
// This is a variable instead of a const to enable testing.
|
||||
var gceProductNameFile = "/sys/class/dmi/id/product_name"
|
||||
|
||||
// For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match
|
||||
// "foo.gcr.io" and "bar.gcr.io".
|
||||
var containerRegistryUrls = []string{"container.cloud.google.com", "gcr.io", "*.gcr.io"}
|
||||
|
||||
var metadataHeader = &http.Header{
|
||||
"Metadata-Flavor": []string{"Google"},
|
||||
}
|
||||
|
||||
// A DockerConfigProvider that reads its configuration from Google
|
||||
// Compute Engine metadata.
|
||||
type metadataProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// A DockerConfigProvider that reads its configuration from a specific
|
||||
// Google Compute Engine metadata key: 'google-dockercfg'.
|
||||
type dockerConfigKeyProvider struct {
|
||||
metadataProvider
|
||||
}
|
||||
|
||||
// A DockerConfigProvider that reads its configuration from a URL read from
|
||||
// a specific Google Compute Engine metadata key: 'google-dockercfg-url'.
|
||||
type dockerConfigUrlKeyProvider struct {
|
||||
metadataProvider
|
||||
}
|
||||
|
||||
// A DockerConfigProvider that provides a dockercfg with:
|
||||
// Username: "_token"
|
||||
// Password: "{access token from metadata}"
|
||||
type containerRegistryProvider struct {
|
||||
metadataProvider
|
||||
}
|
||||
|
||||
// init registers the various means by which credentials may
|
||||
// be resolved on GCP.
|
||||
func init() {
|
||||
tr := utilnet.SetTransportDefaults(&http.Transport{})
|
||||
metadataHTTPClientTimeout := time.Second * 10
|
||||
httpClient := &http.Client{
|
||||
Transport: tr,
|
||||
Timeout: metadataHTTPClientTimeout,
|
||||
}
|
||||
credentialprovider.RegisterCredentialProvider("google-dockercfg",
|
||||
&credentialprovider.CachingDockerConfigProvider{
|
||||
Provider: &dockerConfigKeyProvider{
|
||||
metadataProvider{Client: httpClient},
|
||||
},
|
||||
Lifetime: 60 * time.Second,
|
||||
})
|
||||
|
||||
credentialprovider.RegisterCredentialProvider("google-dockercfg-url",
|
||||
&credentialprovider.CachingDockerConfigProvider{
|
||||
Provider: &dockerConfigUrlKeyProvider{
|
||||
metadataProvider{Client: httpClient},
|
||||
},
|
||||
Lifetime: 60 * time.Second,
|
||||
})
|
||||
|
||||
credentialprovider.RegisterCredentialProvider("google-container-registry",
|
||||
// Never cache this. The access token is already
|
||||
// cached by the metadata service.
|
||||
&containerRegistryProvider{
|
||||
metadataProvider{Client: httpClient},
|
||||
})
|
||||
}
|
||||
|
||||
// Returns true if it finds a local GCE VM.
|
||||
// Looks at a product file that is an undocumented API.
|
||||
func onGCEVM() bool {
|
||||
data, err := ioutil.ReadFile(gceProductNameFile)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Error while reading product_name: %v", err)
|
||||
return false
|
||||
}
|
||||
return strings.Contains(string(data), googleProductName)
|
||||
}
|
||||
|
||||
// Enabled implements DockerConfigProvider for all of the Google implementations.
|
||||
func (g *metadataProvider) Enabled() bool {
|
||||
return onGCEVM()
|
||||
}
|
||||
|
||||
// LazyProvide implements DockerConfigProvider. Should never be called.
|
||||
func (g *dockerConfigKeyProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Provide implements DockerConfigProvider
|
||||
func (g *dockerConfigKeyProvider) Provide() credentialprovider.DockerConfig {
|
||||
// Read the contents of the google-dockercfg metadata key and
|
||||
// parse them as an alternate .dockercfg
|
||||
if cfg, err := credentialprovider.ReadDockerConfigFileFromUrl(dockerConfigKey, g.Client, metadataHeader); err != nil {
|
||||
glog.Errorf("while reading 'google-dockercfg' metadata: %v", err)
|
||||
} else {
|
||||
return cfg
|
||||
}
|
||||
|
||||
return credentialprovider.DockerConfig{}
|
||||
}
|
||||
|
||||
// LazyProvide implements DockerConfigProvider. Should never be called.
|
||||
func (g *dockerConfigUrlKeyProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Provide implements DockerConfigProvider
|
||||
func (g *dockerConfigUrlKeyProvider) Provide() credentialprovider.DockerConfig {
|
||||
// Read the contents of the google-dockercfg-url key and load a .dockercfg from there
|
||||
if url, err := credentialprovider.ReadUrl(dockerConfigUrlKey, g.Client, metadataHeader); err != nil {
|
||||
glog.Errorf("while reading 'google-dockercfg-url' metadata: %v", err)
|
||||
} else {
|
||||
if strings.HasPrefix(string(url), "http") {
|
||||
if cfg, err := credentialprovider.ReadDockerConfigFileFromUrl(string(url), g.Client, nil); err != nil {
|
||||
glog.Errorf("while reading 'google-dockercfg-url'-specified url: %s, %v", string(url), err)
|
||||
} else {
|
||||
return cfg
|
||||
}
|
||||
} else {
|
||||
// TODO(mattmoor): support reading alternate scheme URLs (e.g. gs:// or s3://)
|
||||
glog.Errorf("Unsupported URL scheme: %s", string(url))
|
||||
}
|
||||
}
|
||||
|
||||
return credentialprovider.DockerConfig{}
|
||||
}
|
||||
|
||||
// runcWithBackoff runs input function `f` with an exponential backoff.
|
||||
// Note that this method can block indefinitely.
|
||||
func runWithBackoff(f func() ([]byte, error)) []byte {
|
||||
var backoff = 100 * time.Millisecond
|
||||
const maxBackoff = time.Minute
|
||||
for {
|
||||
value, err := f()
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
time.Sleep(backoff)
|
||||
backoff = backoff * 2
|
||||
if backoff > maxBackoff {
|
||||
backoff = maxBackoff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled implements a special metadata-based check, which verifies the
|
||||
// storage scope is available on the GCE VM.
|
||||
// If running on a GCE VM, check if 'default' service account exists.
|
||||
// If it does not exist, assume that registry is not enabled.
|
||||
// If default service account exists, check if relevant scopes exist in the default service account.
|
||||
// The metadata service can become temporarily inaccesible. Hence all requests to the metadata
|
||||
// service will be retried until the metadata server returns a `200`.
|
||||
// It is expected that "http://metadata.google.internal./computeMetadata/v1/instance/service-accounts/" will return a `200`
|
||||
// and "http://metadata.google.internal./computeMetadata/v1/instance/service-accounts/default/scopes" will also return `200`.
|
||||
// More information on metadata service can be found here - https://cloud.google.com/compute/docs/storing-retrieving-metadata
|
||||
func (g *containerRegistryProvider) Enabled() bool {
|
||||
if !onGCEVM() {
|
||||
return false
|
||||
}
|
||||
// Given that we are on GCE, we should keep retrying until the metadata server responds.
|
||||
value := runWithBackoff(func() ([]byte, error) {
|
||||
value, err := credentialprovider.ReadUrl(serviceAccounts, g.Client, metadataHeader)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to Get service accounts from gce metadata server: %v", err)
|
||||
}
|
||||
return value, err
|
||||
})
|
||||
// We expect the service account to return a list of account directories separated by newlines, e.g.,
|
||||
// sv-account-name1/
|
||||
// sv-account-name2/
|
||||
// ref: https://cloud.google.com/compute/docs/storing-retrieving-metadata
|
||||
defaultServiceAccountExists := false
|
||||
for _, sa := range strings.Split(string(value), "\n") {
|
||||
if strings.TrimSpace(sa) == defaultServiceAccount {
|
||||
defaultServiceAccountExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !defaultServiceAccountExists {
|
||||
glog.V(2).Infof("'default' service account does not exist. Found following service accounts: %q", string(value))
|
||||
return false
|
||||
}
|
||||
url := metadataScopes + "?alt=json"
|
||||
value = runWithBackoff(func() ([]byte, error) {
|
||||
value, err := credentialprovider.ReadUrl(url, g.Client, metadataHeader)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to Get scopes in default service account from gce metadata server: %v", err)
|
||||
}
|
||||
return value, err
|
||||
})
|
||||
var scopes []string
|
||||
if err := json.Unmarshal(value, &scopes); err != nil {
|
||||
glog.Errorf("Failed to unmarshal scopes: %v", err)
|
||||
return false
|
||||
}
|
||||
for _, v := range scopes {
|
||||
// cloudPlatformScope implies storage scope.
|
||||
if strings.HasPrefix(v, storageScopePrefix) || strings.HasPrefix(v, cloudPlatformScopePrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
glog.Warningf("Google container registry is disabled, no storage scope is available: %s", value)
|
||||
return false
|
||||
}
|
||||
|
||||
// tokenBlob is used to decode the JSON blob containing an access token
|
||||
// that is returned by GCE metadata.
|
||||
type tokenBlob struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
|
||||
// LazyProvide implements DockerConfigProvider. Should never be called.
|
||||
func (g *containerRegistryProvider) LazyProvide() *credentialprovider.DockerConfigEntry {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Provide implements DockerConfigProvider
|
||||
func (g *containerRegistryProvider) Provide() credentialprovider.DockerConfig {
|
||||
cfg := credentialprovider.DockerConfig{}
|
||||
|
||||
tokenJsonBlob, err := credentialprovider.ReadUrl(metadataToken, g.Client, metadataHeader)
|
||||
if err != nil {
|
||||
glog.Errorf("while reading access token endpoint: %v", err)
|
||||
return cfg
|
||||
}
|
||||
|
||||
email, err := credentialprovider.ReadUrl(metadataEmail, g.Client, metadataHeader)
|
||||
if err != nil {
|
||||
glog.Errorf("while reading email endpoint: %v", err)
|
||||
return cfg
|
||||
}
|
||||
|
||||
var parsedBlob tokenBlob
|
||||
if err := json.Unmarshal([]byte(tokenJsonBlob), &parsedBlob); err != nil {
|
||||
glog.Errorf("while parsing json blob %s: %v", tokenJsonBlob, err)
|
||||
return cfg
|
||||
}
|
||||
|
||||
entry := credentialprovider.DockerConfigEntry{
|
||||
Username: "_token",
|
||||
Password: parsedBlob.AccessToken,
|
||||
Email: string(email),
|
||||
}
|
||||
|
||||
// Add our entry for each of the supported container registry URLs
|
||||
for _, k := range containerRegistryUrls {
|
||||
cfg[k] = entry
|
||||
}
|
||||
return cfg
|
||||
}
|
Reference in New Issue
Block a user