Skip to content

Commit f93c3c8

Browse files
stefanmcshanek0da
authored andcommitted
Add eks pod identities
Signed-off-by: Danil Grigorev <[email protected]>
1 parent d790693 commit f93c3c8

20 files changed

+786
-1
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,6 +3173,36 @@ spec:
31733173
description: Partition is the AWS security partition being used. Defaults
31743174
to "aws"
31753175
type: string
3176+
podIdentityAssociations:
3177+
description: |-
3178+
PodIdentityAssociations represent Kubernetes Service Accounts mapping to AWS IAM Roles without IRSA, using EKS Pod Identity.
3179+
This requires using the AWS EKS Addon for Pod Identity.
3180+
items:
3181+
description: PodIdentityAssociation represents an association between
3182+
a Kubernetes Service Account in a namespace, and an AWS IAM role
3183+
which allows the service principal `pods.eks.amazonaws.com` in
3184+
its trust policy.
3185+
properties:
3186+
roleARN:
3187+
description: RoleARN is the ARN of an IAM role which the Service
3188+
Account can assume.
3189+
type: string
3190+
serviceAccountName:
3191+
description: ServiceAccountName is the name of the kubernetes
3192+
Service Account within the namespace
3193+
type: string
3194+
serviceAccountNamespace:
3195+
default: default
3196+
description: ServiceAccountNamespace is the kubernetes namespace,
3197+
which the kubernetes Service Account resides in. Defaults
3198+
to "default" namespace.
3199+
type: string
3200+
required:
3201+
- roleARN
3202+
- serviceAccountName
3203+
- serviceAccountNamespace
3204+
type: object
3205+
type: array
31763206
region:
31773207
description: The AWS Region the cluster lives in.
31783208
type: string

controlplane/eks/api/v1beta1/conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
123123
dst.Status.Version = restored.Status.Version
124124
dst.Spec.BootstrapSelfManagedAddons = restored.Spec.BootstrapSelfManagedAddons
125125
dst.Spec.UpgradePolicy = restored.Spec.UpgradePolicy
126+
dst.Spec.PodIdentityAssociations = restored.Spec.PodIdentityAssociations
127+
126128
return nil
127129
}
128130

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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned
187187
// +optional
188188
Addons *[]Addon `json:"addons,omitempty"`
189189

190+
// PodIdentityAssociations represent Kubernetes Service Accounts mapping to AWS IAM Roles without IRSA, using EKS Pod Identity.
191+
// This requires using the AWS EKS Addon for Pod Identity.
192+
// +optional
193+
PodIdentityAssociations []PodIdentityAssociation `json:"podIdentityAssociations,omitempty"`
194+
190195
// IdentityProviderconfig is used to specify the oidc provider config
191196
// to be attached with this eks cluster
192197
// +optional

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/pkg/errors"
2626
apierrors "k8s.io/apimachinery/pkg/api/errors"
2727
"k8s.io/apimachinery/pkg/runtime"
28+
"k8s.io/apimachinery/pkg/util/validation"
2829
"k8s.io/apimachinery/pkg/util/validation/field"
2930
"k8s.io/apimachinery/pkg/util/version"
3031
"k8s.io/klog/v2"
@@ -108,6 +109,7 @@ func (*awsManagedControlPlaneWebhook) ValidateCreate(_ context.Context, obj runt
108109
allErrs = append(allErrs, r.validateNetwork()...)
109110
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
110111
allErrs = append(allErrs, r.validateAccessConfigCreate()...)
112+
allErrs = append(allErrs, r.validServiceAccountName()...)
111113

112114
if len(allErrs) == 0 {
113115
return nil, nil
@@ -150,6 +152,7 @@ func (*awsManagedControlPlaneWebhook) ValidateUpdate(ctx context.Context, oldObj
150152
allErrs = append(allErrs, r.validateKubeProxy()...)
151153
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
152154
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
155+
allErrs = append(allErrs, r.validServiceAccountName()...)
153156

154157
if r.Spec.Region != oldAWSManagedControlplane.Spec.Region {
155158
allErrs = append(allErrs,
@@ -507,6 +510,28 @@ func validatePrivateDNSHostnameTypeOnLaunch(networkSpec infrav1.NetworkSpec, pat
507510
return allErrs
508511
}
509512

513+
func (r *AWSManagedControlPlane) validServiceAccountName() field.ErrorList {
514+
var allErrs field.ErrorList
515+
516+
if r.Spec.PodIdentityAssociations != nil {
517+
for i, association := range r.Spec.PodIdentityAssociations {
518+
associationPath := field.NewPath("spec", "podIdentityAssociations").Index(i)
519+
if association.ServiceAccountName == "" {
520+
allErrs = append(allErrs, field.Required(associationPath.Child("serviceAccountName"), "serviceAccountName is required"))
521+
}
522+
523+
// kubernetes uses ValidateServiceAccountName internally, which maps to IsDNS1123Subdomain
524+
// https://github.com/kubernetes/apimachinery/blob/d794766488ac2892197a7cc8d0b4b46b0edbda80/pkg/api/validation/generic.go#L68
525+
526+
if validationErrs := validation.IsDNS1123Subdomain(association.ServiceAccountName); len(validationErrs) > 0 {
527+
allErrs = append(allErrs, field.Invalid(associationPath.Child("serviceAccountName"), association.ServiceAccountName, fmt.Sprintf("serviceAccountName is invalid: %v", validationErrs)))
528+
}
529+
}
530+
}
531+
532+
return allErrs
533+
}
534+
510535
func (r *AWSManagedControlPlane) validateNetwork() field.ErrorList {
511536
return validateNetwork("AWSManagedControlPlane", r.Spec.NetworkSpec, r.Spec.SecondaryCidrBlock, field.NewPath("spec"))
512537
}

controlplane/eks/api/v1beta2/conditions_consts.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ const (
5252
EKSAddonsConfiguredFailedReason = "EKSAddonsConfiguredFailed"
5353
)
5454

55+
const (
56+
// EKSPodIdentityAssociationConfiguredCondition condition reports on the successful reconciliation of EKS pod identity associations.
57+
EKSPodIdentityAssociationConfiguredCondition clusterv1.ConditionType = "EKSPodIdentityAssociationConfigured"
58+
// EKSPodIdentityAssociationFailedReason is used to report failures while reconciling the EKS pod identity associations.
59+
EKSPodIdentityAssociationFailedReason = "EKSPodIdentityAssociationConfigurationFailed"
60+
)
61+
5562
const (
5663
// EKSIdentityProviderConfiguredCondition condition reports on the successful association of identity provider config.
5764
EKSIdentityProviderConfiguredCondition clusterv1.ConditionType = "EKSIdentityProviderConfigured"

controlplane/eks/api/v1beta2/types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,17 @@ type OIDCIdentityProviderConfig struct {
326326
// +optional
327327
Tags infrav1.Tags `json:"tags,omitempty"`
328328
}
329+
330+
// PodIdentityAssociation represents an association between a Kubernetes Service Account in a namespace, and an AWS IAM role which allows the service principal `pods.eks.amazonaws.com` in its trust policy.
331+
type PodIdentityAssociation struct {
332+
// ServiceAccountName is the name of the kubernetes Service Account within the namespace
333+
// +kubebuilder:validation:Required
334+
ServiceAccountName string `json:"serviceAccountName"`
335+
// ServiceAccountNamespace is the kubernetes namespace, which the kubernetes Service Account resides in. Defaults to "default" namespace.
336+
// +kubebuilder:validation:Required
337+
// +kubebuilder:default=default
338+
ServiceAccountNamespace string `json:"serviceAccountNamespace"`
339+
// RoleARN is the ARN of an IAM role which the Service Account can assume.
340+
// +kubebuilder:validation:Required
341+
RoleARN string `json:"roleARN,omitempty"`
342+
}

controlplane/eks/api/v1beta2/zz_generated.deepcopy.go

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

controlplane/eks/controllers/awsmanagedcontrolplane_controller_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,11 @@ func mockedEKSCluster(ctx context.Context, g *WithT, eksRec *mock_eksiface.MockE
973973
}).Return(&eks.ListAddonsOutput{}, nil)
974974

975975
eksRec.UpdateClusterConfig(ctx, gomock.AssignableToTypeOf(&eks.UpdateClusterConfigInput{})).After(waitUntilClusterActiveCall).Return(&eks.UpdateClusterConfigOutput{}, nil)
976+
eksRec.ListPodIdentityAssociations(context.TODO(), gomock.Eq(&eks.ListPodIdentityAssociationsInput{
977+
ClusterName: aws.String("test-cluster"),
978+
})).Return(&eks.ListPodIdentityAssociationsOutput{
979+
Associations: []ekstypes.PodIdentityAssociationSummary{},
980+
}, nil)
976981

977982
awsNodeRec.ReconcileCNI(gomock.Any()).Return(nil)
978983
kubeProxyRec.ReconcileKubeProxy(gomock.Any()).Return(nil)

docs/book/src/SUMMARY_PREFIX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [Creating a cluster](./topics/eks/creating-a-cluster.md)
2121
- [Using EKS Console](./topics/eks/eks-console.md)
2222
- [Using EKS Addons](./topics/eks/addons.md)
23+
- [Using EKS Pod Identity Associations](./topics/eks/pod-identity-associations.md)
2324
- [Enabling Encryption](./topics/eks/encryption.md)
2425
- [Cluster Upgrades](./topics/eks/cluster-upgrades.md)
2526
- [ROSA Support](./topics/rosa/index.md)

0 commit comments

Comments
 (0)