Skip to content

Commit aadab40

Browse files
stefanmcshanek0da
authored andcommitted
Add eks pod identities
Signed-off-by: Danil Grigorev <danil.grigorev@suse.com>
1 parent 840b657 commit aadab40

20 files changed

+811
-7
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
@@ -3116,6 +3116,36 @@ spec:
31163116
description: Partition is the AWS security partition being used. Defaults
31173117
to "aws"
31183118
type: string
3119+
podIdentityAssociations:
3120+
description: |-
3121+
PodIdentityAssociations represent Kubernetes Service Accounts mapping to AWS IAM Roles without IRSA, using EKS Pod Identity.
3122+
This requires using the AWS EKS Addon for Pod Identity.
3123+
items:
3124+
description: PodIdentityAssociation represents an association between
3125+
a Kubernetes Service Account in a namespace, and an AWS IAM role
3126+
which allows the service principal `pods.eks.amazonaws.com` in
3127+
its trust policy.
3128+
properties:
3129+
roleARN:
3130+
description: RoleARN is the ARN of an IAM role which the Service
3131+
Account can assume.
3132+
type: string
3133+
serviceAccountName:
3134+
description: ServiceAccountName is the name of the kubernetes
3135+
Service Account within the namespace
3136+
type: string
3137+
serviceAccountNamespace:
3138+
default: default
3139+
description: ServiceAccountNamespace is the kubernetes namespace,
3140+
which the kubernetes Service Account resides in. Defaults
3141+
to "default" namespace.
3142+
type: string
3143+
required:
3144+
- roleARN
3145+
- serviceAccountName
3146+
- serviceAccountNamespace
3147+
type: object
3148+
type: array
31193149
region:
31203150
description: The AWS Region the cluster lives in.
31213151
type: string

controlplane/eks/api/v1beta1/conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
121121
dst.Spec.RolePermissionsBoundary = restored.Spec.RolePermissionsBoundary
122122
dst.Status.Version = restored.Status.Version
123123
dst.Spec.BootstrapSelfManagedAddons = restored.Spec.BootstrapSelfManagedAddons
124+
dst.Spec.PodIdentityAssociations = restored.Spec.PodIdentityAssociations
125+
124126
return nil
125127
}
126128

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"
@@ -107,6 +108,7 @@ func (*awsManagedControlPlaneWebhook) ValidateCreate(_ context.Context, obj runt
107108
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
108109
allErrs = append(allErrs, r.validateNetwork()...)
109110
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
111+
allErrs = append(allErrs, r.validServiceAccountName()...)
110112

111113
if len(allErrs) == 0 {
112114
return nil, nil
@@ -148,6 +150,7 @@ func (*awsManagedControlPlaneWebhook) ValidateUpdate(ctx context.Context, oldObj
148150
allErrs = append(allErrs, r.validateKubeProxy()...)
149151
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
150152
allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...)
153+
allErrs = append(allErrs, r.validServiceAccountName()...)
151154

152155
if r.Spec.Region != oldAWSManagedControlplane.Spec.Region {
153156
allErrs = append(allErrs,
@@ -458,6 +461,28 @@ func validatePrivateDNSHostnameTypeOnLaunch(networkSpec infrav1.NetworkSpec, pat
458461
return allErrs
459462
}
460463

464+
func (r *AWSManagedControlPlane) validServiceAccountName() field.ErrorList {
465+
var allErrs field.ErrorList
466+
467+
if r.Spec.PodIdentityAssociations != nil {
468+
for i, association := range r.Spec.PodIdentityAssociations {
469+
associationPath := field.NewPath("spec", "podIdentityAssociations").Index(i)
470+
if association.ServiceAccountName == "" {
471+
allErrs = append(allErrs, field.Required(associationPath.Child("serviceAccountName"), "serviceAccountName is required"))
472+
}
473+
474+
// kubernetes uses ValidateServiceAccountName internally, which maps to IsDNS1123Subdomain
475+
// https://github.com/kubernetes/apimachinery/blob/d794766488ac2892197a7cc8d0b4b46b0edbda80/pkg/api/validation/generic.go#L68
476+
477+
if validationErrs := validation.IsDNS1123Subdomain(association.ServiceAccountName); len(validationErrs) > 0 {
478+
allErrs = append(allErrs, field.Invalid(associationPath.Child("serviceAccountName"), association.ServiceAccountName, fmt.Sprintf("serviceAccountName is invalid: %v", validationErrs)))
479+
}
480+
}
481+
}
482+
483+
return allErrs
484+
}
485+
461486
func (r *AWSManagedControlPlane) validateNetwork() field.ErrorList {
462487
return validateNetwork("AWSManagedControlPlane", r.Spec.NetworkSpec, r.Spec.SecondaryCidrBlock, field.NewPath("spec"))
463488
}

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: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,10 @@ var (
7979
EKSTokenMethodAWSCli = EKSTokenMethod("aws-cli")
8080
)
8181

82-
var (
83-
// DefaultEKSControlPlaneRole is the name of the default IAM role to use for the EKS control plane
84-
// if no other role is supplied in the spec and if iam role creation is not enabled. The default
85-
// can be created using clusterawsadm or created manually.
86-
DefaultEKSControlPlaneRole = fmt.Sprintf("eks-controlplane%s", iamv1.DefaultNameSuffix)
87-
)
82+
// DefaultEKSControlPlaneRole is the name of the default IAM role to use for the EKS control plane
83+
// if no other role is supplied in the spec and if iam role creation is not enabled. The default
84+
// can be created using clusterawsadm or created manually.
85+
var DefaultEKSControlPlaneRole = fmt.Sprintf("eks-controlplane%s", iamv1.DefaultNameSuffix)
8886

8987
// IAMAuthenticatorConfig represents an aws-iam-authenticator configuration.
9088
type IAMAuthenticatorConfig struct {
@@ -283,3 +281,17 @@ type OIDCIdentityProviderConfig struct {
283281
// +optional
284282
Tags infrav1.Tags `json:"tags,omitempty"`
285283
}
284+
285+
// 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.
286+
type PodIdentityAssociation struct {
287+
// ServiceAccountName is the name of the kubernetes Service Account within the namespace
288+
// +kubebuilder:validation:Required
289+
ServiceAccountName string `json:"serviceAccountName"`
290+
// ServiceAccountNamespace is the kubernetes namespace, which the kubernetes Service Account resides in. Defaults to "default" namespace.
291+
// +kubebuilder:validation:Required
292+
// +kubebuilder:default=default
293+
ServiceAccountNamespace string `json:"serviceAccountNamespace"`
294+
// RoleARN is the ARN of an IAM role which the Service Account can assume.
295+
// +kubebuilder:validation:Required
296+
RoleARN string `json:"roleARN,omitempty"`
297+
}

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
@@ -970,6 +970,11 @@ func mockedEKSCluster(ctx context.Context, g *WithT, eksRec *mock_eksiface.MockE
970970
}).Return(&eks.ListAddonsOutput{}, nil)
971971

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

974979
awsNodeRec.ReconcileCNI(gomock.Any()).Return(nil)
975980
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)