Merge pull request #94196 from andrewsykim/registry-creds
kubelet: add alpha credential provider plugins
This commit is contained in:
commit
d233111f5b
@ -385,6 +385,10 @@ API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,Policy,Pri
|
|||||||
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,RequestedToCapacityRatioArguments,Resources
|
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,RequestedToCapacityRatioArguments,Resources
|
||||||
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,RequestedToCapacityRatioArguments,Shape
|
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,RequestedToCapacityRatioArguments,Shape
|
||||||
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,ServiceAffinity,Labels
|
API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,ServiceAffinity,Labels
|
||||||
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1alpha1,CredentialProvider,Args
|
||||||
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1alpha1,CredentialProvider,Env
|
||||||
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1alpha1,CredentialProvider,MatchImages
|
||||||
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1alpha1,CredentialProviderConfig,Providers
|
||||||
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,AllowedUnsafeSysctls
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,AllowedUnsafeSysctls
|
||||||
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ClusterDNS
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ClusterDNS
|
||||||
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,EnforceNodeAllocatable
|
API rule violation: list_type_missing,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,EnforceNodeAllocatable
|
||||||
|
@ -101,6 +101,7 @@ tags_values_pkgs = {"openapi-gen": {
|
|||||||
"staging/src/k8s.io/kube-proxy/config/v1alpha1",
|
"staging/src/k8s.io/kube-proxy/config/v1alpha1",
|
||||||
"staging/src/k8s.io/kube-scheduler/config/v1",
|
"staging/src/k8s.io/kube-scheduler/config/v1",
|
||||||
"staging/src/k8s.io/kube-scheduler/config/v1beta1",
|
"staging/src/k8s.io/kube-scheduler/config/v1beta1",
|
||||||
|
"staging/src/k8s.io/kubelet/config/v1alpha1",
|
||||||
"staging/src/k8s.io/kubelet/config/v1beta1",
|
"staging/src/k8s.io/kubelet/config/v1beta1",
|
||||||
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1",
|
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1",
|
||||||
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2",
|
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2",
|
||||||
@ -188,6 +189,7 @@ tags_pkgs_values = {"openapi-gen": {
|
|||||||
"staging/src/k8s.io/kube-proxy/config/v1alpha1": ["true"],
|
"staging/src/k8s.io/kube-proxy/config/v1alpha1": ["true"],
|
||||||
"staging/src/k8s.io/kube-scheduler/config/v1": ["true"],
|
"staging/src/k8s.io/kube-scheduler/config/v1": ["true"],
|
||||||
"staging/src/k8s.io/kube-scheduler/config/v1beta1": ["true"],
|
"staging/src/k8s.io/kube-scheduler/config/v1beta1": ["true"],
|
||||||
|
"staging/src/k8s.io/kubelet/config/v1alpha1": ["true"],
|
||||||
"staging/src/k8s.io/kubelet/config/v1beta1": ["true"],
|
"staging/src/k8s.io/kubelet/config/v1beta1": ["true"],
|
||||||
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1": ["true"],
|
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1": ["true"],
|
||||||
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2": ["true"],
|
"staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2": ["true"],
|
||||||
|
@ -1130,6 +1130,8 @@ func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencie
|
|||||||
kubeServer.CloudProvider,
|
kubeServer.CloudProvider,
|
||||||
kubeServer.CertDirectory,
|
kubeServer.CertDirectory,
|
||||||
kubeServer.RootDirectory,
|
kubeServer.RootDirectory,
|
||||||
|
kubeServer.ImageCredentialProviderConfigFile,
|
||||||
|
kubeServer.ImageCredentialProviderBinDir,
|
||||||
kubeServer.RegisterNode,
|
kubeServer.RegisterNode,
|
||||||
kubeServer.RegisterWithTaints,
|
kubeServer.RegisterWithTaints,
|
||||||
kubeServer.AllowedUnsafeSysctls,
|
kubeServer.AllowedUnsafeSysctls,
|
||||||
@ -1204,6 +1206,8 @@ func createAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
cloudProvider string,
|
cloudProvider string,
|
||||||
certDirectory string,
|
certDirectory string,
|
||||||
rootDirectory string,
|
rootDirectory string,
|
||||||
|
imageCredentialProviderConfigFile string,
|
||||||
|
imageCredentialProviderBinDir string,
|
||||||
registerNode bool,
|
registerNode bool,
|
||||||
registerWithTaints []api.Taint,
|
registerWithTaints []api.Taint,
|
||||||
allowedUnsafeSysctls []string,
|
allowedUnsafeSysctls []string,
|
||||||
@ -1235,6 +1239,8 @@ func createAndInitKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
cloudProvider,
|
cloudProvider,
|
||||||
certDirectory,
|
certDirectory,
|
||||||
rootDirectory,
|
rootDirectory,
|
||||||
|
imageCredentialProviderConfigFile,
|
||||||
|
imageCredentialProviderBinDir,
|
||||||
registerNode,
|
registerNode,
|
||||||
registerWithTaints,
|
registerWithTaints,
|
||||||
allowedUnsafeSysctls,
|
allowedUnsafeSysctls,
|
||||||
|
@ -88,6 +88,7 @@ pkg/controller/volume/persistentvolume
|
|||||||
pkg/controller/volume/persistentvolume/config/v1alpha1
|
pkg/controller/volume/persistentvolume/config/v1alpha1
|
||||||
pkg/controlplane/controller/crdregistration
|
pkg/controlplane/controller/crdregistration
|
||||||
pkg/controlplane/tunneler
|
pkg/controlplane/tunneler
|
||||||
|
pkg/credentialprovider/plugin
|
||||||
pkg/features
|
pkg/features
|
||||||
pkg/kubeapiserver
|
pkg/kubeapiserver
|
||||||
pkg/kubectl/cmd/convert
|
pkg/kubectl/cmd/convert
|
||||||
@ -455,6 +456,8 @@ staging/src/k8s.io/kubectl/pkg/polymorphichelpers
|
|||||||
staging/src/k8s.io/kubectl/pkg/scale
|
staging/src/k8s.io/kubectl/pkg/scale
|
||||||
staging/src/k8s.io/kubectl/pkg/util/templates
|
staging/src/k8s.io/kubectl/pkg/util/templates
|
||||||
staging/src/k8s.io/kubelet/config/v1beta1
|
staging/src/k8s.io/kubelet/config/v1beta1
|
||||||
|
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider
|
||||||
|
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1
|
||||||
staging/src/k8s.io/legacy-cloud-providers/vsphere
|
staging/src/k8s.io/legacy-cloud-providers/vsphere
|
||||||
staging/src/k8s.io/metrics/pkg/apis/custom_metrics
|
staging/src/k8s.io/metrics/pkg/apis/custom_metrics
|
||||||
staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1
|
staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1
|
||||||
|
@ -46,6 +46,7 @@ filegroup(
|
|||||||
"//pkg/credentialprovider/aws:all-srcs",
|
"//pkg/credentialprovider/aws:all-srcs",
|
||||||
"//pkg/credentialprovider/azure:all-srcs",
|
"//pkg/credentialprovider/azure:all-srcs",
|
||||||
"//pkg/credentialprovider/gcp:all-srcs",
|
"//pkg/credentialprovider/gcp:all-srcs",
|
||||||
|
"//pkg/credentialprovider/plugin:all-srcs",
|
||||||
"//pkg/credentialprovider/secrets:all-srcs",
|
"//pkg/credentialprovider/secrets:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
@ -158,9 +158,10 @@ func isDefaultRegistryMatch(image string) bool {
|
|||||||
return !strings.ContainsAny(parts[0], ".:")
|
return !strings.ContainsAny(parts[0], ".:")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseSchemelessURL parses a schemeless url and returns a url.URL
|
||||||
// url.Parse require a scheme, but ours don't have schemes. Adding a
|
// url.Parse require a scheme, but ours don't have schemes. Adding a
|
||||||
// scheme to make url.Parse happy, then clear out the resulting scheme.
|
// scheme to make url.Parse happy, then clear out the resulting scheme.
|
||||||
func parseSchemelessURL(schemelessURL string) (*url.URL, error) {
|
func ParseSchemelessURL(schemelessURL string) (*url.URL, error) {
|
||||||
parsed, err := url.Parse("https://" + schemelessURL)
|
parsed, err := url.Parse("https://" + schemelessURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -170,8 +171,8 @@ func parseSchemelessURL(schemelessURL string) (*url.URL, error) {
|
|||||||
return parsed, nil
|
return parsed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// split the host name into parts, as well as the port
|
// SplitURL splits the host name into parts, as well as the port
|
||||||
func splitURL(url *url.URL) (parts []string, port string) {
|
func SplitURL(url *url.URL) (parts []string, port string) {
|
||||||
host, port, err := net.SplitHostPort(url.Host)
|
host, port, err := net.SplitHostPort(url.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// could not parse port
|
// could not parse port
|
||||||
@ -180,20 +181,20 @@ func splitURL(url *url.URL) (parts []string, port string) {
|
|||||||
return strings.Split(host, "."), port
|
return strings.Split(host, "."), port
|
||||||
}
|
}
|
||||||
|
|
||||||
// overloaded version of urlsMatch, operating on strings instead of URLs.
|
// URLsMatchStr is wrapper for URLsMatch, operating on strings instead of URLs.
|
||||||
func urlsMatchStr(glob string, target string) (bool, error) {
|
func URLsMatchStr(glob string, target string) (bool, error) {
|
||||||
globURL, err := parseSchemelessURL(glob)
|
globURL, err := ParseSchemelessURL(glob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
targetURL, err := parseSchemelessURL(target)
|
targetURL, err := ParseSchemelessURL(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return urlsMatch(globURL, targetURL)
|
return URLsMatch(globURL, targetURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether the given target url matches the glob url, which may have
|
// URLsMatch checks whether the given target url matches the glob url, which may have
|
||||||
// glob wild cards in the host name.
|
// glob wild cards in the host name.
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
@ -201,9 +202,9 @@ func urlsMatchStr(glob string, target string) (bool, error) {
|
|||||||
// globURL=*.docker.io, targetURL=not.right.io => no match
|
// globURL=*.docker.io, targetURL=not.right.io => no match
|
||||||
//
|
//
|
||||||
// Note that we don't support wildcards in ports and paths yet.
|
// Note that we don't support wildcards in ports and paths yet.
|
||||||
func urlsMatch(globURL *url.URL, targetURL *url.URL) (bool, error) {
|
func URLsMatch(globURL *url.URL, targetURL *url.URL) (bool, error) {
|
||||||
globURLParts, globPort := splitURL(globURL)
|
globURLParts, globPort := SplitURL(globURL)
|
||||||
targetURLParts, targetPort := splitURL(targetURL)
|
targetURLParts, targetPort := SplitURL(targetURL)
|
||||||
if globPort != targetPort {
|
if globPort != targetPort {
|
||||||
// port doesn't match
|
// port doesn't match
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -240,7 +241,7 @@ func (dk *BasicDockerKeyring) Lookup(image string) ([]AuthConfig, bool) {
|
|||||||
for _, k := range dk.index {
|
for _, k := range dk.index {
|
||||||
// both k and image are schemeless URLs because even though schemes are allowed
|
// both k and image are schemeless URLs because even though schemes are allowed
|
||||||
// in the credential configurations, we remove them in Add.
|
// in the credential configurations, we remove them in Add.
|
||||||
if matched, _ := urlsMatchStr(k, image); matched {
|
if matched, _ := URLsMatchStr(k, image); matched {
|
||||||
ret = append(ret, dk.creds[k]...)
|
ret = append(ret, dk.creds[k]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUrlsMatch(t *testing.T) {
|
func TestURLsMatch(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
globURL string
|
globURL string
|
||||||
targetURL string
|
targetURL string
|
||||||
@ -112,7 +112,7 @@ func TestUrlsMatch(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
matched, _ := urlsMatchStr(test.globURL, test.targetURL)
|
matched, _ := URLsMatchStr(test.globURL, test.targetURL)
|
||||||
if matched != test.matchExpected {
|
if matched != test.matchExpected {
|
||||||
t.Errorf("Expected match result of %s and %s to be %t, but was %t",
|
t.Errorf("Expected match result of %s and %s to be %t, but was %t",
|
||||||
test.globURL, test.targetURL, test.matchExpected, matched)
|
test.globURL, test.targetURL, test.matchExpected, matched)
|
||||||
|
58
pkg/credentialprovider/plugin/BUILD
Normal file
58
pkg/credentialprovider/plugin/BUILD
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"config.go",
|
||||||
|
"plugin.go",
|
||||||
|
],
|
||||||
|
importpath = "k8s.io/kubernetes/pkg/credentialprovider/plugin",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/credentialprovider:go_default_library",
|
||||||
|
"//pkg/kubelet/apis/config:go_default_library",
|
||||||
|
"//pkg/kubelet/apis/config/v1alpha1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/install:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1:go_default_library",
|
||||||
|
"//vendor/k8s.io/klog/v2:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"config_test.go",
|
||||||
|
"plugin_test.go",
|
||||||
|
],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/credentialprovider:go_default_library",
|
||||||
|
"//pkg/kubelet/apis/config:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
128
pkg/credentialprovider/plugin/config.go
Normal file
128
pkg/credentialprovider/plugin/config.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// readCredentialProviderConfigFile receives a path to a config file and decodes it
|
||||||
|
// into the internal CredentialProviderConfig type.
|
||||||
|
func readCredentialProviderConfigFile(configPath string) (*kubeletconfig.CredentialProviderConfig, error) {
|
||||||
|
if configPath == "" {
|
||||||
|
return nil, fmt.Errorf("credential provider config path is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read external registry credential provider configuration from %q: %v", configPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := decode(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error decoding config %s: %v", configPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode decodes data into the internal CredentialProviderConfig type.
|
||||||
|
func decode(data []byte) (*kubeletconfig.CredentialProviderConfig, error) {
|
||||||
|
obj, gvk, err := codecs.UniversalDecoder().Decode(data, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.Kind != "CredentialProviderConfig" {
|
||||||
|
return nil, fmt.Errorf("failed to decode %q (wrong Kind)", gvk.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.Group != kubeletconfig.GroupName {
|
||||||
|
return nil, fmt.Errorf("failed to decode CredentialProviderConfig, unexpected Group: %s", gvk.Group)
|
||||||
|
}
|
||||||
|
|
||||||
|
if internalConfig, ok := obj.(*kubeletconfig.CredentialProviderConfig); ok {
|
||||||
|
return internalConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unable to convert %T to *CredentialProviderConfig", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateCredentialProviderConfig validates CredentialProviderConfig.
|
||||||
|
func validateCredentialProviderConfig(config *kubeletconfig.CredentialProviderConfig) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
if len(config.Providers) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(field.NewPath("providers"), "at least 1 item in plugins is required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldPath := field.NewPath("providers")
|
||||||
|
for _, provider := range config.Providers {
|
||||||
|
if strings.Contains(provider.Name, "/") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("name"), provider.Name, "provider name cannot contain '/'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(provider.Name, " ") {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("name"), provider.Name, "provider name cannot contain spaces"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.Name == "." {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("name"), provider.Name, "provider name cannot be '.'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.Name == ".." {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("name"), provider.Name, "provider name cannot be '..'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.APIVersion == "" {
|
||||||
|
allErrs = append(allErrs, field.Required(fieldPath.Child("apiVersion"), "apiVersion is required"))
|
||||||
|
} else if _, ok := apiVersions[provider.APIVersion]; !ok {
|
||||||
|
validAPIVersions := []string{}
|
||||||
|
for apiVersion := range apiVersions {
|
||||||
|
validAPIVersions = append(validAPIVersions, apiVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
allErrs = append(allErrs, field.NotSupported(fieldPath.Child("apiVersion"), provider.APIVersion, validAPIVersions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(provider.MatchImages) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fieldPath.Child("matchImages"), "at least 1 item in matchImages is required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, matchImage := range provider.MatchImages {
|
||||||
|
if _, err := credentialprovider.ParseSchemelessURL(matchImage); err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("matchImages"), matchImage, fmt.Sprintf("match image is invalid: %s", err.Error())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.DefaultCacheDuration == nil {
|
||||||
|
allErrs = append(allErrs, field.Required(fieldPath.Child("defaultCacheDuration"), "defaultCacheDuration is required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.DefaultCacheDuration != nil && provider.DefaultCacheDuration.Duration < 0 {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath.Child("defaultCacheDuration"), provider.DefaultCacheDuration.Duration, "defaultCacheDuration must be greater than or equal to 0"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
435
pkg/credentialprovider/plugin/config_test.go
Normal file
435
pkg/credentialprovider/plugin/config_test.go
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_readCredentialProviderConfigFile(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
configData string
|
||||||
|
config *kubeletconfig.CredentialProviderConfig
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "config with 1 plugin and 1 image matcher",
|
||||||
|
configData: `---
|
||||||
|
kind: CredentialProviderConfig
|
||||||
|
apiVersion: kubelet.config.k8s.io/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/foobar"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "test",
|
||||||
|
MatchImages: []string{"registry.io/foobar"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: 10 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
Args: []string{"--v=5"},
|
||||||
|
Env: []kubeletconfig.ExecEnvVar{
|
||||||
|
{
|
||||||
|
Name: "FOO",
|
||||||
|
Value: "BAR",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config with 1 plugin and a wildcard image match",
|
||||||
|
configData: `---
|
||||||
|
kind: CredentialProviderConfig
|
||||||
|
apiVersion: kubelet.config.k8s.io/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/*"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "test",
|
||||||
|
MatchImages: []string{"registry.io/*"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: 10 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
Args: []string{"--v=5"},
|
||||||
|
Env: []kubeletconfig.ExecEnvVar{
|
||||||
|
{
|
||||||
|
Name: "FOO",
|
||||||
|
Value: "BAR",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config with 1 plugin and multiple image matchers",
|
||||||
|
configData: `---
|
||||||
|
kind: CredentialProviderConfig
|
||||||
|
apiVersion: kubelet.config.k8s.io/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/*"
|
||||||
|
- "foobar.registry.io/*"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "test",
|
||||||
|
MatchImages: []string{"registry.io/*", "foobar.registry.io/*"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: 10 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
Args: []string{"--v=5"},
|
||||||
|
Env: []kubeletconfig.ExecEnvVar{
|
||||||
|
{
|
||||||
|
Name: "FOO",
|
||||||
|
Value: "BAR",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config with multiple providers",
|
||||||
|
configData: `---
|
||||||
|
kind: CredentialProviderConfig
|
||||||
|
apiVersion: kubelet.config.k8s.io/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test1
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/one"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
- name: test2
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/two"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "test1",
|
||||||
|
MatchImages: []string{"registry.io/one"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: 10 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "test2",
|
||||||
|
MatchImages: []string{"registry.io/two"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: 10 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
Args: []string{"--v=5"},
|
||||||
|
Env: []kubeletconfig.ExecEnvVar{
|
||||||
|
{
|
||||||
|
Name: "FOO",
|
||||||
|
Value: "BAR",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config with wrong Kind",
|
||||||
|
configData: `---
|
||||||
|
kind: WrongKind
|
||||||
|
apiVersion: kubelet.config.k8s.io/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/foobar"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
config: nil,
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config with wrong apiversion",
|
||||||
|
configData: `---
|
||||||
|
kind: CredentialProviderConfig
|
||||||
|
apiVersion: foobar/v1alpha1
|
||||||
|
providers:
|
||||||
|
- name: test
|
||||||
|
matchImages:
|
||||||
|
- "registry.io/foobar"
|
||||||
|
defaultCacheDuration: 10m
|
||||||
|
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
args:
|
||||||
|
- --v=5
|
||||||
|
env:
|
||||||
|
- name: FOO
|
||||||
|
value: BAR`,
|
||||||
|
config: nil,
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
_, err = file.WriteString(testcase.configData)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
authConfig, err := readCredentialProviderConfigFile(file.Name())
|
||||||
|
if err != nil && !testcase.expectErr {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && testcase.expectErr {
|
||||||
|
t.Error("expected error but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(authConfig, testcase.config) {
|
||||||
|
t.Logf("actual auth config: %#v", authConfig)
|
||||||
|
t.Logf("expected auth config: %#v", testcase.config)
|
||||||
|
t.Error("credential provider config did not match")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_validateCredentialProviderConfig(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
config *kubeletconfig.CredentialProviderConfig
|
||||||
|
shouldErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no providers provided",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no matchImages provided",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no default cache duration provided",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name contains '/'",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foo/../bar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name is '.'",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: ".",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name is '..'",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "..",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name contains spaces",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foo bar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no apiVersion",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid apiVersion",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative default cache duration",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: -1 * time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid match image",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"%invalid%"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid config",
|
||||||
|
config: &kubeletconfig.CredentialProviderConfig{
|
||||||
|
Providers: []kubeletconfig.CredentialProvider{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
MatchImages: []string{"foobar.registry.io"},
|
||||||
|
DefaultCacheDuration: &metav1.Duration{Duration: time.Minute},
|
||||||
|
APIVersion: "credentialprovider.kubelet.k8s.io/v1alpha1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
errs := validateCredentialProviderConfig(testcase.config)
|
||||||
|
|
||||||
|
if testcase.shouldErr && len(errs) == 0 {
|
||||||
|
t.Errorf("expected error but got none")
|
||||||
|
} else if !testcase.shouldErr && len(errs) > 0 {
|
||||||
|
t.Errorf("expected no error but received errors: %v", errs.ToAggregate())
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
420
pkg/credentialprovider/plugin/plugin.go
Normal file
420
pkg/credentialprovider/plugin/plugin.go
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
credentialproviderapi "k8s.io/kubelet/pkg/apis/credentialprovider"
|
||||||
|
"k8s.io/kubelet/pkg/apis/credentialprovider/install"
|
||||||
|
credentialproviderv1alpha1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
|
||||||
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
kubeletconfigv1alpha1 "k8s.io/kubernetes/pkg/kubelet/apis/config/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
globalCacheKey = "global"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
codecs = serializer.NewCodecFactory(scheme)
|
||||||
|
|
||||||
|
apiVersions = map[string]schema.GroupVersion{
|
||||||
|
credentialproviderv1alpha1.SchemeGroupVersion.String(): credentialproviderv1alpha1.SchemeGroupVersion,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
install.Install(scheme)
|
||||||
|
kubeletconfig.AddToScheme(scheme)
|
||||||
|
kubeletconfigv1alpha1.AddToScheme(scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCredentialProviderPlugins is called from kubelet to register external credential provider
|
||||||
|
// plugins according to the CredentialProviderConfig config file.
|
||||||
|
func RegisterCredentialProviderPlugins(pluginConfigFile, pluginBinDir string) error {
|
||||||
|
if _, err := os.Stat(pluginBinDir); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("plugin binary directory %s did not exist", pluginBinDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("error inspecting binary directory %s: %w", pluginBinDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialProviderConfig, err := readCredentialProviderConfigFile(pluginConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := validateCredentialProviderConfig(credentialProviderConfig)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to validate credential provider config: %v", errs.ToAggregate())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, provider := range credentialProviderConfig.Providers {
|
||||||
|
pluginBin := filepath.Join(pluginBinDir, provider.Name)
|
||||||
|
if _, err := os.Stat(pluginBin); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("plugin binary executable %s did not exist", pluginBin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("error inspecting binary executable %s: %w", pluginBin, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin, err := newPluginProvider(pluginBinDir, provider)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error initializing plugin provider %s: %w", provider.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialprovider.RegisterCredentialProvider(provider.Name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newPluginProvider returns a new pluginProvider based on the credential provider config.
|
||||||
|
func newPluginProvider(pluginBinDir string, provider kubeletconfig.CredentialProvider) (*pluginProvider, error) {
|
||||||
|
mediaType := "application/json"
|
||||||
|
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported media type %q", mediaType)
|
||||||
|
}
|
||||||
|
|
||||||
|
gv, ok := apiVersions[provider.APIVersion]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid apiVersion: %q", provider.APIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pluginProvider{
|
||||||
|
matchImages: provider.MatchImages,
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
defaultCacheDuration: provider.DefaultCacheDuration.Duration,
|
||||||
|
plugin: &execPlugin{
|
||||||
|
name: provider.Name,
|
||||||
|
apiVersion: provider.APIVersion,
|
||||||
|
encoder: codecs.EncoderForVersion(info.Serializer, gv),
|
||||||
|
pluginBinDir: pluginBinDir,
|
||||||
|
args: provider.Args,
|
||||||
|
envVars: provider.Env,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pluginProvider is the plugin-based implementation of the DockerConfigProvider interface.
|
||||||
|
type pluginProvider struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
// matchImages defines the matching image URLs this plugin should operate against.
|
||||||
|
// The plugin provider will not return any credentials for images that do not match
|
||||||
|
// against this list of match URLs.
|
||||||
|
matchImages []string
|
||||||
|
|
||||||
|
// cache stores DockerConfig entries with an expiration time based on the cache duration
|
||||||
|
// returned from the credential provider plugin.
|
||||||
|
cache cache.Store
|
||||||
|
// defaultCacheDuration is the default duration credentials are cached in-memory if the auth plugin
|
||||||
|
// response did not provide a cache duration for credentials.
|
||||||
|
defaultCacheDuration time.Duration
|
||||||
|
|
||||||
|
// plugin is the exec implementation of the credential providing plugin.
|
||||||
|
plugin Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheEntry is the cache object that will be stored in cache.Store.
|
||||||
|
type cacheEntry struct {
|
||||||
|
key string
|
||||||
|
credentials credentialprovider.DockerConfig
|
||||||
|
expiresAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheKeyFunc extracts AuthEntry.MatchKey as the cache key function for the plugin provider.
|
||||||
|
func cacheKeyFunc(obj interface{}) (string, error) {
|
||||||
|
key := obj.(*cacheEntry).key
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheExpirationPolicy defines implements cache.ExpirationPolicy, determining expiration based on the expiresAt timestamp.
|
||||||
|
type cacheExpirationPolicy struct{}
|
||||||
|
|
||||||
|
// IsExpired returns true if the current time is after cacheEntry.expiresAt, which is determined by the
|
||||||
|
// cache duration returned from the credential provider plugin response.
|
||||||
|
func (c *cacheExpirationPolicy) IsExpired(entry *cache.TimestampedEntry) bool {
|
||||||
|
return time.Now().After(entry.Obj.(*cacheEntry).expiresAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide returns a credentialprovider.DockerConfig based on the credentials returned
|
||||||
|
// from cache or the exec plugin.
|
||||||
|
func (p *pluginProvider) Provide(image string) credentialprovider.DockerConfig {
|
||||||
|
if !p.isImageAllowed(image) {
|
||||||
|
return credentialprovider.DockerConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
cachedConfig, found, err := p.getCachedCredentials(image)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("Failed to get cached docker config: %v", err)
|
||||||
|
return credentialprovider.DockerConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return cachedConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := p.plugin.ExecPlugin(context.Background(), image)
|
||||||
|
if err != nil {
|
||||||
|
klog.Errorf("Failed getting credential from external registry credential provider: %v", err)
|
||||||
|
return credentialprovider.DockerConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cacheKey string
|
||||||
|
switch cacheKeyType := response.CacheKeyType; cacheKeyType {
|
||||||
|
case credentialproviderapi.ImagePluginCacheKeyType:
|
||||||
|
cacheKey = image
|
||||||
|
case credentialproviderapi.RegistryPluginCacheKeyType:
|
||||||
|
registry := parseRegistry(image)
|
||||||
|
cacheKey = registry
|
||||||
|
case credentialproviderapi.GlobalPluginCacheKeyType:
|
||||||
|
cacheKey = globalCacheKey
|
||||||
|
default:
|
||||||
|
klog.Errorf("credential provider plugin did not return a valid cacheKeyType: %q", cacheKeyType)
|
||||||
|
return credentialprovider.DockerConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerConfig := make(credentialprovider.DockerConfig, len(response.Auth))
|
||||||
|
for matchImage, authConfig := range response.Auth {
|
||||||
|
dockerConfig[matchImage] = credentialprovider.DockerConfigEntry{
|
||||||
|
Username: authConfig.Username,
|
||||||
|
Password: authConfig.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache duration was explicitly 0 so don't cache this response at all.
|
||||||
|
if response.CacheDuration != nil && response.CacheDuration.Duration == 0 {
|
||||||
|
return dockerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var expiresAt time.Time
|
||||||
|
// nil cache duration means use the default cache duration
|
||||||
|
if response.CacheDuration == nil {
|
||||||
|
if p.defaultCacheDuration == 0 {
|
||||||
|
return dockerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresAt = time.Now().Add(p.defaultCacheDuration)
|
||||||
|
} else {
|
||||||
|
expiresAt = time.Now().Add(response.CacheDuration.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedEntry := &cacheEntry{
|
||||||
|
key: cacheKey,
|
||||||
|
credentials: dockerConfig,
|
||||||
|
expiresAt: expiresAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.cache.Add(cachedEntry); err != nil {
|
||||||
|
klog.Errorf("Error adding auth entry to cache: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled always returns true since registration of the plugin via kubelet implies it should be enabled.
|
||||||
|
func (e *pluginProvider) Enabled() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// isImageAllowed returns true if the image matches against the list of allowed matches by the plugin.
|
||||||
|
func (p *pluginProvider) isImageAllowed(image string) bool {
|
||||||
|
for _, matchImage := range p.matchImages {
|
||||||
|
if matched, _ := credentialprovider.URLsMatchStr(matchImage, image); matched {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCachedCredentials returns a credentialprovider.DockerConfig if cached from the plugin.
|
||||||
|
func (p *pluginProvider) getCachedCredentials(image string) (credentialprovider.DockerConfig, bool, error) {
|
||||||
|
obj, found, err := p.cache.GetByKey(image)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return obj.(*cacheEntry).credentials, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
registry := parseRegistry(image)
|
||||||
|
obj, found, err = p.cache.GetByKey(registry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return obj.(*cacheEntry).credentials, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, found, err = p.cache.GetByKey(globalCacheKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return obj.(*cacheEntry).credentials, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin is the interface calling ExecPlugin. This is mainly for testability
|
||||||
|
// so tests don't have to actually exec any processes.
|
||||||
|
type Plugin interface {
|
||||||
|
ExecPlugin(ctx context.Context, image string) (*credentialproviderapi.CredentialProviderResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execPlugin is the implementation of the Plugin interface that execs a credential provider plugin based
|
||||||
|
// on it's name provided in CredentialProviderConfig. It is assumed that the executable is available in the
|
||||||
|
// plugin directory provided by the kubelet.
|
||||||
|
type execPlugin struct {
|
||||||
|
name string
|
||||||
|
apiVersion string
|
||||||
|
encoder runtime.Encoder
|
||||||
|
args []string
|
||||||
|
envVars []kubeletconfig.ExecEnvVar
|
||||||
|
pluginBinDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecPlugin executes the plugin binary with arguments and environment variables specified in CredentialProviderConfig:
|
||||||
|
//
|
||||||
|
// $ ENV_NAME=ENV_VALUE <plugin-name> args[0] args[1] <<<request
|
||||||
|
//
|
||||||
|
// The plugin is expected to receive the CredentialProviderRequest API via stdin from the kubelet and
|
||||||
|
// return CredentialProviderResponse via stdout.
|
||||||
|
func (e *execPlugin) ExecPlugin(ctx context.Context, image string) (*credentialproviderapi.CredentialProviderResponse, error) {
|
||||||
|
authRequest := &credentialproviderapi.CredentialProviderRequest{Image: image}
|
||||||
|
data, err := e.encodeRequest(authRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to encode auth request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout := &bytes.Buffer{}
|
||||||
|
stderr := &bytes.Buffer{}
|
||||||
|
stdin := bytes.NewBuffer(data)
|
||||||
|
|
||||||
|
// Use a catch-all timeout of 1 minute for all exec-based plugins, this should leave enough
|
||||||
|
// head room in case a plugin needs to retry a failed request while ensuring an exec plugin
|
||||||
|
// does not run forever. In the future we may want this timeout to be tweakable from the plugin
|
||||||
|
// config file.
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(ctx, filepath.Join(e.pluginBinDir, e.name), e.args...)
|
||||||
|
cmd.Stdout, cmd.Stderr, cmd.Stdin = stdout, stderr, stdin
|
||||||
|
|
||||||
|
cmd.Env = []string{}
|
||||||
|
for _, envVar := range e.envVars {
|
||||||
|
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", envVar.Name, envVar.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Run()
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, fmt.Errorf("error execing credential provider plugin %s for image %s: %w", e.name, image, ctx.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.V(2).Infof("Error execing credential provider plugin, stderr: %v", stderr.String())
|
||||||
|
return nil, fmt.Errorf("error execing credential provider plugin %s for image %s: %w", e.name, image, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data = stdout.Bytes()
|
||||||
|
|
||||||
|
// check that the response apiVersion matches what is expected
|
||||||
|
gvk, err := json.DefaultMetaFactory.Interpret(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading GVK from response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.GroupVersion().String() != e.apiVersion {
|
||||||
|
return nil, errors.New("apiVersion from credential plugin response did not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := e.decodeResponse(stdout.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
// err is explicitly not wrapped since it may contain credentials in the response.
|
||||||
|
return nil, errors.New("error decoding credential provider plugin response from stdout")
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeRequest encodes the internal CredentialProviderRequest type into the v1alpha1 version in json
|
||||||
|
func (e *execPlugin) encodeRequest(request *credentialproviderapi.CredentialProviderRequest) ([]byte, error) {
|
||||||
|
data, err := runtime.Encode(e.encoder, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error encoding request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeResponse decodes data into the internal CredentialProviderResponse type
|
||||||
|
func (e *execPlugin) decodeResponse(data []byte) (*credentialproviderapi.CredentialProviderResponse, error) {
|
||||||
|
obj, gvk, err := codecs.UniversalDecoder().Decode(data, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.Kind != "CredentialProviderResponse" {
|
||||||
|
return nil, fmt.Errorf("failed to decode CredentialProviderResponse, unexpected Kind: %q", gvk.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.Group != credentialproviderapi.GroupName {
|
||||||
|
return nil, fmt.Errorf("failed to decode CredentialProviderResponse, unexpected Group: %s", gvk.Group)
|
||||||
|
}
|
||||||
|
|
||||||
|
if internalResponse, ok := obj.(*credentialproviderapi.CredentialProviderResponse); ok {
|
||||||
|
return internalResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unable to convert %T to *CredentialProviderResponse", obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRegistry extracts the registry hostname of an image (including port if specified).
|
||||||
|
func parseRegistry(image string) string {
|
||||||
|
imageParts := strings.Split(image, "/")
|
||||||
|
return imageParts[0]
|
||||||
|
}
|
505
pkg/credentialprovider/plugin/plugin_test.go
Normal file
505
pkg/credentialprovider/plugin/plugin_test.go
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
credentialproviderapi "k8s.io/kubelet/pkg/apis/credentialprovider"
|
||||||
|
credentialproviderv1alpha1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
|
||||||
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeExecPlugin struct {
|
||||||
|
cacheKeyType credentialproviderapi.PluginCacheKeyType
|
||||||
|
cacheDuration time.Duration
|
||||||
|
|
||||||
|
auth map[string]credentialproviderapi.AuthConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeExecPlugin) ExecPlugin(ctx context.Context, image string) (*credentialproviderapi.CredentialProviderResponse, error) {
|
||||||
|
return &credentialproviderapi.CredentialProviderResponse{
|
||||||
|
CacheKeyType: f.cacheKeyType,
|
||||||
|
CacheDuration: &metav1.Duration{
|
||||||
|
Duration: f.cacheDuration,
|
||||||
|
},
|
||||||
|
Auth: f.auth,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Provide(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
pluginProvider *pluginProvider
|
||||||
|
image string
|
||||||
|
dockerconfig credentialprovider.DockerConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "exact image match, with Registry cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"test.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.RegistryPluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"test.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "test.registry.io/foo/bar",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"test.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exact image match, with Image cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"test.registry.io/foo/bar"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.ImagePluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"test.registry.io/foo/bar": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "test.registry.io/foo/bar",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"test.registry.io/foo/bar": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exact image match, with Global cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"test.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.GlobalPluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"test.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "test.registry.io",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"test.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wild card image match, with Registry cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io:8080"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.RegistryPluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io:8080": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "test.registry.io:8080/foo",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io:8080": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wild card image match, with Image cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"*.*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.ImagePluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "foo.bar.registry.io/foo/bar",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"*.*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wild card image match, with Global cache key",
|
||||||
|
pluginProvider: &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.GlobalPluginCacheKeyType,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: "test.registry.io",
|
||||||
|
dockerconfig: credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
dockerconfig := testcase.pluginProvider.Provide(testcase.image)
|
||||||
|
if !reflect.DeepEqual(dockerconfig, testcase.dockerconfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerconfig)
|
||||||
|
t.Logf("expected docker config: %v", testcase.dockerconfig)
|
||||||
|
t.Error("unexpected docker config")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_encodeRequest(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
apiVersion string
|
||||||
|
request *credentialproviderapi.CredentialProviderRequest
|
||||||
|
expectedData []byte
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "successful",
|
||||||
|
request: &credentialproviderapi.CredentialProviderRequest{
|
||||||
|
Image: "test.registry.io/foobar",
|
||||||
|
},
|
||||||
|
expectedData: []byte(`{"kind":"CredentialProviderRequest","apiVersion":"credentialprovider.kubelet.k8s.io/v1alpha1","image":"test.registry.io/foobar"}
|
||||||
|
`),
|
||||||
|
expectedErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
mediaType := "application/json"
|
||||||
|
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("unsupported media type: %s", mediaType)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := &execPlugin{
|
||||||
|
encoder: codecs.EncoderForVersion(info.Serializer, credentialproviderv1alpha1.SchemeGroupVersion),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := e.encodeRequest(testcase.request)
|
||||||
|
if err != nil && !testcase.expectedErr {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && testcase.expectedErr {
|
||||||
|
t.Fatalf("expected error %v but got nil", testcase.expectedErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(data, testcase.expectedData) {
|
||||||
|
t.Errorf("actual encoded data: %v", string(data))
|
||||||
|
t.Errorf("expected encoded data: %v", string(testcase.expectedData))
|
||||||
|
t.Errorf("unexpected encoded response")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_decodeResponse(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
expectedResponse *credentialproviderapi.CredentialProviderResponse
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
data: []byte(`{"kind":"CredentialProviderResponse","apiVersion":"credentialprovider.kubelet.k8s.io/v1alpha1","cacheKeyType":"Registry","cacheDuration":"1m","auth":{"*.registry.io":{"username":"user","password":"password"}}}`),
|
||||||
|
expectedResponse: &credentialproviderapi.CredentialProviderResponse{
|
||||||
|
CacheKeyType: credentialproviderapi.RegistryPluginCacheKeyType,
|
||||||
|
CacheDuration: &metav1.Duration{
|
||||||
|
Duration: time.Minute,
|
||||||
|
},
|
||||||
|
Auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong Kind",
|
||||||
|
data: []byte(`{"kind":"WrongKind","apiVersion":"credentialprovider.kubelet.k8s.io/v1alpha1","cacheKeyType":"Registry","cacheDuration":"1m","auth":{"*.registry.io":{"username":"user","password":"password"}}}`),
|
||||||
|
expectedResponse: nil,
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong Group",
|
||||||
|
data: []byte(`{"kind":"CredentialProviderResponse","apiVersion":"foobar.kubelet.k8s.io/v1alpha1","cacheKeyType":"Registry","cacheDuration":"1m","auth":{"*.registry.io":{"username":"user","password":"password"}}}`),
|
||||||
|
expectedResponse: nil,
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
|
e := &execPlugin{}
|
||||||
|
|
||||||
|
decodedResponse, err := e.decodeResponse(testcase.data)
|
||||||
|
if err != nil && !testcase.expectedErr {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && testcase.expectedErr {
|
||||||
|
t.Fatalf("expected error %v but not nil", testcase.expectedErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(decodedResponse, testcase.expectedResponse) {
|
||||||
|
t.Logf("actual decoded response: %#v", decodedResponse)
|
||||||
|
t.Logf("expected decoded response: %#v", testcase.expectedResponse)
|
||||||
|
t.Errorf("unexpected decoded response")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_RegistryCacheKeyType(t *testing.T) {
|
||||||
|
pluginProvider := &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.RegistryPluginCacheKeyType,
|
||||||
|
cacheDuration: time.Hour,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedDockerConfig := credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerConfig := pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCacheKeys := []string{"test.registry.io"}
|
||||||
|
cacheKeys := pluginProvider.cache.ListKeys()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cacheKeys, expectedCacheKeys) {
|
||||||
|
t.Logf("actual cache keys: %v", cacheKeys)
|
||||||
|
t.Logf("expected cache keys: %v", expectedCacheKeys)
|
||||||
|
t.Error("unexpected cache keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil out the exec plugin, this will test whether credentialproviderapi are fetched
|
||||||
|
// from cache, otherwise Provider should panic
|
||||||
|
pluginProvider.plugin = nil
|
||||||
|
dockerConfig = pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ImageCacheKeyType(t *testing.T) {
|
||||||
|
pluginProvider := &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.ImagePluginCacheKeyType,
|
||||||
|
cacheDuration: time.Hour,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedDockerConfig := credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerConfig := pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCacheKeys := []string{"test.registry.io/foo/bar"}
|
||||||
|
cacheKeys := pluginProvider.cache.ListKeys()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cacheKeys, expectedCacheKeys) {
|
||||||
|
t.Logf("actual cache keys: %v", cacheKeys)
|
||||||
|
t.Logf("expected cache keys: %v", expectedCacheKeys)
|
||||||
|
t.Error("unexpected cache keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil out the exec plugin, this will test whether credentialproviderapi are fetched
|
||||||
|
// from cache, otherwise Provider should panic
|
||||||
|
pluginProvider.plugin = nil
|
||||||
|
dockerConfig = pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_GlobalCacheKeyType(t *testing.T) {
|
||||||
|
pluginProvider := &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.GlobalPluginCacheKeyType,
|
||||||
|
cacheDuration: time.Hour,
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedDockerConfig := credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerConfig := pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCacheKeys := []string{"global"}
|
||||||
|
cacheKeys := pluginProvider.cache.ListKeys()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cacheKeys, expectedCacheKeys) {
|
||||||
|
t.Logf("actual cache keys: %v", cacheKeys)
|
||||||
|
t.Logf("expected cache keys: %v", expectedCacheKeys)
|
||||||
|
t.Error("unexpected cache keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil out the exec plugin, this will test whether credentialproviderapi are fetched
|
||||||
|
// from cache, otherwise Provider should panic
|
||||||
|
pluginProvider.plugin = nil
|
||||||
|
dockerConfig = pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_NoCacheResponse(t *testing.T) {
|
||||||
|
pluginProvider := &pluginProvider{
|
||||||
|
matchImages: []string{"*.registry.io"},
|
||||||
|
cache: cache.NewExpirationStore(cacheKeyFunc, &cacheExpirationPolicy{}),
|
||||||
|
plugin: &fakeExecPlugin{
|
||||||
|
cacheKeyType: credentialproviderapi.GlobalPluginCacheKeyType,
|
||||||
|
cacheDuration: 0, // no cache
|
||||||
|
auth: map[string]credentialproviderapi.AuthConfig{
|
||||||
|
"*.registry.io": {
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedDockerConfig := credentialprovider.DockerConfig{
|
||||||
|
"*.registry.io": credentialprovider.DockerConfigEntry{
|
||||||
|
Username: "user",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerConfig := pluginProvider.Provide("test.registry.io/foo/bar")
|
||||||
|
if !reflect.DeepEqual(dockerConfig, expectedDockerConfig) {
|
||||||
|
t.Logf("actual docker config: %v", dockerConfig)
|
||||||
|
t.Logf("expected docker config: %v", expectedDockerConfig)
|
||||||
|
t.Fatal("unexpected docker config")
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCacheKeys := []string{}
|
||||||
|
cacheKeys := pluginProvider.cache.ListKeys()
|
||||||
|
if !reflect.DeepEqual(cacheKeys, expectedCacheKeys) {
|
||||||
|
t.Logf("actual cache keys: %v", cacheKeys)
|
||||||
|
t.Logf("expected cache keys: %v", expectedCacheKeys)
|
||||||
|
t.Error("unexpected cache keys")
|
||||||
|
}
|
||||||
|
}
|
@ -686,6 +686,12 @@ const (
|
|||||||
// may depend on old behavior where exec probe timeouts were ignored.
|
// may depend on old behavior where exec probe timeouts were ignored.
|
||||||
// Lock to default in v1.21 and remove in v1.22.
|
// Lock to default in v1.21 and remove in v1.22.
|
||||||
ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout"
|
ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout"
|
||||||
|
|
||||||
|
// owner: @andrewsykim
|
||||||
|
// alpha: v1.20
|
||||||
|
//
|
||||||
|
// Enable kubelet exec plugins for image pull credentials.
|
||||||
|
KubeletCredentialProviders featuregate.Feature = "KubeletCredentialProviders"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -789,6 +795,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
SizeMemoryBackedVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
SizeMemoryBackedVolumes: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
LoadBalancerIPMode: {Default: false, PreRelease: featuregate.Alpha},
|
LoadBalancerIPMode: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default in v1.21 and remove in v1.22
|
ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default in v1.21 and remove in v1.22
|
||||||
|
KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
|
||||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||||
// unintentionally on either side:
|
// unintentionally on either side:
|
||||||
|
@ -38,6 +38,7 @@ filegroup(
|
|||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//pkg/kubelet/apis/config/fuzzer:all-srcs",
|
"//pkg/kubelet/apis/config/fuzzer:all-srcs",
|
||||||
"//pkg/kubelet/apis/config/scheme:all-srcs",
|
"//pkg/kubelet/apis/config/scheme:all-srcs",
|
||||||
|
"//pkg/kubelet/apis/config/v1alpha1:all-srcs",
|
||||||
"//pkg/kubelet/apis/config/v1beta1:all-srcs",
|
"//pkg/kubelet/apis/config/v1beta1:all-srcs",
|
||||||
"//pkg/kubelet/apis/config/validation:all-srcs",
|
"//pkg/kubelet/apis/config/validation:all-srcs",
|
||||||
],
|
],
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
# See the OWNERS docs at https://go.k8s.io/owners
|
# See the OWNERS docs at https://go.k8s.io/owners
|
||||||
|
|
||||||
|
# Disable inheritance as this is an api owners file
|
||||||
|
options:
|
||||||
|
no_parent_owners: true
|
||||||
approvers:
|
approvers:
|
||||||
- mtaufen
|
- api-approvers
|
||||||
reviewers:
|
reviewers:
|
||||||
- sig-node-reviewers
|
- sig-node-api-reviewers
|
||||||
|
@ -39,6 +39,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
&KubeletConfiguration{},
|
&KubeletConfiguration{},
|
||||||
&SerializedNodeConfigSource{},
|
&SerializedNodeConfigSource{},
|
||||||
|
&CredentialProviderConfig{},
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -440,3 +440,79 @@ type SerializedNodeConfigSource struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Source v1.NodeConfigSource
|
Source v1.NodeConfigSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderConfig is the configuration containing information about
|
||||||
|
// each exec credential provider. Kubelet reads this configuration from disk and enables
|
||||||
|
// each provider as specified by the CredentialProvider type.
|
||||||
|
type CredentialProviderConfig struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
// providers is a list of credential provider plugins that will be enabled by the kubelet.
|
||||||
|
// Multiple providers may match against a single image, in which case credentials
|
||||||
|
// from all providers will be returned to the kubelet. If multiple providers are called
|
||||||
|
// for a single image, the results are combined. If providers return overlapping
|
||||||
|
// auth keys, the value from the provider earlier in this list is used.
|
||||||
|
Providers []CredentialProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialProvider represents an exec plugin to be invoked by the kubelet. The plugin is only
|
||||||
|
// invoked when an image being pulled matches the images handled by the plugin (see matchImages).
|
||||||
|
type CredentialProvider struct {
|
||||||
|
// name is the required name of the credential provider. It must match the name of the
|
||||||
|
// provider executable as seen by the kubelet. The executable must be in the kubelet's
|
||||||
|
// bin directory (set by the --credential-provider-bin-dir flag).
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// matchImages is a required list of strings used to match against images in order to
|
||||||
|
// determine if this provider should be invoked. If one of the strings matches the
|
||||||
|
// requested image from the kubelet, the plugin will be invoked and given a chance
|
||||||
|
// to provide credentials. Images are expected to contain the registry domain
|
||||||
|
// and URL path.
|
||||||
|
//
|
||||||
|
// Each entry in matchImages is a pattern which can optionally contain a port and a path.
|
||||||
|
// Globs can be used in the domain, but not in the port or the path. Globs are supported
|
||||||
|
// as subdomains like '*.k8s.io' or 'k8s.*.io', and top-level-domains such as 'k8s.*'.
|
||||||
|
// Matching partial subdomains like 'app*.k8s.io' is also supported. Each glob can only match
|
||||||
|
// a single subdomain segment, so *.io does not match *.k8s.io.
|
||||||
|
//
|
||||||
|
// A match exists between an image and a matchImage when all of the below are true:
|
||||||
|
// - Both contain the same number of domain parts and each part matches.
|
||||||
|
// - The URL path of an imageMatch must be a prefix of the target image URL path.
|
||||||
|
// - If the imageMatch contains a port, then the port must match in the image as well.
|
||||||
|
//
|
||||||
|
// Example values of matchImages:
|
||||||
|
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
|
||||||
|
// - *.azurecr.io
|
||||||
|
// - gcr.io
|
||||||
|
// - *.*.registry.io
|
||||||
|
// - registry.io:8080/path
|
||||||
|
MatchImages []string
|
||||||
|
|
||||||
|
// defaultCacheDuration is the default duration the plugin will cache credentials in-memory
|
||||||
|
// if a cache duration is not provided in the plugin response. This field is required.
|
||||||
|
DefaultCacheDuration *metav1.Duration
|
||||||
|
|
||||||
|
// Required input version of the exec CredentialProviderRequest. The returned CredentialProviderResponse
|
||||||
|
// MUST use the same encoding version as the input. Current supported values are:
|
||||||
|
// - credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
APIVersion string
|
||||||
|
|
||||||
|
// Arguments to pass to the command when executing it.
|
||||||
|
// +optional
|
||||||
|
Args []string
|
||||||
|
|
||||||
|
// Env defines additional environment variables to expose to the process. These
|
||||||
|
// are unioned with the host's environment, as well as variables client-go uses
|
||||||
|
// to pass argument to the plugin.
|
||||||
|
// +optional
|
||||||
|
Env []ExecEnvVar
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecEnvVar is used for setting environment variables when executing an exec-based
|
||||||
|
// credential plugin.
|
||||||
|
type ExecEnvVar struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
36
pkg/kubelet/apis/config/v1alpha1/BUILD
Normal file
36
pkg/kubelet/apis/config/v1alpha1/BUILD
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"register.go",
|
||||||
|
"zz_generated.conversion.go",
|
||||||
|
"zz_generated.deepcopy.go",
|
||||||
|
"zz_generated.defaults.go",
|
||||||
|
],
|
||||||
|
importpath = "k8s.io/kubernetes/pkg/kubelet/apis/config/v1alpha1",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/kubelet/apis/config:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/config/v1alpha1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
24
pkg/kubelet/apis/config/v1alpha1/doc.go
Normal file
24
pkg/kubelet/apis/config/v1alpha1/doc.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/kubelet/apis/config
|
||||||
|
// +k8s:conversion-gen-external-types=k8s.io/kubelet/config/v1alpha1
|
||||||
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
// +k8s:defaulter-gen-input=../../../../../vendor/k8s.io/kubelet/config/v1alpha1
|
||||||
|
// +groupName=kubelet.config.k8s.io
|
||||||
|
|
||||||
|
package v1alpha1 // import "k8s.io/kubernetes/pkg/kubelet/apis/config/v1alpha1"
|
36
pkg/kubelet/apis/config/v1alpha1/register.go
Normal file
36
pkg/kubelet/apis/config/v1alpha1/register.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
kubeletconfigv1alpha1 "k8s.io/kubelet/config/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupName is the group name used in this package
|
||||||
|
const GroupName = "kubelet.config.k8s.io"
|
||||||
|
|
||||||
|
// SchemeGroupVersion is group version used to register these objects
|
||||||
|
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package,
|
||||||
|
// defaulting and conversion init funcs are registered as well.
|
||||||
|
localSchemeBuilder = &kubeletconfigv1alpha1.SchemeBuilder
|
||||||
|
// AddToScheme is a global function that registers this API group & version to a scheme
|
||||||
|
AddToScheme = localSchemeBuilder.AddToScheme
|
||||||
|
)
|
143
pkg/kubelet/apis/config/v1alpha1/zz_generated.conversion.go
generated
Normal file
143
pkg/kubelet/apis/config/v1alpha1/zz_generated.conversion.go
generated
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by conversion-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
v1alpha1 "k8s.io/kubelet/config/v1alpha1"
|
||||||
|
config "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
localSchemeBuilder.Register(RegisterConversions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterConversions adds conversion functions to the given scheme.
|
||||||
|
// Public to allow building arbitrary schemes.
|
||||||
|
func RegisterConversions(s *runtime.Scheme) error {
|
||||||
|
if err := s.AddGeneratedConversionFunc((*v1alpha1.CredentialProvider)(nil), (*config.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_CredentialProvider_To_config_CredentialProvider(a.(*v1alpha1.CredentialProvider), b.(*config.CredentialProvider), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*config.CredentialProvider)(nil), (*v1alpha1.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(a.(*config.CredentialProvider), b.(*v1alpha1.CredentialProvider), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*v1alpha1.CredentialProviderConfig)(nil), (*config.CredentialProviderConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(a.(*v1alpha1.CredentialProviderConfig), b.(*config.CredentialProviderConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*config.CredentialProviderConfig)(nil), (*v1alpha1.CredentialProviderConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig(a.(*config.CredentialProviderConfig), b.(*v1alpha1.CredentialProviderConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*v1alpha1.ExecEnvVar)(nil), (*config.ExecEnvVar)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_ExecEnvVar_To_config_ExecEnvVar(a.(*v1alpha1.ExecEnvVar), b.(*config.ExecEnvVar), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*config.ExecEnvVar)(nil), (*v1alpha1.ExecEnvVar)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_config_ExecEnvVar_To_v1alpha1_ExecEnvVar(a.(*config.ExecEnvVar), b.(*v1alpha1.ExecEnvVar), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_CredentialProvider_To_config_CredentialProvider(in *v1alpha1.CredentialProvider, out *config.CredentialProvider, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
out.MatchImages = *(*[]string)(unsafe.Pointer(&in.MatchImages))
|
||||||
|
out.DefaultCacheDuration = (*v1.Duration)(unsafe.Pointer(in.DefaultCacheDuration))
|
||||||
|
out.APIVersion = in.APIVersion
|
||||||
|
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
|
||||||
|
out.Env = *(*[]config.ExecEnvVar)(unsafe.Pointer(&in.Env))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_CredentialProvider_To_config_CredentialProvider is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_CredentialProvider_To_config_CredentialProvider(in *v1alpha1.CredentialProvider, out *config.CredentialProvider, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_CredentialProvider_To_config_CredentialProvider(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in *config.CredentialProvider, out *v1alpha1.CredentialProvider, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
out.MatchImages = *(*[]string)(unsafe.Pointer(&in.MatchImages))
|
||||||
|
out.DefaultCacheDuration = (*v1.Duration)(unsafe.Pointer(in.DefaultCacheDuration))
|
||||||
|
out.APIVersion = in.APIVersion
|
||||||
|
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
|
||||||
|
out.Env = *(*[]v1alpha1.ExecEnvVar)(unsafe.Pointer(&in.Env))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider is an autogenerated conversion function.
|
||||||
|
func Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in *config.CredentialProvider, out *v1alpha1.CredentialProvider, s conversion.Scope) error {
|
||||||
|
return autoConvert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(in *v1alpha1.CredentialProviderConfig, out *config.CredentialProviderConfig, s conversion.Scope) error {
|
||||||
|
out.Providers = *(*[]config.CredentialProvider)(unsafe.Pointer(&in.Providers))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(in *v1alpha1.CredentialProviderConfig, out *config.CredentialProviderConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig(in *config.CredentialProviderConfig, out *v1alpha1.CredentialProviderConfig, s conversion.Scope) error {
|
||||||
|
out.Providers = *(*[]v1alpha1.CredentialProvider)(unsafe.Pointer(&in.Providers))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig is an autogenerated conversion function.
|
||||||
|
func Convert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig(in *config.CredentialProviderConfig, out *v1alpha1.CredentialProviderConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_ExecEnvVar_To_config_ExecEnvVar(in *v1alpha1.ExecEnvVar, out *config.ExecEnvVar, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
out.Value = in.Value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_ExecEnvVar_To_config_ExecEnvVar is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_ExecEnvVar_To_config_ExecEnvVar(in *v1alpha1.ExecEnvVar, out *config.ExecEnvVar, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_ExecEnvVar_To_config_ExecEnvVar(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_config_ExecEnvVar_To_v1alpha1_ExecEnvVar(in *config.ExecEnvVar, out *v1alpha1.ExecEnvVar, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
out.Value = in.Value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_config_ExecEnvVar_To_v1alpha1_ExecEnvVar is an autogenerated conversion function.
|
||||||
|
func Convert_config_ExecEnvVar_To_v1alpha1_ExecEnvVar(in *config.ExecEnvVar, out *v1alpha1.ExecEnvVar, s conversion.Scope) error {
|
||||||
|
return autoConvert_config_ExecEnvVar_To_v1alpha1_ExecEnvVar(in, out, s)
|
||||||
|
}
|
21
pkg/kubelet/apis/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
21
pkg/kubelet/apis/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
32
pkg/kubelet/apis/config/v1alpha1/zz_generated.defaults.go
generated
Normal file
32
pkg/kubelet/apis/config/v1alpha1/zz_generated.defaults.go
generated
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||||
|
// Public to allow building arbitrary schemes.
|
||||||
|
// All generated defaulters are covering - they call all nested defaulters.
|
||||||
|
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||||
|
return nil
|
||||||
|
}
|
85
pkg/kubelet/apis/config/zz_generated.deepcopy.go
generated
85
pkg/kubelet/apis/config/zz_generated.deepcopy.go
generated
@ -21,9 +21,94 @@ limitations under the License.
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProvider) DeepCopyInto(out *CredentialProvider) {
|
||||||
|
*out = *in
|
||||||
|
if in.MatchImages != nil {
|
||||||
|
in, out := &in.MatchImages, &out.MatchImages
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.DefaultCacheDuration != nil {
|
||||||
|
in, out := &in.DefaultCacheDuration, &out.DefaultCacheDuration
|
||||||
|
*out = new(v1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Args != nil {
|
||||||
|
in, out := &in.Args, &out.Args
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Env != nil {
|
||||||
|
in, out := &in.Env, &out.Env
|
||||||
|
*out = make([]ExecEnvVar, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProvider.
|
||||||
|
func (in *CredentialProvider) DeepCopy() *CredentialProvider {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProvider)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopyInto(out *CredentialProviderConfig) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.Providers != nil {
|
||||||
|
in, out := &in.Providers, &out.Providers
|
||||||
|
*out = make([]CredentialProvider, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderConfig.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopy() *CredentialProviderConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecEnvVar) DeepCopyInto(out *ExecEnvVar) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecEnvVar.
|
||||||
|
func (in *ExecEnvVar) DeepCopy() *ExecEnvVar {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecEnvVar)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *KubeletAnonymousAuthentication) DeepCopyInto(out *KubeletAnonymousAuthentication) {
|
func (in *KubeletAnonymousAuthentication) DeepCopyInto(out *KubeletAnonymousAuthentication) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -65,6 +65,20 @@ type ContainerRuntimeOptions struct {
|
|||||||
// CNICacheDir is the full path of the directory in which CNI should store
|
// CNICacheDir is the full path of the directory in which CNI should store
|
||||||
// cache files
|
// cache files
|
||||||
CNICacheDir string
|
CNICacheDir string
|
||||||
|
|
||||||
|
// Image credential provider plugin options
|
||||||
|
|
||||||
|
// ImageCredentialProviderConfigFile is the path to the credential provider plugin config file.
|
||||||
|
// This config file is a specification for what credential providers are enabled and invokved
|
||||||
|
// by the kubelet. The plugin config should contain information about what plugin binary
|
||||||
|
// to execute and what container images the plugin should be called for.
|
||||||
|
// +optional
|
||||||
|
ImageCredentialProviderConfigFile string
|
||||||
|
// ImageCredentialProviderBinDir is the path to the directory where credential provider plugin
|
||||||
|
// binaries exist. The name of each plugin binary is expected to match the name of the plugin
|
||||||
|
// specified in imageCredentialProviderConfigFile.
|
||||||
|
// +optional
|
||||||
|
ImageCredentialProviderBinDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFlags adds flags to the container runtime, according to ContainerRuntimeOptions.
|
// AddFlags adds flags to the container runtime, according to ContainerRuntimeOptions.
|
||||||
@ -90,4 +104,8 @@ func (s *ContainerRuntimeOptions) AddFlags(fs *pflag.FlagSet) {
|
|||||||
fs.StringVar(&s.CNIBinDir, "cni-bin-dir", s.CNIBinDir, fmt.Sprintf("A comma-separated list of full paths of directories in which to search for CNI plugin binaries. %s", dockerOnlyWarning))
|
fs.StringVar(&s.CNIBinDir, "cni-bin-dir", s.CNIBinDir, fmt.Sprintf("A comma-separated list of full paths of directories in which to search for CNI plugin binaries. %s", dockerOnlyWarning))
|
||||||
fs.StringVar(&s.CNICacheDir, "cni-cache-dir", s.CNICacheDir, fmt.Sprintf("The full path of the directory in which CNI should store cache files. %s", dockerOnlyWarning))
|
fs.StringVar(&s.CNICacheDir, "cni-cache-dir", s.CNICacheDir, fmt.Sprintf("The full path of the directory in which CNI should store cache files. %s", dockerOnlyWarning))
|
||||||
fs.Int32Var(&s.NetworkPluginMTU, "network-plugin-mtu", s.NetworkPluginMTU, fmt.Sprintf("The MTU to be passed to the network plugin, to override the default. Set to 0 to use the default 1460 MTU. %s", dockerOnlyWarning))
|
fs.Int32Var(&s.NetworkPluginMTU, "network-plugin-mtu", s.NetworkPluginMTU, fmt.Sprintf("The MTU to be passed to the network plugin, to override the default. Set to 0 to use the default 1460 MTU. %s", dockerOnlyWarning))
|
||||||
|
|
||||||
|
// Image credential provider settings.
|
||||||
|
fs.StringVar(&s.ImageCredentialProviderConfigFile, "image-credential-provider-config", s.ImageCredentialProviderConfigFile, "The path to the credential provider plugin config file.")
|
||||||
|
fs.StringVar(&s.ImageCredentialProviderBinDir, "image-credential-provider-bin-dir", s.ImageCredentialProviderBinDir, "The path to the directory where credential provider plugin binaries are located.")
|
||||||
}
|
}
|
||||||
|
@ -338,6 +338,8 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
cloudProvider string,
|
cloudProvider string,
|
||||||
certDirectory string,
|
certDirectory string,
|
||||||
rootDirectory string,
|
rootDirectory string,
|
||||||
|
imageCredentialProviderConfigFile string,
|
||||||
|
imageCredentialProviderBinDir string,
|
||||||
registerNode bool,
|
registerNode bool,
|
||||||
registerWithTaints []api.Taint,
|
registerWithTaints []api.Taint,
|
||||||
allowedUnsafeSysctls []string,
|
allowedUnsafeSysctls []string,
|
||||||
@ -600,6 +602,8 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
kubeCfg.SerializeImagePulls,
|
kubeCfg.SerializeImagePulls,
|
||||||
float32(kubeCfg.RegistryPullQPS),
|
float32(kubeCfg.RegistryPullQPS),
|
||||||
int(kubeCfg.RegistryBurst),
|
int(kubeCfg.RegistryBurst),
|
||||||
|
imageCredentialProviderConfigFile,
|
||||||
|
imageCredentialProviderBinDir,
|
||||||
kubeCfg.CPUCFSQuota,
|
kubeCfg.CPUCFSQuota,
|
||||||
kubeCfg.CPUCFSQuotaPeriod,
|
kubeCfg.CPUCFSQuotaPeriod,
|
||||||
kubeDeps.RemoteRuntimeService,
|
kubeDeps.RemoteRuntimeService,
|
||||||
|
@ -35,6 +35,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/credentialprovider:go_default_library",
|
"//pkg/credentialprovider:go_default_library",
|
||||||
|
"//pkg/credentialprovider/plugin:go_default_library",
|
||||||
"//pkg/credentialprovider/secrets:go_default_library",
|
"//pkg/credentialprovider/secrets:go_default_library",
|
||||||
"//pkg/features:go_default_library",
|
"//pkg/features:go_default_library",
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/credentialprovider"
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
|
"k8s.io/kubernetes/pkg/credentialprovider/plugin"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
@ -166,6 +167,8 @@ func NewKubeGenericRuntimeManager(
|
|||||||
serializeImagePulls bool,
|
serializeImagePulls bool,
|
||||||
imagePullQPS float32,
|
imagePullQPS float32,
|
||||||
imagePullBurst int,
|
imagePullBurst int,
|
||||||
|
imageCredentialProviderConfigFile string,
|
||||||
|
imageCredentialProviderBinDir string,
|
||||||
cpuCFSQuota bool,
|
cpuCFSQuota bool,
|
||||||
cpuCFSQuotaPeriod metav1.Duration,
|
cpuCFSQuotaPeriod metav1.Duration,
|
||||||
runtimeService internalapi.RuntimeService,
|
runtimeService internalapi.RuntimeService,
|
||||||
@ -187,7 +190,6 @@ func NewKubeGenericRuntimeManager(
|
|||||||
runtimeHelper: runtimeHelper,
|
runtimeHelper: runtimeHelper,
|
||||||
runtimeService: newInstrumentedRuntimeService(runtimeService),
|
runtimeService: newInstrumentedRuntimeService(runtimeService),
|
||||||
imageService: newInstrumentedImageManagerService(imageService),
|
imageService: newInstrumentedImageManagerService(imageService),
|
||||||
keyring: credentialprovider.NewDockerKeyring(),
|
|
||||||
internalLifecycle: internalLifecycle,
|
internalLifecycle: internalLifecycle,
|
||||||
legacyLogProvider: legacyLogProvider,
|
legacyLogProvider: legacyLogProvider,
|
||||||
logManager: logManager,
|
logManager: logManager,
|
||||||
@ -225,6 +227,18 @@ func NewKubeGenericRuntimeManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.KubeletCredentialProviders) && (imageCredentialProviderConfigFile != "" || imageCredentialProviderBinDir != "") {
|
||||||
|
klog.Warningf("Flags --image-credential-provider-config or --image-credential-provider-bin-dir were set but the feature gate %s was disabled, these flags will be ignored",
|
||||||
|
features.KubeletCredentialProviders)
|
||||||
|
}
|
||||||
|
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.KubeletCredentialProviders) && (imageCredentialProviderConfigFile != "" || imageCredentialProviderBinDir != "") {
|
||||||
|
if err := plugin.RegisterCredentialProviderPlugins(imageCredentialProviderConfigFile, imageCredentialProviderBinDir); err != nil {
|
||||||
|
klog.Fatalf("Failed to register CRI auth plugins: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kubeRuntimeManager.keyring = credentialprovider.NewDockerKeyring()
|
||||||
|
|
||||||
kubeRuntimeManager.imagePuller = images.NewImageManager(
|
kubeRuntimeManager.imagePuller = images.NewImageManager(
|
||||||
kubecontainer.FilterEventRecorder(recorder),
|
kubecontainer.FilterEventRecorder(recorder),
|
||||||
kubeRuntimeManager,
|
kubeRuntimeManager,
|
||||||
|
@ -210,6 +210,7 @@
|
|||||||
- k8s.io/apimachinery
|
- k8s.io/apimachinery
|
||||||
- k8s.io/klog
|
- k8s.io/klog
|
||||||
- k8s.io/component-base
|
- k8s.io/component-base
|
||||||
|
- k8s.io/kubelet
|
||||||
|
|
||||||
- baseImportPath: "./vendor/k8s.io/cluster-bootstrap/"
|
- baseImportPath: "./vendor/k8s.io/cluster-bootstrap/"
|
||||||
allowedImports:
|
allowedImports:
|
||||||
|
@ -9,7 +9,9 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/kubelet/config/v1alpha1:all-srcs",
|
||||||
"//staging/src/k8s.io/kubelet/config/v1beta1:all-srcs",
|
"//staging/src/k8s.io/kubelet/config/v1beta1:all-srcs",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider:all-srcs",
|
||||||
"//staging/src/k8s.io/kubelet/pkg/apis/deviceplugin/v1alpha:all-srcs",
|
"//staging/src/k8s.io/kubelet/pkg/apis/deviceplugin/v1alpha:all-srcs",
|
||||||
"//staging/src/k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1:all-srcs",
|
"//staging/src/k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1:all-srcs",
|
||||||
"//staging/src/k8s.io/kubelet/pkg/apis/pluginregistration/v1:all-srcs",
|
"//staging/src/k8s.io/kubelet/pkg/apis/pluginregistration/v1:all-srcs",
|
||||||
|
33
staging/src/k8s.io/kubelet/config/v1alpha1/BUILD
Normal file
33
staging/src/k8s.io/kubelet/config/v1alpha1/BUILD
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"register.go",
|
||||||
|
"types.go",
|
||||||
|
"zz_generated.deepcopy.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/kubelet/config/v1alpha1",
|
||||||
|
importpath = "k8s.io/kubelet/config/v1alpha1",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
21
staging/src/k8s.io/kubelet/config/v1alpha1/doc.go
Normal file
21
staging/src/k8s.io/kubelet/config/v1alpha1/doc.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
// +groupName=kubelet.config.k8s.io
|
||||||
|
|
||||||
|
package v1alpha1 // import "k8s.io/kubelet/config/v1alpha1"
|
43
staging/src/k8s.io/kubelet/config/v1alpha1/register.go
Normal file
43
staging/src/k8s.io/kubelet/config/v1alpha1/register.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupName is the group name used in this package
|
||||||
|
const GroupName = "kubelet.config.k8s.io"
|
||||||
|
|
||||||
|
// SchemeGroupVersion is group version used to register these objects
|
||||||
|
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
|
||||||
|
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||||
|
// AddToScheme is a global function that registers this API group & version to a scheme
|
||||||
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
|
)
|
||||||
|
|
||||||
|
// addKnownTypes registers known types to the given scheme
|
||||||
|
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||||
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
|
&CredentialProviderConfig{},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
97
staging/src/k8s.io/kubelet/config/v1alpha1/types.go
Normal file
97
staging/src/k8s.io/kubelet/config/v1alpha1/types.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderConfig is the configuration containing information about
|
||||||
|
// each exec credential provider. Kubelet reads this configuration from disk and enables
|
||||||
|
// each provider as specified by the CredentialProvider type.
|
||||||
|
type CredentialProviderConfig struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// providers is a list of credential provider plugins that will be enabled by the kubelet.
|
||||||
|
// Multiple providers may match against a single image, in which case credentials
|
||||||
|
// from all providers will be returned to the kubelet. If multiple providers are called
|
||||||
|
// for a single image, the results are combined. If providers return overlapping
|
||||||
|
// auth keys, the value from the provider earlier in this list is used.
|
||||||
|
Providers []CredentialProvider `json:"providers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialProvider represents an exec plugin to be invoked by the kubelet. The plugin is only
|
||||||
|
// invoked when an image being pulled matches the images handled by the plugin (see matchImages).
|
||||||
|
type CredentialProvider struct {
|
||||||
|
// name is the required name of the credential provider. It must match the name of the
|
||||||
|
// provider executable as seen by the kubelet. The executable must be in the kubelet's
|
||||||
|
// bin directory (set by the --image-credential-provider-bin-dir flag).
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// matchImages is a required list of strings used to match against images in order to
|
||||||
|
// determine if this provider should be invoked. If one of the strings matches the
|
||||||
|
// requested image from the kubelet, the plugin will be invoked and given a chance
|
||||||
|
// to provide credentials. Images are expected to contain the registry domain
|
||||||
|
// and URL path.
|
||||||
|
//
|
||||||
|
// Each entry in matchImages is a pattern which can optionally contain a port and a path.
|
||||||
|
// Globs can be used in the domain, but not in the port or the path. Globs are supported
|
||||||
|
// as subdomains like '*.k8s.io' or 'k8s.*.io', and top-level-domains such as 'k8s.*'.
|
||||||
|
// Matching partial subdomains like 'app*.k8s.io' is also supported. Each glob can only match
|
||||||
|
// a single subdomain segment, so *.io does not match *.k8s.io.
|
||||||
|
//
|
||||||
|
// A match exists between an image and a matchImage when all of the below are true:
|
||||||
|
// - Both contain the same number of domain parts and each part matches.
|
||||||
|
// - The URL path of an imageMatch must be a prefix of the target image URL path.
|
||||||
|
// - If the imageMatch contains a port, then the port must match in the image as well.
|
||||||
|
//
|
||||||
|
// Example values of matchImages:
|
||||||
|
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
|
||||||
|
// - *.azurecr.io
|
||||||
|
// - gcr.io
|
||||||
|
// - *.*.registry.io
|
||||||
|
// - registry.io:8080/path
|
||||||
|
MatchImages []string `json:"matchImages"`
|
||||||
|
|
||||||
|
// defaultCacheDuration is the default duration the plugin will cache credentials in-memory
|
||||||
|
// if a cache duration is not provided in the plugin response. This field is required.
|
||||||
|
DefaultCacheDuration *metav1.Duration `json:"defaultCacheDuration"`
|
||||||
|
|
||||||
|
// Required input version of the exec CredentialProviderRequest. The returned CredentialProviderResponse
|
||||||
|
// MUST use the same encoding version as the input. Current supported values are:
|
||||||
|
// - credentialprovider.kubelet.k8s.io/v1alpha1
|
||||||
|
APIVersion string `json:"apiVersion"`
|
||||||
|
|
||||||
|
// Arguments to pass to the command when executing it.
|
||||||
|
// +optional
|
||||||
|
Args []string `json:"args,omitempty"`
|
||||||
|
|
||||||
|
// Env defines additional environment variables to expose to the process. These
|
||||||
|
// are unioned with the host's environment, as well as variables client-go uses
|
||||||
|
// to pass argument to the plugin.
|
||||||
|
// +optional
|
||||||
|
Env []ExecEnvVar `json:"env,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecEnvVar is used for setting environment variables when executing an exec-based
|
||||||
|
// credential plugin.
|
||||||
|
type ExecEnvVar struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
110
staging/src/k8s.io/kubelet/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
110
staging/src/k8s.io/kubelet/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProvider) DeepCopyInto(out *CredentialProvider) {
|
||||||
|
*out = *in
|
||||||
|
if in.MatchImages != nil {
|
||||||
|
in, out := &in.MatchImages, &out.MatchImages
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.DefaultCacheDuration != nil {
|
||||||
|
in, out := &in.DefaultCacheDuration, &out.DefaultCacheDuration
|
||||||
|
*out = new(v1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Args != nil {
|
||||||
|
in, out := &in.Args, &out.Args
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Env != nil {
|
||||||
|
in, out := &in.Env, &out.Env
|
||||||
|
*out = make([]ExecEnvVar, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProvider.
|
||||||
|
func (in *CredentialProvider) DeepCopy() *CredentialProvider {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProvider)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopyInto(out *CredentialProviderConfig) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.Providers != nil {
|
||||||
|
in, out := &in.Providers, &out.Providers
|
||||||
|
*out = make([]CredentialProvider, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderConfig.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopy() *CredentialProviderConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderConfig) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecEnvVar) DeepCopyInto(out *ExecEnvVar) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecEnvVar.
|
||||||
|
func (in *ExecEnvVar) DeepCopy() *ExecEnvVar {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecEnvVar)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
37
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/BUILD
Normal file
37
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/BUILD
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"register.go",
|
||||||
|
"types.go",
|
||||||
|
"zz_generated.deepcopy.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/kubelet/pkg/apis/credentialprovider",
|
||||||
|
importpath = "k8s.io/kubelet/pkg/apis/credentialprovider",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/install:all-srcs",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1:all-srcs",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
@ -0,0 +1,10 @@
|
|||||||
|
# See the OWNERS docs at https://go.k8s.io/owners
|
||||||
|
|
||||||
|
# Disable inheritance as this is an api owners file
|
||||||
|
options:
|
||||||
|
no_parent_owners: true
|
||||||
|
approvers:
|
||||||
|
- api-approvers
|
||||||
|
reviewers:
|
||||||
|
- sig-node-api-reviewers
|
||||||
|
- sig-auth-api-reviewers
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +groupName=credentialprovider.kubelet.k8s.io
|
||||||
|
|
||||||
|
package credentialprovider // import "k8s.io/kubelet/pkg/apis/credentialprovider"
|
@ -0,0 +1,29 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["install.go"],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/kubelet/pkg/apis/credentialprovider/install",
|
||||||
|
importpath = "k8s.io/kubelet/pkg/apis/credentialprovider/install",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/kubelet/pkg/apis/credentialprovider"
|
||||||
|
"k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Install registers the credentialprovider.kubelet.k8s.io APIs into the given scheme.
|
||||||
|
func Install(scheme *runtime.Scheme) {
|
||||||
|
utilruntime.Must(credentialprovider.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||||
|
utilruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion))
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 credentialprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupName is the group name use in this package
|
||||||
|
const GroupName = "credentialprovider.kubelet.k8s.io"
|
||||||
|
|
||||||
|
// SchemeGroupVersion is group version used to register these objects
|
||||||
|
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||||
|
|
||||||
|
var (
|
||||||
|
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||||
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
|
)
|
||||||
|
|
||||||
|
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||||
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
|
&CredentialProviderRequest{},
|
||||||
|
&CredentialProviderResponse{},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
117
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/types.go
Normal file
117
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/types.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 credentialprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderRequest includes the image that the kubelet requires authentication for.
|
||||||
|
// Kubelet will pass this request object to the plugin via stdin. In general, plugins should
|
||||||
|
// prefer responding with the same apiVersion they were sent.
|
||||||
|
type CredentialProviderRequest struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
// image is the container image that is being pulled as part of the
|
||||||
|
// credential provider plugin request. Plugins may optionally parse the image
|
||||||
|
// to extract any information required to fetch credentials.
|
||||||
|
Image string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginCacheKeyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImagePluginCacheKeyType means the kubelet will cache credentials on a per-image basis,
|
||||||
|
// using the image passed from the kubelet directly as the cache key. This includes
|
||||||
|
// the registry domain, port (if specified), and path but does not include tags or SHAs.
|
||||||
|
ImagePluginCacheKeyType PluginCacheKeyType = "Image"
|
||||||
|
// RegistryPluginCacheKeyType means the kubelet will cache credentials on a per-registry basis.
|
||||||
|
// The cache key will be based on the registry domain and port (if present) parsed from the requested image.
|
||||||
|
RegistryPluginCacheKeyType PluginCacheKeyType = "Registry"
|
||||||
|
// GlobalPluginCacheKeyType means the kubelet will cache credentials for all images that
|
||||||
|
// match for a given plugin. This cache key should only be returned by plugins that do not use
|
||||||
|
// the image input at all.
|
||||||
|
GlobalPluginCacheKeyType PluginCacheKeyType = "Global"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderResponse holds credentials that the kubelet should use for the specified
|
||||||
|
// image provided in the original request. Kubelet will read the response from the plugin via stdout.
|
||||||
|
// This response should be set to the same apiVersion as CredentialProviderRequest.
|
||||||
|
type CredentialProviderResponse struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
// cacheKeyType indiciates the type of caching key to use based on the image provided
|
||||||
|
// in the request. There are three valid values for the cache key type: Image, Registry, and
|
||||||
|
// Global. If an invalid value is specified, the response will NOT be used by the kubelet.
|
||||||
|
CacheKeyType PluginCacheKeyType
|
||||||
|
|
||||||
|
// cacheDuration indicates the duration the provided credentials should be cached for.
|
||||||
|
// The kubelet will use this field to set the in-memory cache duration for credentials
|
||||||
|
// in the AuthConfig. If null, the kubelet will use defaultCacheDuration provided in
|
||||||
|
// CredentialProviderConfig. If set to 0, the kubelet will not cache the provided AuthConfig.
|
||||||
|
// +optional
|
||||||
|
CacheDuration *metav1.Duration
|
||||||
|
|
||||||
|
// auth is a map containing authentication information passed into the kubelet.
|
||||||
|
// Each key is a match image string (more on this below). The corresponding authConfig value
|
||||||
|
// should be valid for all images that match against this key. A plugin should set
|
||||||
|
// this field to null if no valid credentials can be returned for the requested image.
|
||||||
|
//
|
||||||
|
// Each key in the map is a pattern which can optionally contain a port and a path.
|
||||||
|
// Globs can be used in the domain, but not in the port or the path. Globs are supported
|
||||||
|
// as subdomains like '*.k8s.io' or 'k8s.*.io', and top-level-domains such as 'k8s.*'.
|
||||||
|
// Matching partial subdomains like 'app*.k8s.io' is also supported. Each glob can only match
|
||||||
|
// a single subdomain segment, so *.io does not match *.k8s.io.
|
||||||
|
//
|
||||||
|
// The kubelet will match images against the key when all of the below are true:
|
||||||
|
// - Both contain the same number of domain parts and each part matches.
|
||||||
|
// - The URL path of an imageMatch must be a prefix of the target image URL path.
|
||||||
|
// - If the imageMatch contains a port, then the port must match in the image as well.
|
||||||
|
//
|
||||||
|
// When multiple keys are returned, the kubelet will traverse all keys in reverse order so that:
|
||||||
|
// - longer keys come before shorter keys with the same prefix
|
||||||
|
// - non-wildcard keys come before wildcard keys with the same prefix.
|
||||||
|
//
|
||||||
|
// For any given match, the kubelet will attempt an image pull with the provided credentials,
|
||||||
|
// stopping after the first successfully authenticated pull.
|
||||||
|
//
|
||||||
|
// Example keys:
|
||||||
|
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
|
||||||
|
// - *.azurecr.io
|
||||||
|
// - gcr.io
|
||||||
|
// - *.*.registry.io
|
||||||
|
// - registry.io:8080/path
|
||||||
|
// +optional
|
||||||
|
Auth map[string]AuthConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthConfig contains authentication information for a container registry.
|
||||||
|
// Only username/password based authentication is supported today, but more authentication
|
||||||
|
// mechanisms may be added in the future.
|
||||||
|
type AuthConfig struct {
|
||||||
|
// username is the username used for authenticating to the container registry
|
||||||
|
// An empty username is valid.
|
||||||
|
Username string
|
||||||
|
|
||||||
|
// password is the password used for authenticating to the container registry
|
||||||
|
// An empty password is valid.
|
||||||
|
Password string
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"register.go",
|
||||||
|
"types.go",
|
||||||
|
"zz_generated.conversion.go",
|
||||||
|
"zz_generated.deepcopy.go",
|
||||||
|
"zz_generated.defaults.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1",
|
||||||
|
importpath = "k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
|
"//staging/src/k8s.io/kubelet/pkg/apis/credentialprovider:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:conversion-gen=k8s.io/kubelet/pkg/apis/credentialprovider
|
||||||
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
// +groupName=credentialprovider.kubelet.k8s.io
|
||||||
|
|
||||||
|
package v1alpha1 // import "k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupName is the group name use in this package
|
||||||
|
const GroupName = "credentialprovider.kubelet.k8s.io"
|
||||||
|
|
||||||
|
// SchemeGroupVersion is group version used to register these objects
|
||||||
|
var (
|
||||||
|
SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||||
|
localSchemeBuilder = &SchemeBuilder
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||||
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
|
)
|
||||||
|
|
||||||
|
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||||
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
|
&CredentialProviderRequest{},
|
||||||
|
&CredentialProviderResponse{},
|
||||||
|
)
|
||||||
|
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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 v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderRequest includes the image that the kubelet requires authentication for.
|
||||||
|
// Kubelet will pass this request object to the plugin via stdin. In general, plugins should
|
||||||
|
// prefer responding with the same apiVersion they were sent.
|
||||||
|
type CredentialProviderRequest struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// image is the container image that is being pulled as part of the
|
||||||
|
// credential provider plugin request. Plugins may optionally parse the image
|
||||||
|
// to extract any information required to fetch credentials.
|
||||||
|
Image string `json:"image"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginCacheKeyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImagePluginCacheKeyType means the kubelet will cache credentials on a per-image basis,
|
||||||
|
// using the image passed from the kubelet directly as the cache key. This includes
|
||||||
|
// the registry domain, port (if specified), and path but does not include tags or SHAs.
|
||||||
|
ImagePluginCacheKeyType PluginCacheKeyType = "Image"
|
||||||
|
// RegistryPluginCacheKeyType means the kubelet will cache credentials on a per-registry basis.
|
||||||
|
// The cache key will be based on the registry domain and port (if present) parsed from the requested image.
|
||||||
|
RegistryPluginCacheKeyType PluginCacheKeyType = "Registry"
|
||||||
|
// GlobalPluginCacheKeyType means the kubelet will cache credentials for all images that
|
||||||
|
// match for a given plugin. This cache key should only be returned by plugins that do not use
|
||||||
|
// the image input at all.
|
||||||
|
GlobalPluginCacheKeyType PluginCacheKeyType = "Global"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// CredentialProviderResponse holds credentials that the kubelet should use for the specified
|
||||||
|
// image provided in the original request. Kubelet will read the response from the plugin via stdout.
|
||||||
|
// This response should be set to the same apiVersion as CredentialProviderRequest.
|
||||||
|
type CredentialProviderResponse struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// cacheKeyType indiciates the type of caching key to use based on the image provided
|
||||||
|
// in the request. There are three valid values for the cache key type: Image, Registry, and
|
||||||
|
// Global. If an invalid value is specified, the response will NOT be used by the kubelet.
|
||||||
|
CacheKeyType PluginCacheKeyType `json:"cacheKeyType"`
|
||||||
|
|
||||||
|
// cacheDuration indicates the duration the provided credentials should be cached for.
|
||||||
|
// The kubelet will use this field to set the in-memory cache duration for credentials
|
||||||
|
// in the AuthConfig. If null, the kubelet will use defaultCacheDuration provided in
|
||||||
|
// CredentialProviderConfig. If set to 0, the kubelet will not cache the provided AuthConfig.
|
||||||
|
// +optional
|
||||||
|
CacheDuration *metav1.Duration `json:"cacheDuration,omitempty"`
|
||||||
|
|
||||||
|
// auth is a map containing authentication information passed into the kubelet.
|
||||||
|
// Each key is a match image string (more on this below). The corresponding authConfig value
|
||||||
|
// should be valid for all images that match against this key. A plugin should set
|
||||||
|
// this field to null if no valid credentials can be returned for the requested image.
|
||||||
|
//
|
||||||
|
// Each key in the map is a pattern which can optionally contain a port and a path.
|
||||||
|
// Globs can be used in the domain, but not in the port or the path. Globs are supported
|
||||||
|
// as subdomains like '*.k8s.io' or 'k8s.*.io', and top-level-domains such as 'k8s.*'.
|
||||||
|
// Matching partial subdomains like 'app*.k8s.io' is also supported. Each glob can only match
|
||||||
|
// a single subdomain segment, so *.io does not match *.k8s.io.
|
||||||
|
//
|
||||||
|
// The kubelet will match images against the key when all of the below are true:
|
||||||
|
// - Both contain the same number of domain parts and each part matches.
|
||||||
|
// - The URL path of an imageMatch must be a prefix of the target image URL path.
|
||||||
|
// - If the imageMatch contains a port, then the port must match in the image as well.
|
||||||
|
//
|
||||||
|
// When multiple keys are returned, the kubelet will traverse all keys in reverse order so that:
|
||||||
|
// - longer keys come before shorter keys with the same prefix
|
||||||
|
// - non-wildcard keys come before wildcard keys with the same prefix.
|
||||||
|
//
|
||||||
|
// For any given match, the kubelet will attempt an image pull with the provided credentials,
|
||||||
|
// stopping after the first successfully authenticated pull.
|
||||||
|
//
|
||||||
|
// Example keys:
|
||||||
|
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
|
||||||
|
// - *.azurecr.io
|
||||||
|
// - gcr.io
|
||||||
|
// - *.*.registry.io
|
||||||
|
// - registry.io:8080/path
|
||||||
|
// +optional
|
||||||
|
Auth map[string]AuthConfig `json:"auth,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthConfig contains authentication information for a container registry.
|
||||||
|
// Only username/password based authentication is supported today, but more authentication
|
||||||
|
// mechanisms may be added in the future.
|
||||||
|
type AuthConfig struct {
|
||||||
|
// username is the username used for authenticating to the container registry
|
||||||
|
// An empty username is valid.
|
||||||
|
Username string `json:"username"`
|
||||||
|
|
||||||
|
// password is the password used for authenticating to the container registry
|
||||||
|
// An empty password is valid.
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
136
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.conversion.go
generated
Normal file
136
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.conversion.go
generated
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by conversion-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
credentialprovider "k8s.io/kubelet/pkg/apis/credentialprovider"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
localSchemeBuilder.Register(RegisterConversions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterConversions adds conversion functions to the given scheme.
|
||||||
|
// Public to allow building arbitrary schemes.
|
||||||
|
func RegisterConversions(s *runtime.Scheme) error {
|
||||||
|
if err := s.AddGeneratedConversionFunc((*AuthConfig)(nil), (*credentialprovider.AuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_AuthConfig_To_credentialprovider_AuthConfig(a.(*AuthConfig), b.(*credentialprovider.AuthConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*credentialprovider.AuthConfig)(nil), (*AuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_credentialprovider_AuthConfig_To_v1alpha1_AuthConfig(a.(*credentialprovider.AuthConfig), b.(*AuthConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*CredentialProviderRequest)(nil), (*credentialprovider.CredentialProviderRequest)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_CredentialProviderRequest_To_credentialprovider_CredentialProviderRequest(a.(*CredentialProviderRequest), b.(*credentialprovider.CredentialProviderRequest), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*credentialprovider.CredentialProviderRequest)(nil), (*CredentialProviderRequest)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_credentialprovider_CredentialProviderRequest_To_v1alpha1_CredentialProviderRequest(a.(*credentialprovider.CredentialProviderRequest), b.(*CredentialProviderRequest), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*CredentialProviderResponse)(nil), (*credentialprovider.CredentialProviderResponse)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_CredentialProviderResponse_To_credentialprovider_CredentialProviderResponse(a.(*CredentialProviderResponse), b.(*credentialprovider.CredentialProviderResponse), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*credentialprovider.CredentialProviderResponse)(nil), (*CredentialProviderResponse)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_credentialprovider_CredentialProviderResponse_To_v1alpha1_CredentialProviderResponse(a.(*credentialprovider.CredentialProviderResponse), b.(*CredentialProviderResponse), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_AuthConfig_To_credentialprovider_AuthConfig(in *AuthConfig, out *credentialprovider.AuthConfig, s conversion.Scope) error {
|
||||||
|
out.Username = in.Username
|
||||||
|
out.Password = in.Password
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_AuthConfig_To_credentialprovider_AuthConfig is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_AuthConfig_To_credentialprovider_AuthConfig(in *AuthConfig, out *credentialprovider.AuthConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_AuthConfig_To_credentialprovider_AuthConfig(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_credentialprovider_AuthConfig_To_v1alpha1_AuthConfig(in *credentialprovider.AuthConfig, out *AuthConfig, s conversion.Scope) error {
|
||||||
|
out.Username = in.Username
|
||||||
|
out.Password = in.Password
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_credentialprovider_AuthConfig_To_v1alpha1_AuthConfig is an autogenerated conversion function.
|
||||||
|
func Convert_credentialprovider_AuthConfig_To_v1alpha1_AuthConfig(in *credentialprovider.AuthConfig, out *AuthConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_credentialprovider_AuthConfig_To_v1alpha1_AuthConfig(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_CredentialProviderRequest_To_credentialprovider_CredentialProviderRequest(in *CredentialProviderRequest, out *credentialprovider.CredentialProviderRequest, s conversion.Scope) error {
|
||||||
|
out.Image = in.Image
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_CredentialProviderRequest_To_credentialprovider_CredentialProviderRequest is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_CredentialProviderRequest_To_credentialprovider_CredentialProviderRequest(in *CredentialProviderRequest, out *credentialprovider.CredentialProviderRequest, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_CredentialProviderRequest_To_credentialprovider_CredentialProviderRequest(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_credentialprovider_CredentialProviderRequest_To_v1alpha1_CredentialProviderRequest(in *credentialprovider.CredentialProviderRequest, out *CredentialProviderRequest, s conversion.Scope) error {
|
||||||
|
out.Image = in.Image
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_credentialprovider_CredentialProviderRequest_To_v1alpha1_CredentialProviderRequest is an autogenerated conversion function.
|
||||||
|
func Convert_credentialprovider_CredentialProviderRequest_To_v1alpha1_CredentialProviderRequest(in *credentialprovider.CredentialProviderRequest, out *CredentialProviderRequest, s conversion.Scope) error {
|
||||||
|
return autoConvert_credentialprovider_CredentialProviderRequest_To_v1alpha1_CredentialProviderRequest(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_CredentialProviderResponse_To_credentialprovider_CredentialProviderResponse(in *CredentialProviderResponse, out *credentialprovider.CredentialProviderResponse, s conversion.Scope) error {
|
||||||
|
out.CacheKeyType = credentialprovider.PluginCacheKeyType(in.CacheKeyType)
|
||||||
|
out.CacheDuration = (*v1.Duration)(unsafe.Pointer(in.CacheDuration))
|
||||||
|
out.Auth = *(*map[string]credentialprovider.AuthConfig)(unsafe.Pointer(&in.Auth))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_CredentialProviderResponse_To_credentialprovider_CredentialProviderResponse is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_CredentialProviderResponse_To_credentialprovider_CredentialProviderResponse(in *CredentialProviderResponse, out *credentialprovider.CredentialProviderResponse, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_CredentialProviderResponse_To_credentialprovider_CredentialProviderResponse(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_credentialprovider_CredentialProviderResponse_To_v1alpha1_CredentialProviderResponse(in *credentialprovider.CredentialProviderResponse, out *CredentialProviderResponse, s conversion.Scope) error {
|
||||||
|
out.CacheKeyType = PluginCacheKeyType(in.CacheKeyType)
|
||||||
|
out.CacheDuration = (*v1.Duration)(unsafe.Pointer(in.CacheDuration))
|
||||||
|
out.Auth = *(*map[string]AuthConfig)(unsafe.Pointer(&in.Auth))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_credentialprovider_CredentialProviderResponse_To_v1alpha1_CredentialProviderResponse is an autogenerated conversion function.
|
||||||
|
func Convert_credentialprovider_CredentialProviderResponse_To_v1alpha1_CredentialProviderResponse(in *credentialprovider.CredentialProviderResponse, out *CredentialProviderResponse, s conversion.Scope) error {
|
||||||
|
return autoConvert_credentialprovider_CredentialProviderResponse_To_v1alpha1_CredentialProviderResponse(in, out, s)
|
||||||
|
}
|
104
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
104
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *AuthConfig) DeepCopyInto(out *AuthConfig) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfig.
|
||||||
|
func (in *AuthConfig) DeepCopy() *AuthConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(AuthConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopyInto(out *CredentialProviderRequest) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderRequest.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopy() *CredentialProviderRequest {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderRequest)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopyInto(out *CredentialProviderResponse) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.CacheDuration != nil {
|
||||||
|
in, out := &in.CacheDuration, &out.CacheDuration
|
||||||
|
*out = new(v1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Auth != nil {
|
||||||
|
in, out := &in.Auth, &out.Auth
|
||||||
|
*out = make(map[string]AuthConfig, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderResponse.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopy() *CredentialProviderResponse {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderResponse)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
32
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.defaults.go
generated
Normal file
32
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1/zz_generated.defaults.go
generated
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||||
|
// Public to allow building arbitrary schemes.
|
||||||
|
// All generated defaulters are covering - they call all nested defaulters.
|
||||||
|
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||||
|
return nil
|
||||||
|
}
|
104
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/zz_generated.deepcopy.go
generated
Normal file
104
staging/src/k8s.io/kubelet/pkg/apis/credentialprovider/zz_generated.deepcopy.go
generated
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package credentialprovider
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *AuthConfig) DeepCopyInto(out *AuthConfig) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfig.
|
||||||
|
func (in *AuthConfig) DeepCopy() *AuthConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(AuthConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopyInto(out *CredentialProviderRequest) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderRequest.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopy() *CredentialProviderRequest {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderRequest)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderRequest) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopyInto(out *CredentialProviderResponse) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.CacheDuration != nil {
|
||||||
|
in, out := &in.CacheDuration, &out.CacheDuration
|
||||||
|
*out = new(v1.Duration)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Auth != nil {
|
||||||
|
in, out := &in.Auth, &out.Auth
|
||||||
|
*out = make(map[string]AuthConfig, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialProviderResponse.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopy() *CredentialProviderResponse {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialProviderResponse)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *CredentialProviderResponse) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -2426,7 +2426,11 @@ k8s.io/kubectl/pkg/validation
|
|||||||
# k8s.io/kubelet v0.0.0 => ./staging/src/k8s.io/kubelet
|
# k8s.io/kubelet v0.0.0 => ./staging/src/k8s.io/kubelet
|
||||||
## explicit
|
## explicit
|
||||||
# k8s.io/kubelet => ./staging/src/k8s.io/kubelet
|
# k8s.io/kubelet => ./staging/src/k8s.io/kubelet
|
||||||
|
k8s.io/kubelet/config/v1alpha1
|
||||||
k8s.io/kubelet/config/v1beta1
|
k8s.io/kubelet/config/v1beta1
|
||||||
|
k8s.io/kubelet/pkg/apis/credentialprovider
|
||||||
|
k8s.io/kubelet/pkg/apis/credentialprovider/install
|
||||||
|
k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1
|
||||||
k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1
|
k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1
|
||||||
k8s.io/kubelet/pkg/apis/pluginregistration/v1
|
k8s.io/kubelet/pkg/apis/pluginregistration/v1
|
||||||
k8s.io/kubelet/pkg/apis/podresources/v1
|
k8s.io/kubelet/pkg/apis/podresources/v1
|
||||||
|
Loading…
Reference in New Issue
Block a user