Skip to content

Commit b442d79

Browse files
authored
Populate role ARN from stack outputs on NoChangeError in pod identity update (#8717)
fix: populate role ARN from stack outputs on NoChangeError IAMRoleUpdater.Update returns an empty roleArn to the caller when CFN has nothing to update and the config uses roleName (no roleARN). Pull the ARN from the existing stack outputs instead.
1 parent 6d4926d commit b442d79

2 files changed

Lines changed: 79 additions & 2 deletions

File tree

pkg/actions/podidentityassociation/iam_role_updater.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ func (u *IAMRoleUpdater) Update(ctx context.Context, podIdentityAssociation api.
5252
var noChangeErr *manager.NoChangeError
5353
if errors.As(err, &noChangeErr) {
5454
logger.Info("IAM resources for %s (pod identity association ID: %s) are already up-to-date", podIdentityAssociation.NameString(), podIdentityAssociationID)
55+
if err := populateRoleARN(rs, stack); err != nil {
56+
return "", false, err
57+
}
5558
return podIdentityAssociation.RoleARN, false, nil
5659
}
5760
return "", false, fmt.Errorf("updating IAM resources for pod identity association: %w", err)

pkg/actions/podidentityassociation/updater_test.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,21 @@ var _ = Describe("Pod Identity Update", func() {
433433
ServiceAccountName: "aws-node",
434434
},
435435
}
436+
describeStackOutputs := []cfntypes.Output{
437+
{
438+
OutputKey: aws.String(outputs.IAMServiceAccountRoleName),
439+
OutputValue: aws.String("arn:aws:iam::1234567:role/Role"),
440+
},
441+
}
436442
mockListStackNames(stackManager, podIdentifiers)
437443
for _, options := range []mockOptions{
438444
{
439-
podIdentifier: podIdentifiers[0],
445+
podIdentifier: podIdentifiers[0],
446+
describeStackOutputs: describeStackOutputs,
440447
},
441448
{
442-
podIdentifier: podIdentifiers[1],
449+
podIdentifier: podIdentifiers[1],
450+
describeStackOutputs: describeStackOutputs,
443451
},
444452
} {
445453
mockCalls(stackManager, eksAPI, options)
@@ -458,6 +466,72 @@ var _ = Describe("Pod Identity Update", func() {
458466
},
459467
}),
460468

469+
Entry("IAM no changes but disableSessionTags triggers EKS update with roleName resolving ARN from stack", updateEntry{
470+
podIdentityAssociations: []api.PodIdentityAssociation{
471+
{
472+
Namespace: "default",
473+
ServiceAccountName: "default",
474+
RoleName: "my-custom-role",
475+
DisableSessionTags: aws.Bool(true),
476+
},
477+
},
478+
mockCalls: func(stackManager *managerfakes.FakeStackManager, eksAPI *mocksv2.EKS) {
479+
podIdentifier := podidentityassociation.Identifier{
480+
Namespace: "default",
481+
ServiceAccountName: "default",
482+
}
483+
mockListStackNames(stackManager, []podidentityassociation.Identifier{podIdentifier})
484+
485+
stackName := makeIRSAv2StackName(podIdentifier)
486+
associationID := fmt.Sprintf("%x", sha1.Sum([]byte(stackName)))
487+
resolvedRoleARN := "arn:aws:iam::1234567:role/my-custom-role"
488+
489+
mockListPodIdentityAssociations(eksAPI, podIdentifier, []ekstypes.PodIdentityAssociationSummary{
490+
{
491+
AssociationId: aws.String(associationID),
492+
},
493+
}, nil)
494+
eksAPI.On("DescribePodIdentityAssociation", mock.Anything, &eks.DescribePodIdentityAssociationInput{
495+
AssociationId: aws.String(associationID),
496+
ClusterName: aws.String(clusterName),
497+
}).Return(&eks.DescribePodIdentityAssociationOutput{
498+
Association: &ekstypes.PodIdentityAssociation{
499+
AssociationId: aws.String(associationID),
500+
RoleArn: aws.String(resolvedRoleARN),
501+
},
502+
}, nil)
503+
504+
stackManager.DescribeStackReturns(&cfntypes.Stack{
505+
StackName: aws.String(stackName),
506+
Outputs: []cfntypes.Output{
507+
{
508+
OutputKey: aws.String(outputs.IAMServiceAccountRoleName),
509+
OutputValue: aws.String(resolvedRoleARN),
510+
},
511+
},
512+
Capabilities: []cfntypes.Capability{cfntypes.CapabilityCapabilityIam, cfntypes.CapabilityCapabilityNamedIam},
513+
}, nil)
514+
515+
stackManager.MustUpdateStackReturns(&manager.NoChangeError{
516+
Msg: "no changes found",
517+
})
518+
519+
eksAPI.On("UpdatePodIdentityAssociation", mock.Anything, &eks.UpdatePodIdentityAssociationInput{
520+
AssociationId: aws.String(associationID),
521+
ClusterName: aws.String(clusterName),
522+
RoleArn: aws.String(resolvedRoleARN),
523+
DisableSessionTags: aws.Bool(true),
524+
}).Return(&eks.UpdatePodIdentityAssociationOutput{}, nil)
525+
},
526+
527+
expectedCalls: func(stackManager *managerfakes.FakeStackManager, eksAPI *mocksv2.EKS) {
528+
Expect(stackManager.ListPodIdentityStackNamesCallCount()).To(Equal(1))
529+
Expect(stackManager.DescribeStackCallCount()).To(Equal(1))
530+
Expect(stackManager.MustUpdateStackCallCount()).To(Equal(1))
531+
eksAPI.AssertExpectations(GinkgoT())
532+
},
533+
}),
534+
461535
Entry("update pod identity association with cross-account access", updateEntry{
462536
podIdentityAssociations: []api.PodIdentityAssociation{
463537
{

0 commit comments

Comments
 (0)