Add TokenAttributes field to v1 CredentialProvider

Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
Anish Ramasekar
2024-10-17 11:46:24 -07:00
parent c5d4e53444
commit ba2eecca0d
11 changed files with 423 additions and 25 deletions

View File

@@ -1253,6 +1253,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"k8s.io/kubelet/config/v1.CredentialProvider": schema_k8sio_kubelet_config_v1_CredentialProvider(ref),
"k8s.io/kubelet/config/v1.CredentialProviderConfig": schema_k8sio_kubelet_config_v1_CredentialProviderConfig(ref),
"k8s.io/kubelet/config/v1.ExecEnvVar": schema_k8sio_kubelet_config_v1_ExecEnvVar(ref),
"k8s.io/kubelet/config/v1.ServiceAccountTokenAttributes": schema_k8sio_kubelet_config_v1_ServiceAccountTokenAttributes(ref),
"k8s.io/kubelet/config/v1alpha1.CredentialProvider": schema_k8sio_kubelet_config_v1alpha1_CredentialProvider(ref),
"k8s.io/kubelet/config/v1alpha1.CredentialProviderConfig": schema_k8sio_kubelet_config_v1alpha1_CredentialProviderConfig(ref),
"k8s.io/kubelet/config/v1alpha1.ExecEnvVar": schema_k8sio_kubelet_config_v1alpha1_ExecEnvVar(ref),
@@ -64169,12 +64170,18 @@ func schema_k8sio_kubelet_config_v1_CredentialProvider(ref common.ReferenceCallb
},
},
},
"tokenAttributes": {
SchemaProps: spec.SchemaProps{
Description: "tokenAttributes is the configuration for the service account token that will be passed to the plugin. The credential provider opts in to using service account tokens for image pull by setting this field. When this field is set, kubelet will generate a service account token bound to the pod for which the image is being pulled and pass to the plugin as part of CredentialProviderRequest along with other attributes required by the plugin.\n\nThe service account metadata and token attributes will be used as a dimension to cache the credentials in kubelet. The cache key is generated by combining the service account metadata (namespace, name, UID, and annotations key+value for the keys defined in serviceAccountTokenAttribute.requiredServiceAccountAnnotationKeys and serviceAccountTokenAttribute.optionalServiceAccountAnnotationKeys). The pod metadata (namespace, name, UID) that are in the service account token are not used as a dimension to cache the credentials in kubelet. This means workloads that are using the same service account could end up using the same credentials for image pull. For plugins that don't want this behavior, or plugins that operate in pass-through mode; i.e., they return the service account token as-is, they can set the credentialProviderResponse.cacheDuration to 0. This will disable the caching of credentials in kubelet and the plugin will be invoked for every image pull. This does result in token generation overhead for every image pull, but it is the only way to ensure that the credentials are not shared across pods (even if they are using the same service account).",
Ref: ref("k8s.io/kubelet/config/v1.ServiceAccountTokenAttributes"),
},
},
},
Required: []string{"name", "matchImages", "defaultCacheDuration", "apiVersion"},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/kubelet/config/v1.ExecEnvVar"},
"k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/kubelet/config/v1.ExecEnvVar", "k8s.io/kubelet/config/v1.ServiceAccountTokenAttributes"},
}
}
@@ -64250,6 +64257,75 @@ func schema_k8sio_kubelet_config_v1_ExecEnvVar(ref common.ReferenceCallback) com
}
}
func schema_k8sio_kubelet_config_v1_ServiceAccountTokenAttributes(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "ServiceAccountTokenAttributes is the configuration for the service account token that will be passed to the plugin.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"serviceAccountTokenAudience": {
SchemaProps: spec.SchemaProps{
Description: "serviceAccountTokenAudience is the intended audience for the projected service account token.",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"requireServiceAccount": {
SchemaProps: spec.SchemaProps{
Description: "requireServiceAccount indicates whether the plugin requires the pod to have a service account. If set to true, kubelet will only invoke the plugin if the pod has a service account. If set to false, kubelet will invoke the plugin even if the pod does not have a service account and will not include a token in the CredentialProviderRequest in that scenario. This is useful for plugins that are used to pull images for pods without service accounts (e.g., static pods).",
Type: []string{"boolean"},
Format: "",
},
},
"requiredServiceAccountAnnotationKeys": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-list-type": "set",
},
},
SchemaProps: spec.SchemaProps{
Description: "requiredServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in and that are required to be present in the service account. The keys defined in this list will be extracted from the corresponding service account and passed to the plugin as part of the CredentialProviderRequest. If any of the keys defined in this list are not present in the service account, kubelet will not invoke the plugin and will return an error. This field is optional and may be empty. Plugins may use this field to extract additional information required to fetch credentials or allow workloads to opt in to using service account tokens for image pull. If non-empty, requireServiceAccount must be set to true.",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
},
},
"optionalServiceAccountAnnotationKeys": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-list-type": "set",
},
},
SchemaProps: spec.SchemaProps{
Description: "optionalServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in and that are optional to be present in the service account. The keys defined in this list will be extracted from the corresponding service account and passed to the plugin as part of the CredentialProviderRequest. The plugin is responsible for validating the existence of annotations and their values. This field is optional and may be empty. Plugins may use this field to extract additional information required to fetch credentials.",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
},
},
},
Required: []string{"serviceAccountTokenAudience", "requireServiceAccount"},
},
},
}
}
func schema_k8sio_kubelet_config_v1alpha1_CredentialProvider(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@@ -127,5 +127,11 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
"AllBeta": true,
}
},
// tokenAttributes field is only supported in v1 CredentialProvider
func(obj *kubeletconfig.CredentialProvider, c randfill.Continue) {
c.FillNoCustom(obj)
obj.TokenAttributes = nil
},
}
}

View File

@@ -670,6 +670,64 @@ type CredentialProvider struct {
// to pass argument to the plugin.
// +optional
Env []ExecEnvVar
// tokenAttributes is the configuration for the service account token that will be passed to the plugin.
// The credential provider opts in to using service account tokens for image pull by setting this field.
// When this field is set, kubelet will generate a service account token bound to the pod for which the
// image is being pulled and pass to the plugin as part of CredentialProviderRequest along with other
// attributes required by the plugin.
//
// The service account metadata and token attributes will be used as a dimension to cache
// the credentials in kubelet. The cache key is generated by combining the service account metadata
// (namespace, name, UID, and annotations key+value for the keys defined in
// serviceAccountTokenAttribute.requiredServiceAccountAnnotationKeys and serviceAccountTokenAttribute.optionalServiceAccountAnnotationKeys).
// The pod metadata (namespace, name, UID) that are in the service account token are not used as a dimension
// to cache the credentials in kubelet. This means workloads that are using the same service account
// could end up using the same credentials for image pull. For plugins that don't want this behavior, or
// plugins that operate in pass-through mode; i.e., they return the service account token as-is, they
// can set the credentialProviderResponse.cacheDuration to 0. This will disable the caching of
// credentials in kubelet and the plugin will be invoked for every image pull. This does result in
// token generation overhead for every image pull, but it is the only way to ensure that the
// credentials are not shared across pods (even if they are using the same service account).
// +optional
TokenAttributes *ServiceAccountTokenAttributes
}
// ServiceAccountTokenAttributes is the configuration for the service account token that will be passed to the plugin.
type ServiceAccountTokenAttributes struct {
// serviceAccountTokenAudience is the intended audience for the projected service account token.
// +required
ServiceAccountTokenAudience string
// requireServiceAccount indicates whether the plugin requires the pod to have a service account.
// If set to true, kubelet will only invoke the plugin if the pod has a service account.
// If set to false, kubelet will invoke the plugin even if the pod does not have a service account
// and will not include a token in the CredentialProviderRequest in that scenario. This is useful for plugins that
// are used to pull images for pods without service accounts (e.g., static pods).
// +required
RequireServiceAccount *bool
// requiredServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in
// and that are required to be present in the service account.
// The keys defined in this list will be extracted from the corresponding service account and passed
// to the plugin as part of the CredentialProviderRequest. If any of the keys defined in this list
// are not present in the service account, kubelet will not invoke the plugin and will return an error.
// This field is optional and may be empty. Plugins may use this field to extract
// additional information required to fetch credentials or allow workloads to opt in to
// using service account tokens for image pull.
// If non-empty, requireServiceAccount must be set to true.
// +optional
RequiredServiceAccountAnnotationKeys []string
// optionalServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in
// and that are optional to be present in the service account.
// The keys defined in this list will be extracted from the corresponding service account and passed
// to the plugin as part of the CredentialProviderRequest. The plugin is responsible for validating
// the existence of annotations and their values.
// This field is optional and may be empty. Plugins may use this field to extract
// additional information required to fetch credentials.
// +optional
OptionalServiceAccountAnnotationKeys []string
}
// ExecEnvVar is used for setting environment variables when executing an exec-based

View File

@@ -68,6 +68,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*configv1.ServiceAccountTokenAttributes)(nil), (*config.ServiceAccountTokenAttributes)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_ServiceAccountTokenAttributes_To_config_ServiceAccountTokenAttributes(a.(*configv1.ServiceAccountTokenAttributes), b.(*config.ServiceAccountTokenAttributes), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.ServiceAccountTokenAttributes)(nil), (*configv1.ServiceAccountTokenAttributes)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_ServiceAccountTokenAttributes_To_v1_ServiceAccountTokenAttributes(a.(*config.ServiceAccountTokenAttributes), b.(*configv1.ServiceAccountTokenAttributes), scope)
}); err != nil {
return err
}
return nil
}
@@ -78,6 +88,7 @@ func autoConvert_v1_CredentialProvider_To_config_CredentialProvider(in *configv1
out.APIVersion = in.APIVersion
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
out.Env = *(*[]config.ExecEnvVar)(unsafe.Pointer(&in.Env))
out.TokenAttributes = (*config.ServiceAccountTokenAttributes)(unsafe.Pointer(in.TokenAttributes))
return nil
}
@@ -93,6 +104,7 @@ func autoConvert_config_CredentialProvider_To_v1_CredentialProvider(in *config.C
out.APIVersion = in.APIVersion
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
out.Env = *(*[]configv1.ExecEnvVar)(unsafe.Pointer(&in.Env))
out.TokenAttributes = (*configv1.ServiceAccountTokenAttributes)(unsafe.Pointer(in.TokenAttributes))
return nil
}
@@ -142,3 +154,29 @@ func autoConvert_config_ExecEnvVar_To_v1_ExecEnvVar(in *config.ExecEnvVar, out *
func Convert_config_ExecEnvVar_To_v1_ExecEnvVar(in *config.ExecEnvVar, out *configv1.ExecEnvVar, s conversion.Scope) error {
return autoConvert_config_ExecEnvVar_To_v1_ExecEnvVar(in, out, s)
}
func autoConvert_v1_ServiceAccountTokenAttributes_To_config_ServiceAccountTokenAttributes(in *configv1.ServiceAccountTokenAttributes, out *config.ServiceAccountTokenAttributes, s conversion.Scope) error {
out.ServiceAccountTokenAudience = in.ServiceAccountTokenAudience
out.RequireServiceAccount = (*bool)(unsafe.Pointer(in.RequireServiceAccount))
out.RequiredServiceAccountAnnotationKeys = *(*[]string)(unsafe.Pointer(&in.RequiredServiceAccountAnnotationKeys))
out.OptionalServiceAccountAnnotationKeys = *(*[]string)(unsafe.Pointer(&in.OptionalServiceAccountAnnotationKeys))
return nil
}
// Convert_v1_ServiceAccountTokenAttributes_To_config_ServiceAccountTokenAttributes is an autogenerated conversion function.
func Convert_v1_ServiceAccountTokenAttributes_To_config_ServiceAccountTokenAttributes(in *configv1.ServiceAccountTokenAttributes, out *config.ServiceAccountTokenAttributes, s conversion.Scope) error {
return autoConvert_v1_ServiceAccountTokenAttributes_To_config_ServiceAccountTokenAttributes(in, out, s)
}
func autoConvert_config_ServiceAccountTokenAttributes_To_v1_ServiceAccountTokenAttributes(in *config.ServiceAccountTokenAttributes, out *configv1.ServiceAccountTokenAttributes, s conversion.Scope) error {
out.ServiceAccountTokenAudience = in.ServiceAccountTokenAudience
out.RequireServiceAccount = (*bool)(unsafe.Pointer(in.RequireServiceAccount))
out.RequiredServiceAccountAnnotationKeys = *(*[]string)(unsafe.Pointer(&in.RequiredServiceAccountAnnotationKeys))
out.OptionalServiceAccountAnnotationKeys = *(*[]string)(unsafe.Pointer(&in.OptionalServiceAccountAnnotationKeys))
return nil
}
// Convert_config_ServiceAccountTokenAttributes_To_v1_ServiceAccountTokenAttributes is an autogenerated conversion function.
func Convert_config_ServiceAccountTokenAttributes_To_v1_ServiceAccountTokenAttributes(in *config.ServiceAccountTokenAttributes, out *configv1.ServiceAccountTokenAttributes, s conversion.Scope) error {
return autoConvert_config_ServiceAccountTokenAttributes_To_v1_ServiceAccountTokenAttributes(in, out, s)
}

View File

@@ -0,0 +1,28 @@
/*
Copyright 2025 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/conversion"
configv1alpha1 "k8s.io/kubelet/config/v1alpha1"
"k8s.io/kubernetes/pkg/kubelet/apis/config"
)
func Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in *config.CredentialProvider, out *configv1alpha1.CredentialProvider, s conversion.Scope) error {
// This conversion intentionally omits the tokenAttributes field which is only supported in v1 CredentialProvider.
return autoConvert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in, out, s)
}

View File

@@ -43,11 +43,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CredentialProvider)(nil), (*configv1alpha1.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(a.(*config.CredentialProvider), b.(*configv1alpha1.CredentialProvider), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*configv1alpha1.CredentialProviderConfig)(nil), (*config.CredentialProviderConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(a.(*configv1alpha1.CredentialProviderConfig), b.(*config.CredentialProviderConfig), scope)
}); err != nil {
@@ -68,6 +63,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.CredentialProvider)(nil), (*configv1alpha1.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(a.(*config.CredentialProvider), b.(*configv1alpha1.CredentialProvider), scope)
}); err != nil {
return err
}
return nil
}
@@ -93,16 +93,22 @@ func autoConvert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in *co
out.APIVersion = in.APIVersion
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
out.Env = *(*[]configv1alpha1.ExecEnvVar)(unsafe.Pointer(&in.Env))
// WARNING: in.TokenAttributes requires manual conversion: does not exist in peer-type
return nil
}
// Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider is an autogenerated conversion function.
func Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in *config.CredentialProvider, out *configv1alpha1.CredentialProvider, s conversion.Scope) error {
return autoConvert_config_CredentialProvider_To_v1alpha1_CredentialProvider(in, out, s)
}
func autoConvert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfig(in *configv1alpha1.CredentialProviderConfig, out *config.CredentialProviderConfig, s conversion.Scope) error {
out.Providers = *(*[]config.CredentialProvider)(unsafe.Pointer(&in.Providers))
if in.Providers != nil {
in, out := &in.Providers, &out.Providers
*out = make([]config.CredentialProvider, len(*in))
for i := range *in {
if err := Convert_v1alpha1_CredentialProvider_To_config_CredentialProvider(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Providers = nil
}
return nil
}
@@ -112,7 +118,17 @@ func Convert_v1alpha1_CredentialProviderConfig_To_config_CredentialProviderConfi
}
func autoConvert_config_CredentialProviderConfig_To_v1alpha1_CredentialProviderConfig(in *config.CredentialProviderConfig, out *configv1alpha1.CredentialProviderConfig, s conversion.Scope) error {
out.Providers = *(*[]configv1alpha1.CredentialProvider)(unsafe.Pointer(&in.Providers))
if in.Providers != nil {
in, out := &in.Providers, &out.Providers
*out = make([]configv1alpha1.CredentialProvider, len(*in))
for i := range *in {
if err := Convert_config_CredentialProvider_To_v1alpha1_CredentialProvider(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Providers = nil
}
return nil
}

View File

@@ -0,0 +1,28 @@
/*
Copyright 2025 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 v1beta1
import (
"k8s.io/apimachinery/pkg/conversion"
configv1beta1 "k8s.io/kubelet/config/v1beta1"
"k8s.io/kubernetes/pkg/kubelet/apis/config"
)
func Convert_config_CredentialProvider_To_v1beta1_CredentialProvider(in *config.CredentialProvider, out *configv1beta1.CredentialProvider, s conversion.Scope) error {
// This conversion intentionally omits the tokenAttributes field which is only supported in v1 CredentialProvider.
return autoConvert_config_CredentialProvider_To_v1beta1_CredentialProvider(in, out, s)
}

View File

@@ -55,11 +55,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.CredentialProvider)(nil), (*configv1beta1.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CredentialProvider_To_v1beta1_CredentialProvider(a.(*config.CredentialProvider), b.(*configv1beta1.CredentialProvider), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*configv1beta1.CredentialProviderConfig)(nil), (*config.CredentialProviderConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_CredentialProviderConfig_To_config_CredentialProviderConfig(a.(*configv1beta1.CredentialProviderConfig), b.(*config.CredentialProviderConfig), scope)
}); err != nil {
@@ -190,6 +185,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.CredentialProvider)(nil), (*configv1beta1.CredentialProvider)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_CredentialProvider_To_v1beta1_CredentialProvider(a.(*config.CredentialProvider), b.(*configv1beta1.CredentialProvider), scope)
}); err != nil {
return err
}
return nil
}
@@ -235,16 +235,22 @@ func autoConvert_config_CredentialProvider_To_v1beta1_CredentialProvider(in *con
out.APIVersion = in.APIVersion
out.Args = *(*[]string)(unsafe.Pointer(&in.Args))
out.Env = *(*[]configv1beta1.ExecEnvVar)(unsafe.Pointer(&in.Env))
// WARNING: in.TokenAttributes requires manual conversion: does not exist in peer-type
return nil
}
// Convert_config_CredentialProvider_To_v1beta1_CredentialProvider is an autogenerated conversion function.
func Convert_config_CredentialProvider_To_v1beta1_CredentialProvider(in *config.CredentialProvider, out *configv1beta1.CredentialProvider, s conversion.Scope) error {
return autoConvert_config_CredentialProvider_To_v1beta1_CredentialProvider(in, out, s)
}
func autoConvert_v1beta1_CredentialProviderConfig_To_config_CredentialProviderConfig(in *configv1beta1.CredentialProviderConfig, out *config.CredentialProviderConfig, s conversion.Scope) error {
out.Providers = *(*[]config.CredentialProvider)(unsafe.Pointer(&in.Providers))
if in.Providers != nil {
in, out := &in.Providers, &out.Providers
*out = make([]config.CredentialProvider, len(*in))
for i := range *in {
if err := Convert_v1beta1_CredentialProvider_To_config_CredentialProvider(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Providers = nil
}
return nil
}
@@ -254,7 +260,17 @@ func Convert_v1beta1_CredentialProviderConfig_To_config_CredentialProviderConfig
}
func autoConvert_config_CredentialProviderConfig_To_v1beta1_CredentialProviderConfig(in *config.CredentialProviderConfig, out *configv1beta1.CredentialProviderConfig, s conversion.Scope) error {
out.Providers = *(*[]configv1beta1.CredentialProvider)(unsafe.Pointer(&in.Providers))
if in.Providers != nil {
in, out := &in.Providers, &out.Providers
*out = make([]configv1beta1.CredentialProvider, len(*in))
for i := range *in {
if err := Convert_config_CredentialProvider_To_v1beta1_CredentialProvider(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Providers = nil
}
return nil
}

View File

@@ -72,6 +72,11 @@ func (in *CredentialProvider) DeepCopyInto(out *CredentialProvider) {
*out = make([]ExecEnvVar, len(*in))
copy(*out, *in)
}
if in.TokenAttributes != nil {
in, out := &in.TokenAttributes, &out.TokenAttributes
*out = new(ServiceAccountTokenAttributes)
(*in).DeepCopyInto(*out)
}
return
}
@@ -491,6 +496,37 @@ func (in *SerializedNodeConfigSource) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceAccountTokenAttributes) DeepCopyInto(out *ServiceAccountTokenAttributes) {
*out = *in
if in.RequireServiceAccount != nil {
in, out := &in.RequireServiceAccount, &out.RequireServiceAccount
*out = new(bool)
**out = **in
}
if in.RequiredServiceAccountAnnotationKeys != nil {
in, out := &in.RequiredServiceAccountAnnotationKeys, &out.RequiredServiceAccountAnnotationKeys
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.OptionalServiceAccountAnnotationKeys != nil {
in, out := &in.OptionalServiceAccountAnnotationKeys, &out.OptionalServiceAccountAnnotationKeys
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountTokenAttributes.
func (in *ServiceAccountTokenAttributes) DeepCopy() *ServiceAccountTokenAttributes {
if in == nil {
return nil
}
out := new(ServiceAccountTokenAttributes)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ShutdownGracePeriodByPodPriority) DeepCopyInto(out *ShutdownGracePeriodByPodPriority) {
*out = *in

View File

@@ -88,6 +88,66 @@ type CredentialProvider struct {
// to pass argument to the plugin.
// +optional
Env []ExecEnvVar `json:"env,omitempty"`
// tokenAttributes is the configuration for the service account token that will be passed to the plugin.
// The credential provider opts in to using service account tokens for image pull by setting this field.
// When this field is set, kubelet will generate a service account token bound to the pod for which the
// image is being pulled and pass to the plugin as part of CredentialProviderRequest along with other
// attributes required by the plugin.
//
// The service account metadata and token attributes will be used as a dimension to cache
// the credentials in kubelet. The cache key is generated by combining the service account metadata
// (namespace, name, UID, and annotations key+value for the keys defined in
// serviceAccountTokenAttribute.requiredServiceAccountAnnotationKeys and serviceAccountTokenAttribute.optionalServiceAccountAnnotationKeys).
// The pod metadata (namespace, name, UID) that are in the service account token are not used as a dimension
// to cache the credentials in kubelet. This means workloads that are using the same service account
// could end up using the same credentials for image pull. For plugins that don't want this behavior, or
// plugins that operate in pass-through mode; i.e., they return the service account token as-is, they
// can set the credentialProviderResponse.cacheDuration to 0. This will disable the caching of
// credentials in kubelet and the plugin will be invoked for every image pull. This does result in
// token generation overhead for every image pull, but it is the only way to ensure that the
// credentials are not shared across pods (even if they are using the same service account).
// +optional
TokenAttributes *ServiceAccountTokenAttributes `json:"tokenAttributes,omitempty"`
}
// ServiceAccountTokenAttributes is the configuration for the service account token that will be passed to the plugin.
type ServiceAccountTokenAttributes struct {
// serviceAccountTokenAudience is the intended audience for the projected service account token.
// +required
ServiceAccountTokenAudience string `json:"serviceAccountTokenAudience"`
// requireServiceAccount indicates whether the plugin requires the pod to have a service account.
// If set to true, kubelet will only invoke the plugin if the pod has a service account.
// If set to false, kubelet will invoke the plugin even if the pod does not have a service account
// and will not include a token in the CredentialProviderRequest in that scenario. This is useful for plugins that
// are used to pull images for pods without service accounts (e.g., static pods).
// +required
RequireServiceAccount *bool `json:"requireServiceAccount"`
// requiredServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in
// and that are required to be present in the service account.
// The keys defined in this list will be extracted from the corresponding service account and passed
// to the plugin as part of the CredentialProviderRequest. If any of the keys defined in this list
// are not present in the service account, kubelet will not invoke the plugin and will return an error.
// This field is optional and may be empty. Plugins may use this field to extract
// additional information required to fetch credentials or allow workloads to opt in to
// using service account tokens for image pull.
// If non-empty, requireServiceAccount must be set to true.
// +optional
// +listType=set
RequiredServiceAccountAnnotationKeys []string `json:"requiredServiceAccountAnnotationKeys,omitempty"`
// optionalServiceAccountAnnotationKeys is the list of annotation keys that the plugin is interested in
// and that are optional to be present in the service account.
// The keys defined in this list will be extracted from the corresponding service account and passed
// to the plugin as part of the CredentialProviderRequest. The plugin is responsible for validating
// the existence of annotations and their values.
// This field is optional and may be empty. Plugins may use this field to extract
// additional information required to fetch credentials.
// +optional
// +listType=set
OptionalServiceAccountAnnotationKeys []string `json:"optionalServiceAccountAnnotationKeys,omitempty"`
}
// ExecEnvVar is used for setting environment variables when executing an exec-based

View File

@@ -49,6 +49,11 @@ func (in *CredentialProvider) DeepCopyInto(out *CredentialProvider) {
*out = make([]ExecEnvVar, len(*in))
copy(*out, *in)
}
if in.TokenAttributes != nil {
in, out := &in.TokenAttributes, &out.TokenAttributes
*out = new(ServiceAccountTokenAttributes)
(*in).DeepCopyInto(*out)
}
return
}
@@ -109,3 +114,34 @@ func (in *ExecEnvVar) DeepCopy() *ExecEnvVar {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceAccountTokenAttributes) DeepCopyInto(out *ServiceAccountTokenAttributes) {
*out = *in
if in.RequireServiceAccount != nil {
in, out := &in.RequireServiceAccount, &out.RequireServiceAccount
*out = new(bool)
**out = **in
}
if in.RequiredServiceAccountAnnotationKeys != nil {
in, out := &in.RequiredServiceAccountAnnotationKeys, &out.RequiredServiceAccountAnnotationKeys
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.OptionalServiceAccountAnnotationKeys != nil {
in, out := &in.OptionalServiceAccountAnnotationKeys, &out.OptionalServiceAccountAnnotationKeys
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountTokenAttributes.
func (in *ServiceAccountTokenAttributes) DeepCopy() *ServiceAccountTokenAttributes {
if in == nil {
return nil
}
out := new(ServiceAccountTokenAttributes)
in.DeepCopyInto(out)
return out
}