Skip to content

Commit e0ab1a1

Browse files
authored
Merge pull request kubernetes#128372 from aramase/aramase/f/kep_4412_alpha_impl
KSA token for Kubelet image credential providers alpha
2 parents 0b00454 + 2090a01 commit e0ab1a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2619
-491
lines changed

pkg/credentialprovider/plugin/config.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import (
2222
"strings"
2323

2424
"k8s.io/apimachinery/pkg/util/sets"
25+
"k8s.io/apimachinery/pkg/util/validation"
2526
"k8s.io/apimachinery/pkg/util/validation/field"
27+
credentialproviderv1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1"
2628
"k8s.io/kubernetes/pkg/credentialprovider"
2729
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
2830
)
@@ -70,7 +72,7 @@ func decode(data []byte) (*kubeletconfig.CredentialProviderConfig, error) {
7072
}
7173

7274
// validateCredentialProviderConfig validates CredentialProviderConfig.
73-
func validateCredentialProviderConfig(config *kubeletconfig.CredentialProviderConfig) field.ErrorList {
75+
func validateCredentialProviderConfig(config *kubeletconfig.CredentialProviderConfig, saTokenForCredentialProviders bool) field.ErrorList {
7476
allErrs := field.ErrorList{}
7577

7678
if len(config.Providers) == 0 {
@@ -125,7 +127,56 @@ func validateCredentialProviderConfig(config *kubeletconfig.CredentialProviderCo
125127
if provider.DefaultCacheDuration != nil && provider.DefaultCacheDuration.Duration < 0 {
126128
allErrs = append(allErrs, field.Invalid(fieldPath.Child("defaultCacheDuration"), provider.DefaultCacheDuration.Duration, "defaultCacheDuration must be greater than or equal to 0"))
127129
}
130+
131+
if provider.TokenAttributes != nil {
132+
fldPath := fieldPath.Child("tokenAttributes")
133+
if !saTokenForCredentialProviders {
134+
allErrs = append(allErrs, field.Forbidden(fldPath, "tokenAttributes is not supported when KubeletServiceAccountTokenForCredentialProviders feature gate is disabled"))
135+
}
136+
if len(provider.TokenAttributes.ServiceAccountTokenAudience) == 0 {
137+
allErrs = append(allErrs, field.Required(fldPath.Child("serviceAccountTokenAudience"), "serviceAccountTokenAudience is required"))
138+
}
139+
if provider.TokenAttributes.RequireServiceAccount == nil {
140+
allErrs = append(allErrs, field.Required(fldPath.Child("requireServiceAccount"), "requireServiceAccount is required"))
141+
}
142+
if provider.APIVersion != credentialproviderv1.SchemeGroupVersion.String() {
143+
allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("tokenAttributes is only supported for %s API version", credentialproviderv1.SchemeGroupVersion.String())))
144+
}
145+
146+
if provider.TokenAttributes.RequireServiceAccount != nil && !*provider.TokenAttributes.RequireServiceAccount && len(provider.TokenAttributes.RequiredServiceAccountAnnotationKeys) > 0 {
147+
allErrs = append(allErrs, field.Forbidden(fldPath.Child("requiredServiceAccountAnnotationKeys"), "requireServiceAccount cannot be false when requiredServiceAccountAnnotationKeys is set"))
148+
}
149+
150+
allErrs = append(allErrs, validateServiceAccountAnnotationKeys(fldPath.Child("requiredServiceAccountAnnotationKeys"), provider.TokenAttributes.RequiredServiceAccountAnnotationKeys)...)
151+
allErrs = append(allErrs, validateServiceAccountAnnotationKeys(fldPath.Child("optionalServiceAccountAnnotationKeys"), provider.TokenAttributes.OptionalServiceAccountAnnotationKeys)...)
152+
153+
requiredServiceAccountAnnotationKeys := sets.New[string](provider.TokenAttributes.RequiredServiceAccountAnnotationKeys...)
154+
optionalServiceAccountAnnotationKeys := sets.New[string](provider.TokenAttributes.OptionalServiceAccountAnnotationKeys...)
155+
duplicateAnnotationKeys := requiredServiceAccountAnnotationKeys.Intersection(optionalServiceAccountAnnotationKeys)
156+
if duplicateAnnotationKeys.Len() > 0 {
157+
allErrs = append(allErrs, field.Invalid(fldPath, sets.List(duplicateAnnotationKeys), "annotation keys cannot be both required and optional"))
158+
}
159+
}
128160
}
129161

130162
return allErrs
131163
}
164+
165+
// validateServiceAccountAnnotationKeys validates the service account annotation keys.
166+
func validateServiceAccountAnnotationKeys(fldPath *field.Path, keys []string) field.ErrorList {
167+
allErrs := field.ErrorList{}
168+
169+
seenAnnotationKeys := sets.New[string]()
170+
// Using the validation logic for keys from https://github.com/kubernetes/kubernetes/blob/69dbc74417304328a9fd3c161643dc4f0a057f41/staging/src/k8s.io/apimachinery/pkg/api/validation/objectmeta.go#L46-L51
171+
for _, k := range keys {
172+
// The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking.
173+
for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
174+
allErrs = append(allErrs, field.Invalid(fldPath, k, msg))
175+
}
176+
if seenAnnotationKeys.Has(k) {
177+
allErrs = append(allErrs, field.Duplicate(fldPath, k))
178+
}
179+
seenAnnotationKeys.Insert(k)
180+
}
181+
return allErrs
182+
}

0 commit comments

Comments
 (0)