Skip to content

Commit 9d2fd30

Browse files
committed
Add validation for Hybrid node IAM role
1 parent 0352113 commit 9d2fd30

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

internal/node/hybrid/hybrid.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
apiServerEndpointResolution = "api-server-endpoint-resolution-validation"
2828
proxyValidation = "proxy-validation"
2929
nodeInactiveValidation = "node-inactive-validation"
30+
hybridRoleValidation = "hybrid-role-validation"
3031
kubeletCurrentCertPath = "/var/lib/kubelet/pki/kubelet-server-current.pem"
3132
)
3233

@@ -145,6 +146,7 @@ func (hnp *HybridNodeProvider) Validate(ctx context.Context) error {
145146
validation.New(apiServerEndpointResolution, kubernetes.ValidateAPIServerEndpointResolution),
146147
validation.New(proxyValidation, network.NewProxyValidator().Run),
147148
validation.New(nodeInactiveValidation, hnp.ValidateNodeIsInactive),
149+
validation.New(hybridRoleValidation, hnp.ValidateKubeletVersionSkew),
148150
)
149151

150152
// Run all validations sequentially
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package hybrid
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/aws/aws-sdk-go-v2/aws"
9+
"github.com/aws/aws-sdk-go-v2/aws/arn"
10+
"github.com/aws/aws-sdk-go-v2/service/eks"
11+
"github.com/aws/aws-sdk-go-v2/service/sts"
12+
13+
"github.com/aws/eks-hybrid/internal/api"
14+
"github.com/aws/eks-hybrid/internal/validation"
15+
)
16+
17+
func (hnp *HybridNodeProvider) ValidateClusterAccess(ctx context.Context, informer validation.Informer, _ *api.NodeConfig) error {
18+
var err error
19+
informer.Starting(ctx, "cluster-access", "Validating cluster access through EKS access entry or ConfigMap")
20+
defer func() {
21+
informer.Done(ctx, "cluster-access", err)
22+
}()
23+
24+
var roleName string
25+
stsClient := sts.NewFromConfig(*hnp.awsConfig)
26+
eksClient := eks.NewFromConfig(*hnp.awsConfig)
27+
28+
getCallerIdentityOutput, err := stsClient.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
29+
if err != nil {
30+
return err
31+
}
32+
roleArn := *getCallerIdentityOutput.Arn
33+
parsedARN, err := arn.Parse(roleArn)
34+
if err != nil {
35+
return err
36+
}
37+
38+
splitArn := strings.Split(parsedARN.Resource, "/")
39+
if parsedARN.Service == "sts" && strings.HasPrefix(parsedARN.Resource, "assumed-role") {
40+
roleName = splitArn[1]
41+
} else if parsedARN.Service == "iam" && strings.HasPrefix(parsedARN.Resource, "role") {
42+
roleName = splitArn[len(splitArn)-1]
43+
}
44+
45+
accessEntries := []string{}
46+
listAccessEntriesOutput, err := eksClient.ListAccessEntries(ctx, &eks.ListAccessEntriesInput{
47+
ClusterName: hnp.cluster.Name,
48+
})
49+
if err != nil {
50+
return err
51+
}
52+
53+
accessEntries = append(accessEntries, listAccessEntriesOutput.AccessEntries...)
54+
nextToken := listAccessEntriesOutput.NextToken
55+
56+
for nextToken != nil && aws.ToString(nextToken) != "" {
57+
listAccessEntriesOutput, err = eksClient.ListAccessEntries(ctx, &eks.ListAccessEntriesInput{
58+
ClusterName: hnp.cluster.Name,
59+
NextToken: nextToken,
60+
})
61+
if err != nil {
62+
return err
63+
}
64+
65+
accessEntries = append(accessEntries, listAccessEntriesOutput.AccessEntries...)
66+
nextToken = listAccessEntriesOutput.NextToken
67+
}
68+
69+
foundRole := false
70+
for _, accessEntry := range accessEntries {
71+
if strings.Contains(accessEntry, roleName) {
72+
foundRole = true
73+
}
74+
}
75+
76+
if !foundRole {
77+
err = validation.WithRemediation(fmt.Errorf("missing access entry with Hybrid Node role principal"), "Ensure your EKS cluster has at least one access entry with the hybrid node IAM role as principal.")
78+
return err
79+
}
80+
81+
return nil
82+
}

test/e2e/credentials/stack.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (s *Stack) Deploy(ctx context.Context, logger logr.Logger) (*StackOutput, e
9494
}
9595

9696
if !skipIRATest() {
97-
logger.Info("Creating access entry", "iamRoleArn", output.IRANodeRoleARN)
97+
logger.Info("Creating access entry", "iamRARoleArn", output.IRANodeRoleARN)
9898
_, err = s.EKS.CreateAccessEntry(ctx, &eks.CreateAccessEntryInput{
9999
ClusterName: &s.ClusterName,
100100
PrincipalArn: &output.IRANodeRoleARN,
@@ -335,7 +335,7 @@ func (s *Stack) Delete(ctx context.Context, logger logr.Logger, output *StackOut
335335
return fmt.Errorf("deleting SSM access entry: %w", err)
336336
}
337337
if !skipIRATest() {
338-
logger.Info("Deleting access entry", "iamRoleArn", output.IRANodeRoleARN)
338+
logger.Info("Deleting access entry", "iamRARoleArn", output.IRANodeRoleARN)
339339
if _, err := s.EKS.DeleteAccessEntry(ctx, &eks.DeleteAccessEntryInput{
340340
ClusterName: &s.ClusterName,
341341
PrincipalArn: &output.IRANodeRoleARN,

0 commit comments

Comments
 (0)