Skip to content

Commit cff1216

Browse files
authored
fix: match cloudformation stack name using suffix for pod identity association (#8511)
fix: pod identity association cloudformation stack matching using suffix
1 parent b7c02b3 commit cff1216

File tree

2 files changed

+150
-2
lines changed

2 files changed

+150
-2
lines changed

pkg/actions/podidentityassociation/deleter.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,21 @@ func ToIdentifiers(podIdentityAssociations []api.PodIdentityAssociation) []Ident
229229
}
230230

231231
func getIAMResourcesStack(stackNames []string, p Identifier) (string, bool) {
232+
// Stack names follow two patterns:
233+
// IRSAv2: eksctl-{cluster}-podidentityrole-{namespace}-{serviceAccount}
234+
// IRSAv1: eksctl-{cluster}-addon-iamserviceaccount-{namespace}-{serviceAccount}
235+
// We need to match exactly to avoid substring matches like "service" matching "other-service"
236+
nameString := p.NameString()
237+
targetSuffixes := []string{
238+
"-podidentityrole-" + nameString, // IRSAv2 pattern
239+
"-addon-iamserviceaccount-" + nameString, // IRSAv1 pattern
240+
}
241+
232242
for _, name := range stackNames {
233-
if strings.Contains(name, p.NameString()) {
234-
return name, true
243+
for _, suffix := range targetSuffixes {
244+
if strings.HasSuffix(name, suffix) {
245+
return name, true
246+
}
235247
}
236248
}
237249
return "", false
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package podidentityassociation
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestGetIAMResourcesStack(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
stackNames []string
13+
identifier Identifier
14+
expectedStack string
15+
expectedFound bool
16+
description string
17+
}{
18+
{
19+
name: "exact match found",
20+
stackNames: []string{
21+
"eksctl-cluster-podidentityrole-service-service-account",
22+
},
23+
identifier: Identifier{
24+
Namespace: "service",
25+
ServiceAccountName: "service-account",
26+
},
27+
expectedStack: "eksctl-cluster-podidentityrole-service-service-account",
28+
expectedFound: true,
29+
description: "Should find exact match",
30+
},
31+
{
32+
name: "no substring false positive",
33+
stackNames: []string{
34+
"eksctl-cluster-podidentityrole-other-service-service-account",
35+
},
36+
identifier: Identifier{
37+
Namespace: "service",
38+
ServiceAccountName: "service-account",
39+
},
40+
expectedStack: "",
41+
expectedFound: false,
42+
description: "Should not match 'service-service-account' as substring of 'other-service-service-account'",
43+
},
44+
{
45+
name: "multiple stacks with correct match",
46+
stackNames: []string{
47+
"eksctl-cluster-podidentityrole-other-service-service-account",
48+
"eksctl-cluster-podidentityrole-service-service-account",
49+
"eksctl-cluster-podidentityrole-another-service-different-account",
50+
},
51+
identifier: Identifier{
52+
Namespace: "service",
53+
ServiceAccountName: "service-account",
54+
},
55+
expectedStack: "eksctl-cluster-podidentityrole-service-service-account",
56+
expectedFound: true,
57+
description: "Should find correct match among multiple stacks",
58+
},
59+
{
60+
name: "no match found",
61+
stackNames: []string{
62+
"eksctl-cluster-podidentityrole-other-service-service-account",
63+
"eksctl-cluster-podidentityrole-another-service-different-account",
64+
},
65+
identifier: Identifier{
66+
Namespace: "service",
67+
ServiceAccountName: "service-account",
68+
},
69+
expectedStack: "",
70+
expectedFound: false,
71+
description: "Should not find any match",
72+
},
73+
{
74+
name: "customer reported case",
75+
stackNames: []string{
76+
"eksctl-cluster-podidentityrole-service-service-account",
77+
"eksctl-cluster-podidentityrole-other-service-service-account",
78+
},
79+
identifier: Identifier{
80+
Namespace: "service",
81+
ServiceAccountName: "service-account",
82+
},
83+
expectedStack: "eksctl-cluster-podidentityrole-service-service-account",
84+
expectedFound: true,
85+
description: "Customer reported case: should match 'service' not 'other-service'",
86+
},
87+
{
88+
name: "customer reported case reverse",
89+
stackNames: []string{
90+
"eksctl-cluster-podidentityrole-service-service-account",
91+
"eksctl-cluster-podidentityrole-other-service-service-account",
92+
},
93+
identifier: Identifier{
94+
Namespace: "other-service",
95+
ServiceAccountName: "service-account",
96+
},
97+
expectedStack: "eksctl-cluster-podidentityrole-other-service-service-account",
98+
expectedFound: true,
99+
description: "Customer reported case reverse: should match 'other-service' not 'service'",
100+
},
101+
{
102+
name: "IRSAv1 pattern match",
103+
stackNames: []string{
104+
"eksctl-cluster-addon-iamserviceaccount-service-service-account",
105+
},
106+
identifier: Identifier{
107+
Namespace: "service",
108+
ServiceAccountName: "service-account",
109+
},
110+
expectedStack: "eksctl-cluster-addon-iamserviceaccount-service-service-account",
111+
expectedFound: true,
112+
description: "Should match IRSAv1 pattern",
113+
},
114+
{
115+
name: "IRSAv1 no substring false positive",
116+
stackNames: []string{
117+
"eksctl-cluster-addon-iamserviceaccount-other-service-service-account",
118+
},
119+
identifier: Identifier{
120+
Namespace: "service",
121+
ServiceAccountName: "service-account",
122+
},
123+
expectedStack: "",
124+
expectedFound: false,
125+
description: "Should not match IRSAv1 'service-service-account' as substring of 'other-service-service-account'",
126+
},
127+
}
128+
129+
for _, tt := range tests {
130+
t.Run(tt.name, func(t *testing.T) {
131+
actualStack, actualFound := getIAMResourcesStack(tt.stackNames, tt.identifier)
132+
assert.Equal(t, tt.expectedFound, actualFound, tt.description)
133+
assert.Equal(t, tt.expectedStack, actualStack, tt.description)
134+
})
135+
}
136+
}

0 commit comments

Comments
 (0)