Skip to content

Commit d6be19f

Browse files
joshfrenchadammw
andcommitted
Add Access Entry support
Co-authored-by: Adam Malcontenti-Wilson <amalcontenti-wilson@zendesk.com>
1 parent f3c2166 commit d6be19f

17 files changed

+2053
-0
lines changed

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,6 +2292,85 @@ spec:
22922292
ignored when updating existing clusters. Defaults to true.
22932293
type: boolean
22942294
type: object
2295+
accessEntries:
2296+
description: |-
2297+
AccessEntries specifies the access entries for the cluster
2298+
Access entries require AuthenticationMode to be either "api" or "api_and_config_map"
2299+
items:
2300+
description: AccessEntry represents an AWS EKS access entry for
2301+
IAM principals
2302+
properties:
2303+
accessPolicies:
2304+
description: |-
2305+
AccessPolicies specifies the policies to associate with this access entry
2306+
Cannot be specified if Type is "ec2_linux" or "ec2_windows"
2307+
items:
2308+
description: AccessPolicyReference represents a reference
2309+
to an AWS EKS access policy
2310+
properties:
2311+
accessScope:
2312+
description: AccessScope specifies the scope for the policy
2313+
properties:
2314+
namespaces:
2315+
description: |-
2316+
Namespaces are the namespaces for the access scope
2317+
Only valid when Type is namespace
2318+
items:
2319+
type: string
2320+
minItems: 1
2321+
type: array
2322+
type:
2323+
default: cluster
2324+
description: Type is the type of access scope. Defaults
2325+
to "cluster".
2326+
enum:
2327+
- cluster
2328+
- namespace
2329+
type: string
2330+
required:
2331+
- type
2332+
type: object
2333+
policyARN:
2334+
description: PolicyARN is the Amazon Resource Name (ARN)
2335+
of the access policy
2336+
type: string
2337+
required:
2338+
- accessScope
2339+
- policyARN
2340+
type: object
2341+
maxItems: 20
2342+
type: array
2343+
kubernetesGroups:
2344+
description: |-
2345+
KubernetesGroups represents the Kubernetes groups for the access entry
2346+
Cannot be specified if Type is "ec2_linux" or "ec2_windows"
2347+
items:
2348+
type: string
2349+
type: array
2350+
principalARN:
2351+
description: PrincipalARN is the Amazon Resource Name (ARN)
2352+
of the IAM principal
2353+
type: string
2354+
type:
2355+
default: standard
2356+
description: Type is the type of access entry. Defaults to standard
2357+
if not specified.
2358+
enum:
2359+
- standard
2360+
- ec2_linux
2361+
- ec2_windows
2362+
- fargate_linux
2363+
- ec2
2364+
- hybrid_linux
2365+
- hyperpod_linux
2366+
type: string
2367+
username:
2368+
description: Username is the username for the access entry
2369+
type: string
2370+
required:
2371+
- principalARN
2372+
type: object
2373+
type: array
22952374
additionalTags:
22962375
additionalProperties:
22972376
type: string

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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,87 @@ spec:
7575
ignored when updating existing clusters. Defaults to true.
7676
type: boolean
7777
type: object
78+
accessEntries:
79+
description: |-
80+
AccessEntries specifies the access entries for the cluster
81+
Access entries require AuthenticationMode to be either "api" or "api_and_config_map"
82+
items:
83+
description: AccessEntry represents an AWS EKS access entry
84+
for IAM principals
85+
properties:
86+
accessPolicies:
87+
description: |-
88+
AccessPolicies specifies the policies to associate with this access entry
89+
Cannot be specified if Type is "ec2_linux" or "ec2_windows"
90+
items:
91+
description: AccessPolicyReference represents a reference
92+
to an AWS EKS access policy
93+
properties:
94+
accessScope:
95+
description: AccessScope specifies the scope for
96+
the policy
97+
properties:
98+
namespaces:
99+
description: |-
100+
Namespaces are the namespaces for the access scope
101+
Only valid when Type is namespace
102+
items:
103+
type: string
104+
minItems: 1
105+
type: array
106+
type:
107+
default: cluster
108+
description: Type is the type of access scope.
109+
Defaults to "cluster".
110+
enum:
111+
- cluster
112+
- namespace
113+
type: string
114+
required:
115+
- type
116+
type: object
117+
policyARN:
118+
description: PolicyARN is the Amazon Resource
119+
Name (ARN) of the access policy
120+
type: string
121+
required:
122+
- accessScope
123+
- policyARN
124+
type: object
125+
maxItems: 20
126+
type: array
127+
kubernetesGroups:
128+
description: |-
129+
KubernetesGroups represents the Kubernetes groups for the access entry
130+
Cannot be specified if Type is "ec2_linux" or "ec2_windows"
131+
items:
132+
type: string
133+
type: array
134+
principalARN:
135+
description: PrincipalARN is the Amazon Resource Name
136+
(ARN) of the IAM principal
137+
type: string
138+
type:
139+
default: standard
140+
description: Type is the type of access entry. Defaults
141+
to standard if not specified.
142+
enum:
143+
- standard
144+
- ec2_linux
145+
- ec2_windows
146+
- fargate_linux
147+
- ec2
148+
- hybrid_linux
149+
- hyperpod_linux
150+
type: string
151+
username:
152+
description: Username is the username for the access
153+
entry
154+
type: string
155+
required:
156+
- principalARN
157+
type: object
158+
type: array
78159
additionalTags:
79160
additionalProperties:
80161
type: string

controlplane/eks/api/v1beta1/conversion.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
118118
dst.Spec.Partition = restored.Spec.Partition
119119
dst.Spec.RestrictPrivateSubnets = restored.Spec.RestrictPrivateSubnets
120120
dst.Spec.AccessConfig = restored.Spec.AccessConfig
121+
dst.Spec.AccessEntries = restored.Spec.AccessEntries
121122
dst.Spec.RolePath = restored.Spec.RolePath
122123
dst.Spec.RolePermissionsBoundary = restored.Spec.RolePermissionsBoundary
123124
dst.Status.Version = restored.Status.Version

controlplane/eks/api/v1beta1/zz_generated.conversion.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned
196196
// +optional
197197
AccessConfig *AccessConfig `json:"accessConfig,omitempty"`
198198

199+
// AccessEntries specifies the access entries for the cluster
200+
// Access entries require AuthenticationMode to be either "api" or "api_and_config_map"
201+
// +optional
202+
AccessEntries []AccessEntry `json:"accessEntries,omitempty"`
203+
199204
// VpcCni is used to set configuration options for the VPC CNI plugin
200205
// +optional
201206
VpcCni VpcCni `json:"vpcCni,omitempty"`
@@ -267,6 +272,59 @@ type AccessConfig struct {
267272
BootstrapClusterCreatorAdminPermissions *bool `json:"bootstrapClusterCreatorAdminPermissions,omitempty"`
268273
}
269274

275+
// AccessEntry represents an AWS EKS access entry for IAM principals
276+
type AccessEntry struct {
277+
// PrincipalARN is the Amazon Resource Name (ARN) of the IAM principal
278+
// +kubebuilder:validation:Required
279+
PrincipalARN string `json:"principalARN"`
280+
281+
// Type is the type of access entry. Defaults to standard if not specified.
282+
// +kubebuilder:default=standard
283+
// +kubebuilder:validation:Enum=standard;ec2_linux;ec2_windows;fargate_linux;ec2;hybrid_linux;hyperpod_linux
284+
// +optional
285+
Type AccessEntryType `json:"type,omitempty"`
286+
287+
// KubernetesGroups represents the Kubernetes groups for the access entry
288+
// Cannot be specified if Type is "ec2_linux" or "ec2_windows"
289+
// +optional
290+
KubernetesGroups []string `json:"kubernetesGroups,omitempty"`
291+
292+
// Username is the username for the access entry
293+
// +optional
294+
Username string `json:"username,omitempty"`
295+
296+
// AccessPolicies specifies the policies to associate with this access entry
297+
// Cannot be specified if Type is "ec2_linux" or "ec2_windows"
298+
// +optional
299+
// +kubebuilder:validation:MaxItems=20
300+
AccessPolicies []AccessPolicyReference `json:"accessPolicies,omitempty"`
301+
}
302+
303+
// AccessPolicyReference represents a reference to an AWS EKS access policy
304+
type AccessPolicyReference struct {
305+
// PolicyARN is the Amazon Resource Name (ARN) of the access policy
306+
// +kubebuilder:validation:Required
307+
PolicyARN string `json:"policyARN"`
308+
309+
// AccessScope specifies the scope for the policy
310+
// +kubebuilder:validation:Required
311+
AccessScope AccessScope `json:"accessScope"`
312+
}
313+
314+
// AccessScope represents the scope for an access policy
315+
type AccessScope struct {
316+
// Type is the type of access scope. Defaults to "cluster".
317+
// +kubebuilder:validation:Enum=cluster;namespace
318+
// +kubebuilder:default=cluster
319+
Type AccessScopeType `json:"type"`
320+
321+
// Namespaces are the namespaces for the access scope
322+
// Only valid when Type is namespace
323+
// +optional
324+
// +kubebuilder:validation:MinItems=1
325+
Namespaces []string `json:"namespaces,omitempty"`
326+
}
327+
270328
// EncryptionConfig specifies the encryption configuration for the EKS clsuter.
271329
type EncryptionConfig struct {
272330
// Provider specifies the ARN or alias of the CMK (in AWS KMS)

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ func (*awsManagedControlPlaneWebhook) ValidateCreate(_ context.Context, obj runt
108108
allErrs = append(allErrs, r.validateNetwork()...)
109109
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
110110
allErrs = append(allErrs, r.validateAccessConfigCreate()...)
111+
allErrs = append(allErrs, r.validateAccessEntries()...)
111112

112113
if len(allErrs) == 0 {
113114
return nil, nil
@@ -150,6 +151,7 @@ func (*awsManagedControlPlaneWebhook) ValidateUpdate(ctx context.Context, oldObj
150151
allErrs = append(allErrs, r.validateKubeProxy()...)
151152
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
152153
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
154+
allErrs = append(allErrs, r.validateAccessEntries()...)
153155

154156
if r.Spec.Region != oldAWSManagedControlplane.Spec.Region {
155157
allErrs = append(allErrs,
@@ -367,6 +369,61 @@ func (r *AWSManagedControlPlane) validateAccessConfigCreate() field.ErrorList {
367369
return allErrs
368370
}
369371

372+
func (r *AWSManagedControlPlane) validateAccessEntries() field.ErrorList {
373+
var allErrs field.ErrorList
374+
375+
if len(r.Spec.AccessEntries) > 0 {
376+
// AccessEntries require AuthenticationMode to be api or api_and_config_map
377+
if r.Spec.AccessConfig == nil ||
378+
(r.Spec.AccessConfig.AuthenticationMode != EKSAuthenticationModeAPI &&
379+
r.Spec.AccessConfig.AuthenticationMode != EKSAuthenticationModeAPIAndConfigMap) {
380+
allErrs = append(allErrs,
381+
field.Invalid(field.NewPath("spec", "accessEntries"),
382+
r.Spec.AccessEntries,
383+
"accessEntries can only be used when authenticationMode is set to api or api_and_config_map",
384+
),
385+
)
386+
}
387+
388+
for i, entry := range r.Spec.AccessEntries {
389+
// Validate that EC2 types don't have kubernetes groups or access policies
390+
if entry.Type == AccessEntryTypeEC2Linux || entry.Type == AccessEntryTypeEC2Windows {
391+
if len(entry.KubernetesGroups) > 0 {
392+
allErrs = append(allErrs,
393+
field.Invalid(field.NewPath("spec", "accessEntries").Index(i).Child("kubernetesGroups"),
394+
entry.KubernetesGroups,
395+
"kubernetesGroups cannot be specified when type is ec2_linux or ec2_windows",
396+
),
397+
)
398+
}
399+
400+
if len(entry.AccessPolicies) > 0 {
401+
allErrs = append(allErrs,
402+
field.Invalid(field.NewPath("spec", "accessEntries").Index(i).Child("accessPolicies"),
403+
entry.AccessPolicies,
404+
"accessPolicies cannot be specified when type is ec2_linux or ec2_windows",
405+
),
406+
)
407+
}
408+
}
409+
410+
// Validate namespace scopes
411+
for j, policy := range entry.AccessPolicies {
412+
if policy.AccessScope.Type == AccessScopeTypeNamespace && len(policy.AccessScope.Namespaces) == 0 {
413+
allErrs = append(allErrs,
414+
field.Invalid(field.NewPath("spec", "accessEntries").Index(i).Child("accessPolicies").Index(j).Child("accessScope", "namespaces"),
415+
policy.AccessScope.Namespaces,
416+
"at least one value must be provided when accessScope type is namespace",
417+
),
418+
)
419+
}
420+
}
421+
}
422+
}
423+
424+
return allErrs
425+
}
426+
370427
func (r *AWSManagedControlPlane) validateIAMAuthConfig() field.ErrorList {
371428
return validateIAMAuthConfig(r.Spec.IAMAuthenticatorConfig, field.NewPath("spec.iamAuthenticatorConfig"))
372429
}

0 commit comments

Comments
 (0)