Skip to content

Commit 464f490

Browse files
committed
Tests for AccessEntry validations
1 parent 28cd9a3 commit 464f490

File tree

4 files changed

+168
-3
lines changed

4 files changed

+168
-3
lines changed

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,7 @@ spec:
22702270
Only valid when Type is namespace
22712271
items:
22722272
type: string
2273+
minItems: 1
22732274
type: array
22742275
type:
22752276
default: cluster
@@ -2290,6 +2291,7 @@ spec:
22902291
- accessScope
22912292
- policyARN
22922293
type: object
2294+
maxItems: 20
22932295
type: array
22942296
kubernetesGroups:
22952297
description: |-

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ type AccessEntry struct {
276276
// AccessPolicies specifies the policies to associate with this access entry
277277
// Cannot be specified if Type is EC2_LINUX or EC2_WINDOWS
278278
// +optional
279+
// +kubebuilder:validation:MaxItems=20
279280
AccessPolicies []AccessPolicyReference `json:"accessPolicies,omitempty"`
280281
}
281282

@@ -300,6 +301,7 @@ type AccessScope struct {
300301
// Namespaces are the namespaces for the access scope
301302
// Only valid when Type is namespace
302303
// +optional
304+
// +kubebuilder:validation:MinItems=1
303305
Namespaces []string `json:"namespaces,omitempty"`
304306
}
305307

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func (*awsManagedControlPlaneWebhook) ValidateCreate(_ context.Context, obj runt
9898
// TODO: Add ipv6 validation things in these validations.
9999
allErrs = append(allErrs, r.validateEKSVersion(nil)...)
100100
allErrs = append(allErrs, r.Spec.Bastion.Validate()...)
101+
allErrs = append(allErrs, r.validateAccessConfig(nil)...)
101102
allErrs = append(allErrs, r.validateIAMAuthConfig()...)
102103
allErrs = append(allErrs, r.validateSecondaryCIDR()...)
103104
allErrs = append(allErrs, r.validateEKSAddons()...)
@@ -324,14 +325,14 @@ func (r *AWSManagedControlPlane) validateAccessConfig(old *AWSManagedControlPlan
324325
var allErrs field.ErrorList
325326

326327
// If accessConfig is already set, do not allow removal of it.
327-
if old.Spec.AccessConfig != nil && r.Spec.AccessConfig == nil {
328+
if old != nil && old.Spec.AccessConfig != nil && r.Spec.AccessConfig == nil {
328329
allErrs = append(allErrs,
329330
field.Invalid(field.NewPath("spec", "accessConfig"), r.Spec.AccessConfig, "removing AccessConfig is not allowed after it has been enabled"),
330331
)
331332
}
332333

333334
// AuthenticationMode is ratcheting - do not allow downgrades
334-
if old.Spec.AccessConfig != nil && r.Spec.AccessConfig != nil &&
335+
if old != nil && old.Spec.AccessConfig != nil && r.Spec.AccessConfig != nil &&
335336
old.Spec.AccessConfig.AuthenticationMode != r.Spec.AccessConfig.AuthenticationMode &&
336337
((old.Spec.AccessConfig.AuthenticationMode == EKSAuthenticationModeAPIAndConfigMap && r.Spec.AccessConfig.AuthenticationMode == EKSAuthenticationModeConfigMap) ||
337338
old.Spec.AccessConfig.AuthenticationMode == EKSAuthenticationModeAPI) {
@@ -389,7 +390,7 @@ func (r *AWSManagedControlPlane) validateAccessConfig(old *AWSManagedControlPlan
389390
field.Invalid(
390391
field.NewPath("spec", "accessConfig", "accessEntries").Index(i).Child("accessPolicies").Index(j).Child("accessScope", "namespaces"),
391392
policy.AccessScope.Namespaces,
392-
"at least one value must be specified when accessScope type is namespace",
393+
"at least one value must be provided when accessScope type is namespace",
393394
),
394395
)
395396
}

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook_test.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,166 @@ func TestWebhookCreateIPv6Details(t *testing.T) {
526526
}
527527
}
528528

529+
func TestWebhookValidateAccessEntries(t *testing.T) {
530+
tests := []struct {
531+
name string
532+
accessConfig *AccessConfig
533+
expectError bool
534+
errorSubstr string
535+
}{
536+
{
537+
name: "valid access entries with API auth mode",
538+
accessConfig: &AccessConfig{
539+
AuthenticationMode: EKSAuthenticationModeAPI,
540+
AccessEntries: []AccessEntry{
541+
{
542+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
543+
Type: "STANDARD",
544+
KubernetesGroups: []string{"system:masters"},
545+
},
546+
},
547+
},
548+
expectError: false,
549+
},
550+
{
551+
name: "valid access entries with API_AND_CONFIG_MAP auth mode",
552+
accessConfig: &AccessConfig{
553+
AuthenticationMode: EKSAuthenticationModeAPIAndConfigMap,
554+
AccessEntries: []AccessEntry{
555+
{
556+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
557+
Type: "STANDARD",
558+
KubernetesGroups: []string{"system:masters"},
559+
},
560+
},
561+
},
562+
expectError: false,
563+
},
564+
{
565+
name: "invalid access entries with CONFIG_MAP auth mode",
566+
accessConfig: &AccessConfig{
567+
AuthenticationMode: EKSAuthenticationModeConfigMap,
568+
AccessEntries: []AccessEntry{
569+
{
570+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
571+
Type: "STANDARD",
572+
KubernetesGroups: []string{"system:masters"},
573+
},
574+
},
575+
},
576+
expectError: true,
577+
errorSubstr: "accessEntries can only be used when authenticationMode is set to API or API_AND_CONFIG_MAP",
578+
},
579+
{
580+
name: "invalid EC2_LINUX access entry with kubernetes groups",
581+
accessConfig: &AccessConfig{
582+
AuthenticationMode: EKSAuthenticationModeAPI,
583+
AccessEntries: []AccessEntry{
584+
{
585+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
586+
Type: "EC2_LINUX",
587+
KubernetesGroups: []string{"system:masters"},
588+
},
589+
},
590+
},
591+
expectError: true,
592+
errorSubstr: "kubernetesGroups cannot be specified when type is EC2_LINUX or EC2_WINDOWS",
593+
},
594+
{
595+
name: "invalid EC2_WINDOWS access entry with access policies",
596+
accessConfig: &AccessConfig{
597+
AuthenticationMode: EKSAuthenticationModeAPI,
598+
AccessEntries: []AccessEntry{
599+
{
600+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
601+
Type: "EC2_WINDOWS",
602+
AccessPolicies: []AccessPolicyReference{
603+
{
604+
PolicyARN: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy",
605+
AccessScope: AccessScope{
606+
Type: "cluster",
607+
},
608+
},
609+
},
610+
},
611+
},
612+
},
613+
expectError: true,
614+
errorSubstr: "accessPolicies cannot be specified when type is EC2_LINUX or EC2_WINDOWS",
615+
},
616+
{
617+
name: "invalid access policy with namespace type and no namespaces",
618+
accessConfig: &AccessConfig{
619+
AuthenticationMode: EKSAuthenticationModeAPI,
620+
AccessEntries: []AccessEntry{
621+
{
622+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
623+
Type: "STANDARD",
624+
AccessPolicies: []AccessPolicyReference{
625+
{
626+
PolicyARN: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy",
627+
AccessScope: AccessScope{
628+
Type: "namespace",
629+
},
630+
},
631+
},
632+
},
633+
},
634+
},
635+
expectError: true,
636+
errorSubstr: "at least one value must be provided when accessScope type is namespace",
637+
},
638+
{
639+
name: "valid access policy with namespace type and namespaces",
640+
accessConfig: &AccessConfig{
641+
AuthenticationMode: EKSAuthenticationModeAPI,
642+
AccessEntries: []AccessEntry{
643+
{
644+
PrincipalARN: "arn:aws:iam::123456789012:role/EKSAdmin",
645+
Type: "STANDARD",
646+
AccessPolicies: []AccessPolicyReference{
647+
{
648+
PolicyARN: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy",
649+
AccessScope: AccessScope{
650+
Type: "namespace",
651+
Namespaces: []string{"default", "kube-system"},
652+
},
653+
},
654+
},
655+
},
656+
},
657+
},
658+
expectError: false,
659+
},
660+
}
661+
662+
for _, tc := range tests {
663+
t.Run(tc.name, func(t *testing.T) {
664+
g := NewWithT(t)
665+
666+
mcp := &AWSManagedControlPlane{
667+
Spec: AWSManagedControlPlaneSpec{
668+
EKSClusterName: "default_cluster1",
669+
AccessConfig: tc.accessConfig,
670+
},
671+
}
672+
673+
warn, err := (&awsManagedControlPlaneWebhook{}).ValidateCreate(context.Background(), mcp)
674+
675+
if tc.expectError {
676+
g.Expect(err).ToNot(BeNil())
677+
if tc.errorSubstr != "" {
678+
g.Expect(err.Error()).To(ContainSubstring(tc.errorSubstr))
679+
}
680+
} else {
681+
g.Expect(err).To(BeNil())
682+
}
683+
// Nothing emits warnings yet
684+
g.Expect(warn).To(BeEmpty())
685+
})
686+
}
687+
}
688+
529689
func TestWebhookUpdate(t *testing.T) {
530690
tests := []struct {
531691
name string

0 commit comments

Comments
 (0)