Skip to content

Commit 80d737f

Browse files
committed
Adding regex validation for SSM parameters in nodeadm init command
1 parent 6e05b6c commit 80d737f

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

internal/node/hybrid/validator.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ package hybrid
22

33
import (
44
"fmt"
5+
"regexp"
56
"strings"
67

78
"github.com/aws/eks-hybrid/internal/api"
89
"github.com/aws/eks-hybrid/internal/util/file"
910
)
1011

12+
const (
13+
// https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_CreateActivation.html#systemsmanager-CreateActivation-response-ActivationId
14+
ssmActivationIDPattern = `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`
15+
ssmActivationCodePattern = `^.{20,250}$`
16+
)
17+
1118
func extractFlagValue(args []string, flag string) string {
1219
flagPrefix := "--" + flag + "="
1320
var flagValue string
@@ -51,6 +58,26 @@ func (hnp *HybridNodeProvider) withHybridValidators() {
5158
if cfg.Spec.Hybrid.SSM.ActivationID == "" {
5259
return fmt.Errorf("ActivationID is missing in hybrid ssm configuration")
5360
}
61+
62+
// Compile the activation code pattern
63+
reCode, err := regexp.Compile(ssmActivationCodePattern)
64+
if err != nil {
65+
return fmt.Errorf("internal error: invalid ActivationCode pattern: %v", err)
66+
}
67+
// Check if ActivationCode matches the pattern
68+
if !reCode.MatchString(cfg.Spec.Hybrid.SSM.ActivationCode) {
69+
return fmt.Errorf("invalid ActivationCode format: %s. Must be 20-250 characters", cfg.Spec.Hybrid.SSM.ActivationCode)
70+
}
71+
72+
// Compile the regex patterns
73+
reID, err := regexp.Compile(ssmActivationIDPattern)
74+
if err != nil {
75+
return fmt.Errorf("internal error: invalid ActivationID pattern: %v", err)
76+
}
77+
// Check if ActivationID matches the pattern
78+
if !reID.MatchString(cfg.Spec.Hybrid.SSM.ActivationID) {
79+
return fmt.Errorf("invalid ActivationID format: %s. Must be in format: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", cfg.Spec.Hybrid.SSM.ActivationID)
80+
}
5481
}
5582
return nil
5683
}

internal/node/hybrid/validator_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package hybrid_test
22

33
import (
44
"os"
5+
"strings"
56
"testing"
67

78
. "github.com/onsi/gomega"
@@ -195,6 +196,157 @@ func Test_HybridNodeProviderValidateConfig(t *testing.T) {
195196
},
196197
wantError: "hostname-override kubelet flag is not supported for hybrid nodes but found override: bad-config",
197198
},
199+
{
200+
name: "invalid when both iamRoleAnywhere and ssm provided",
201+
node: &api.NodeConfig{
202+
Spec: api.NodeConfigSpec{
203+
Cluster: api.ClusterDetails{
204+
Region: "us-west-2",
205+
Name: "my-cluster",
206+
},
207+
Hybrid: &api.HybridOptions{
208+
IAMRolesAnywhere: &api.IAMRolesAnywhere{
209+
NodeName: "my-node",
210+
TrustAnchorARN: "trust-anchor-arn",
211+
ProfileARN: "profile-arn",
212+
RoleARN: "role-arn",
213+
CertificatePath: certPath,
214+
PrivateKeyPath: keyPath,
215+
},
216+
SSM: &api.SSM{
217+
ActivationID: "activation-id",
218+
ActivationCode: "activation-code",
219+
},
220+
},
221+
},
222+
},
223+
wantError: "Only one of IAMRolesAnywhere or SSM must be provided for hybrid node configuration",
224+
},
225+
{
226+
name: "valid ssm activation code and activation id",
227+
node: &api.NodeConfig{
228+
Spec: api.NodeConfigSpec{
229+
Cluster: api.ClusterDetails{
230+
Region: "us-west-2",
231+
Name: "my-cluster",
232+
},
233+
Hybrid: &api.HybridOptions{
234+
SSM: &api.SSM{
235+
ActivationCode: "Fjz3/sZfSvv78EXAMPLE",
236+
ActivationID: "e488f2f6-e686-4afb-8a04-ef6dfabcdeff",
237+
},
238+
},
239+
},
240+
},
241+
},
242+
{
243+
name: "missing ssm activation code",
244+
node: &api.NodeConfig{
245+
Spec: api.NodeConfigSpec{
246+
Cluster: api.ClusterDetails{
247+
Region: "us-west-2",
248+
Name: "my-cluster",
249+
},
250+
Hybrid: &api.HybridOptions{
251+
SSM: &api.SSM{
252+
ActivationCode: "",
253+
ActivationID: "e488f2f6-e686-4afb-8a04-ef6dfabcdeff",
254+
},
255+
},
256+
},
257+
},
258+
wantError: "ActivationCode is missing in hybrid ssm configuration",
259+
},
260+
{
261+
name: "missing ssm activation id",
262+
node: &api.NodeConfig{
263+
Spec: api.NodeConfigSpec{
264+
Cluster: api.ClusterDetails{
265+
Region: "us-west-2",
266+
Name: "my-cluster",
267+
},
268+
Hybrid: &api.HybridOptions{
269+
SSM: &api.SSM{
270+
ActivationCode: "Fjz3/sZfSvv78EXAMPLE",
271+
ActivationID: "",
272+
},
273+
},
274+
},
275+
},
276+
wantError: "ActivationID is missing in hybrid ssm configuration",
277+
},
278+
{
279+
name: "invalid ssm activation code (too short)",
280+
node: &api.NodeConfig{
281+
Spec: api.NodeConfigSpec{
282+
Cluster: api.ClusterDetails{
283+
Region: "us-west-2",
284+
Name: "my-cluster",
285+
},
286+
Hybrid: &api.HybridOptions{
287+
SSM: &api.SSM{
288+
ActivationCode: "activation-code",
289+
ActivationID: "e488f2f6-e686-4afb-8a04-ef6dfabcdeff",
290+
},
291+
},
292+
},
293+
},
294+
wantError: "invalid ActivationCode format: activation-code. Must be 20-250 characters",
295+
},
296+
{
297+
name: "invalid ssm activation code (too long - 251 chars)",
298+
node: &api.NodeConfig{
299+
Spec: api.NodeConfigSpec{
300+
Cluster: api.ClusterDetails{
301+
Region: "us-west-2",
302+
Name: "my-cluster",
303+
},
304+
Hybrid: &api.HybridOptions{
305+
SSM: &api.SSM{
306+
ActivationCode: strings.Repeat("a", 251),
307+
ActivationID: "e488f2f6-e686-4afb-8a04-ef6dfabcdeff",
308+
},
309+
},
310+
},
311+
},
312+
wantError: "invalid ActivationCode format: " + strings.Repeat("a", 251) + ". Must be 20-250 characters",
313+
},
314+
{
315+
name: "invalid ssm activation id by length",
316+
node: &api.NodeConfig{
317+
Spec: api.NodeConfigSpec{
318+
Cluster: api.ClusterDetails{
319+
Region: "us-west-2",
320+
Name: "my-cluster",
321+
},
322+
Hybrid: &api.HybridOptions{
323+
SSM: &api.SSM{
324+
ActivationCode: "Fjz3/sZfSvv78EXAMPLE",
325+
ActivationID: "e488f2f6-e686-4afb-8a04-ef6dfabcdefff",
326+
},
327+
},
328+
},
329+
},
330+
wantError: "invalid ActivationID format: e488f2f6-e686-4afb-8a04-ef6dfabcdefff. Must be in format: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
331+
},
332+
{
333+
name: "invalid ssm activation id by characters",
334+
node: &api.NodeConfig{
335+
Spec: api.NodeConfigSpec{
336+
Cluster: api.ClusterDetails{
337+
Region: "us-west-2",
338+
Name: "my-cluster",
339+
},
340+
Hybrid: &api.HybridOptions{
341+
SSM: &api.SSM{
342+
ActivationCode: "Fjz3/sZfSvv78EXAMPLE",
343+
ActivationID: "e488f2f6-e686-4afb-8A04-ef6dfabcdefff",
344+
},
345+
},
346+
},
347+
},
348+
wantError: "invalid ActivationID format: e488f2f6-e686-4afb-8A04-ef6dfabcdefff. Must be in format: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
349+
},
198350
}
199351
for _, tc := range testCases {
200352
t.Run(tc.name, func(t *testing.T) {

0 commit comments

Comments
 (0)