Skip to content

Commit 95e8972

Browse files
authored
Merge pull request #2901 from codablock/fix-oidc-reconcile
Try to find and verify existing OIDC providers before we try to create a new one
2 parents c8c30fc + f2381df commit 95e8972

File tree

5 files changed

+258
-7
lines changed

5 files changed

+258
-7
lines changed

cmd/clusterawsadm/cloudformation/bootstrap/cluster_api_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ func (t Template) ControllersPolicyEKS() *iamv1.PolicyDocument {
361361
statement = append(statement, iamv1.StatementEntry{
362362
Action: iamv1.Actions{
363363
"iam:ListOpenIDConnectProviders",
364+
"iam:GetOpenIDConnectProvider",
364365
"iam:CreateOpenIDConnectProvider",
365366
"iam:AddClientIDToOpenIDConnectProvider",
366367
"iam:UpdateOpenIDConnectProviderThumbprint",

pkg/cloud/services/eks/iam/iam.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package iam
1818

1919
import (
20+
"context"
2021
"crypto/sha1"
2122
"encoding/hex"
2223
"encoding/json"
@@ -45,6 +46,7 @@ const (
4546
type IAMService struct {
4647
logr.Logger
4748
IAMClient iamiface.IAMAPI
49+
Client *http.Client
4850
}
4951

5052
// GetIAMRole will return the IAM role for the IAMService.
@@ -418,7 +420,7 @@ func (s *IAMService) CreateOIDCProvider(cluster *eks.Cluster) (string, error) {
418420
return "", errors.Errorf("invalid scheme for issuer URL %s", issuerURL.String())
419421
}
420422

421-
thumbprint, err := fetchRootCAThumbprint(issuerURL.String())
423+
thumbprint, err := fetchRootCAThumbprint(issuerURL.String(), s.Client)
422424
if err != nil {
423425
return "", err
424426
}
@@ -434,8 +436,53 @@ func (s *IAMService) CreateOIDCProvider(cluster *eks.Cluster) (string, error) {
434436
return *provider.OpenIDConnectProviderArn, nil
435437
}
436438

437-
func fetchRootCAThumbprint(issuerURL string) (string, error) {
438-
response, err := http.Get(issuerURL)
439+
// FindAndVerifyOIDCProvider will try to find an OIDC provider. It will return an error if the found provider does not
440+
// match the cluster spec.
441+
func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, error) {
442+
issuerURL, err := url.Parse(*cluster.Identity.Oidc.Issuer)
443+
if err != nil {
444+
return "", err
445+
}
446+
if issuerURL.Scheme != "https" {
447+
return "", errors.Errorf("invalid scheme for issuer URL %s", issuerURL.String())
448+
}
449+
450+
thumbprint, err := fetchRootCAThumbprint(issuerURL.String(), s.Client)
451+
if err != nil {
452+
return "", err
453+
}
454+
output, err := s.IAMClient.ListOpenIDConnectProviders(&iam.ListOpenIDConnectProvidersInput{})
455+
if err != nil {
456+
return "", errors.Wrap(err, "error listing providers")
457+
}
458+
for _, r := range output.OpenIDConnectProviderList {
459+
provider, err := s.IAMClient.GetOpenIDConnectProvider(&iam.GetOpenIDConnectProviderInput{OpenIDConnectProviderArn: r.Arn})
460+
if err != nil {
461+
return "", errors.Wrap(err, "error getting provider")
462+
}
463+
// URL should always contain `https`.
464+
if *provider.Url != issuerURL.String() {
465+
continue
466+
}
467+
if len(provider.ThumbprintList) != 1 || *provider.ThumbprintList[0] != thumbprint {
468+
return "", errors.Wrap(err, "found provider with matching issuerURL but with non-matching thumbprint")
469+
}
470+
if len(provider.ClientIDList) != 1 || *provider.ClientIDList[0] != stsAWSAudience {
471+
return "", errors.Wrap(err, "found provider with matching issuerURL but with non-matching clientID")
472+
}
473+
return *r.Arn, nil
474+
}
475+
return "", nil
476+
}
477+
478+
func fetchRootCAThumbprint(issuerURL string, client *http.Client) (string, error) {
479+
// needed to appease noctx.
480+
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, issuerURL, nil)
481+
if err != nil {
482+
return "", err
483+
}
484+
485+
response, err := client.Do(req)
439486
if err != nil {
440487
return "", err
441488
}

pkg/cloud/services/eks/oidc.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,18 @@ func (s *Service) reconcileOIDCProvider(cluster *eks.Cluster) error {
5252
}
5353

5454
s.scope.Info("Reconciling EKS OIDC Provider", "cluster-name", cluster.Name)
55-
oidcProvider, err := s.CreateOIDCProvider(cluster)
55+
56+
oidcProvider, err := s.FindAndVerifyOIDCProvider(cluster)
5657
if err != nil {
57-
return errors.Wrap(err, "failed to create OIDC provider")
58+
return errors.Wrap(err, "failed to reconcile OIDC provider")
59+
}
60+
if oidcProvider == "" {
61+
oidcProvider, err = s.CreateOIDCProvider(cluster)
62+
if err != nil {
63+
return errors.Wrap(err, "failed to create OIDC provider")
64+
}
5865
}
66+
5967
s.scope.ControlPlane.Status.OIDCProvider.ARN = oidcProvider
6068

6169
policy, err := converters.IAMPolicyDocumentToJSON(s.buildOIDCTrustPolicy())

pkg/cloud/services/eks/oidc_test.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package eks
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/aws/aws-sdk-go/aws"
9+
"github.com/aws/aws-sdk-go/service/eks"
10+
"github.com/aws/aws-sdk-go/service/iam"
11+
"github.com/golang/mock/gomock"
12+
. "github.com/onsi/gomega"
13+
corev1 "k8s.io/api/core/v1"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/runtime"
16+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
17+
18+
infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta2"
19+
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta2"
20+
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/scope"
21+
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/iamauth/mock_iamauth"
22+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
23+
)
24+
25+
func TestOIDCReconcile(t *testing.T) {
26+
tests := []struct {
27+
name string
28+
expect func(m *mock_iamauth.MockIAMAPIMockRecorder, url string)
29+
cluster func(url string) eks.Cluster
30+
}{
31+
{
32+
name: "cluster create with no OIDC provider present yet should create one",
33+
cluster: func(url string) eks.Cluster {
34+
return eks.Cluster{
35+
Name: aws.String("cluster-test"),
36+
Arn: aws.String("arn:arn"),
37+
RoleArn: aws.String("arn:role"),
38+
Identity: &eks.Identity{
39+
Oidc: &eks.OIDC{
40+
Issuer: aws.String(url),
41+
},
42+
},
43+
}
44+
},
45+
expect: func(m *mock_iamauth.MockIAMAPIMockRecorder, url string) {
46+
m.ListOpenIDConnectProviders(&iam.ListOpenIDConnectProvidersInput{}).Return(&iam.ListOpenIDConnectProvidersOutput{
47+
OpenIDConnectProviderList: []*iam.OpenIDConnectProviderListEntry{},
48+
}, nil)
49+
m.CreateOpenIDConnectProvider(&iam.CreateOpenIDConnectProviderInput{
50+
ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}),
51+
ThumbprintList: aws.StringSlice([]string{"15dbd260c7465ecca6de2c0b2181187f66ee0d1a"}),
52+
Url: &url,
53+
}).Return(&iam.CreateOpenIDConnectProviderOutput{
54+
OpenIDConnectProviderArn: aws.String("arn::oidc"),
55+
}, nil)
56+
},
57+
},
58+
{
59+
name: "cluster create with existing OIDC provider which is retrieved",
60+
cluster: func(url string) eks.Cluster {
61+
return eks.Cluster{
62+
Name: aws.String("cluster-test"),
63+
Arn: aws.String("arn:arn"),
64+
RoleArn: aws.String("arn:role"),
65+
Identity: &eks.Identity{
66+
Oidc: &eks.OIDC{
67+
Issuer: aws.String(url),
68+
},
69+
},
70+
}
71+
},
72+
expect: func(m *mock_iamauth.MockIAMAPIMockRecorder, url string) {
73+
m.ListOpenIDConnectProviders(&iam.ListOpenIDConnectProvidersInput{}).Return(&iam.ListOpenIDConnectProvidersOutput{
74+
OpenIDConnectProviderList: []*iam.OpenIDConnectProviderListEntry{
75+
{
76+
Arn: aws.String("arn::oidc"),
77+
},
78+
},
79+
}, nil)
80+
// This should equal with what we provide.
81+
m.GetOpenIDConnectProvider(&iam.GetOpenIDConnectProviderInput{
82+
OpenIDConnectProviderArn: aws.String("arn::oidc"),
83+
}).Return(&iam.GetOpenIDConnectProviderOutput{
84+
ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}),
85+
ThumbprintList: aws.StringSlice([]string{"15dbd260c7465ecca6de2c0b2181187f66ee0d1a"}),
86+
Url: &url,
87+
}, nil)
88+
},
89+
},
90+
}
91+
92+
for _, tc := range tests {
93+
t.Run(tc.name, func(t *testing.T) {
94+
g := NewWithT(t)
95+
96+
mockControl := gomock.NewController(t)
97+
defer mockControl.Finish()
98+
99+
scheme := runtime.NewScheme()
100+
_ = infrav1.AddToScheme(scheme)
101+
_ = ekscontrolplanev1.AddToScheme(scheme)
102+
_ = corev1.AddToScheme(scheme)
103+
104+
ts := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
105+
// Send response to be tested
106+
rw.WriteHeader(http.StatusOK)
107+
rw.Write([]byte(`OK`))
108+
}))
109+
defer ts.Close()
110+
111+
controlPlane := &ekscontrolplanev1.AWSManagedControlPlane{
112+
ObjectMeta: metav1.ObjectMeta{
113+
Name: "test-source",
114+
Namespace: "ns",
115+
},
116+
Spec: ekscontrolplanev1.AWSManagedControlPlaneSpec{
117+
Version: aws.String("1.25"),
118+
AssociateOIDCProvider: true,
119+
},
120+
}
121+
secret := &corev1.Secret{
122+
ObjectMeta: metav1.ObjectMeta{
123+
Name: "capi-name-kubeconfig",
124+
Namespace: "ns",
125+
},
126+
Data: map[string][]byte{
127+
"value": kubeConfig,
128+
},
129+
}
130+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(controlPlane, secret).Build()
131+
scope, _ := scope.NewManagedControlPlaneScope(scope.ManagedControlPlaneScopeParams{
132+
Client: client,
133+
Cluster: &clusterv1.Cluster{
134+
ObjectMeta: metav1.ObjectMeta{
135+
Namespace: "ns",
136+
Name: "capi-name",
137+
},
138+
},
139+
ControlPlane: controlPlane,
140+
EnableIAM: true,
141+
})
142+
143+
iamMock := mock_iamauth.NewMockIAMAPI(mockControl)
144+
tc.expect(iamMock.EXPECT(), ts.URL)
145+
s := NewService(scope, WithIAMClient(ts.Client()))
146+
s.IAMClient = iamMock
147+
148+
cluster := tc.cluster(ts.URL)
149+
err := s.reconcileOIDCProvider(&cluster)
150+
// We reached the trusted policy reconcile which will fail because it tries to connect to the server.
151+
// But at this point, we already know that the critical area has been covered.
152+
g.Expect(err).To(MatchError(ContainSubstring("dial tcp: lookup test-cluster-api.nodomain.example.com")))
153+
})
154+
}
155+
}
156+
157+
var kubeConfig = []byte(`apiVersion: v1
158+
clusters:
159+
- cluster:
160+
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1Ea3lPVEl3TWpnek1Gb1hEVE15TURreU5qSXdNamd6TUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTFBqCldzdlNEM1kxR1daNGpPSDdqdm4zNUNKUUJvdm8vVnljN3BQdHB6OEVWaFJNNnpRSTMrU2EvdDZyMWdSeHcwM1QKalhHTlRvamNOU0dUVGhHSnN6K28vRjc0Tml5enN2bk5zaThHem9rRU42QmpVU1NmeDg2RVZrM3J4ekVkeFhEaQpoZmNmcDFrQkJBa3lyMGltUGlSZDBaWGFSTnA1dEhldDI3eXp4TTBLZDRjRUxPcHJQc1QzRlp0bGNQTU01YVhzCmhzcGR6dkpmMFNUeWtCNWRtUmU4WHVEc0VDeVgvSTBVbVdXNVkvaWRDMmN0WUE5bEExMjdlcEFrMFUwb29lU2IKUWdMZ0tScjJ6UUl0UzlVNEdEaUttdGVsZVI2dWg2bjdTRkxRZVl1Y25hYXZWb0lBZ1A0UDRRejVMVi9OelF3bApVZENFR3lPODkxQVVDVkIrbENNQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZOTmc4L2ZueStjUW40YmZhdzVGRE1ld3kvcm9NQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRkFMSGZTcFNmTVQwQjlpTGFPVgpqN3d0V2I5MUY1Y25uZm15QWhVbm5qZXk2a1YyOFlNSWl2enZ3ZlQ5ZmVPb1llT3p4Tldla3YxUUVEaGw3a2pZCmJ2L2V5SDR3dDZGSHVCNlduQ1lESVpzK1doaXNURmd6bE5QeDJ0UVZLYjhzdy9WdGI0UU1WWVp3QjdpT2p6V1QKWjA4MW5MTmJpalQ3eEdIeWRWMWQ0SDR5eS91ajNJdWU3bkxYNHFPZk9udi8wQ2Vvb2Evd0VQeG1HMjJYb09WZgpzSlRWZnhrK1Zpak1Fc1kzRmZidWR1d3llNHc0cmxmUXhCNFZtbE1INEFrRmFvT1hLTGdGS3FrQkFLNVgwekhKClQvWWJkTm9jOThlcnJRNXZkRXhDZkV4RjFCWWtnbUVwcGZOV2UwK01xekgwZ2RTTTBzNEFBUmhrME4xNWRwVXoKeTBnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
161+
server: https://test-cluster-api.nodomain.example.com:6443
162+
name: kind-kind
163+
contexts:
164+
- context:
165+
cluster: kind-kind
166+
user: kind-kind
167+
name: kind-kind
168+
current-context: kind-kind
169+
kind: Config
170+
preferences: {}
171+
users:
172+
- name: kind-kind
173+
user:
174+
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJRUlJK3dnRVhXWVF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBNU1qa3lNREk0TXpCYUZ3MHlNekE1TWpreU1ESTRNekZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXFNcHJqYU1NaXdTN2dTOXgKcnd5VGFJRDZncUxOcklpMEh3SnRzTVpMRERTWTJLZWd5VCtwaDcxNjc4bHB3SHk2Njg3dVJ0WXpQcU90cXVNRQpEcTQzdmpxMzNMTng1ZVI4SnhSTk53d2Q3VXJZNmt4R2U1UUF3MXdWRW9OcmZTZk1BdTBOMEtIb1FKRjhEZDNlCjNFTVl5YmxySEYzMlN5MnluNHpWMmZRMDdpV2RUa2x3WDNZbkpTcFlFRTFDM3k2NjFHVVdGSXZCZm03b2NuOFUKeGdzQ01XNkxrbzVaMXh4OGVzZm5SSU5oZHZnS1BuN3dQSEtMUEQzRDNNUUdwM2V2QVVIWVExclpnTXRJNDQ3WQpVeVlkSFo5NDVLcVpRZ1ppS2FCdE1lblpmcVJndzArckNkeG5qMTRFYSt4RmtPMlNYQ0wrRWtNaUdvaFU3T29RCnVnay80d0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JUVFlQUDM1OHZuRUorRzMyc09SUXpIc012Ngo2REFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBTklMSVp3TDhZdlh0QTRqZm9VNlBlYWc4bFBSaWQ2TDlEdTcxCm03NDZMRWQ0cVMvQ2VFb1Z3Q0JqUnplQytLRkcvMERFa3JvYXRTbzhQMXZQQVkxYm5yN3FJdmo3S0RIS25lWFcKSS9saGo4M3ZyYmhoRjN1TXVnTXRiaUI0cnB0eUxjMjc5cGpnWDJqMkFxN09OUDNnVVJoVmJBZG1JTmQwNlVhYQpnaTR1dFBGV1Z2cENsTlpKWXhqUnJVZzJCR0JSQ0RQVU9JWkVkeHBVRnQ5cWsrWWxva0RQb29lR1QzVGlKNnE3ClJwS01UQ04yOWo3cS96cEwxSlNGNXFEVWprdXV5eWd3aUNUcXR0SVBwajAvaU5kak9TVGJlcG5sMUdPOTVNTUEKbGN6NzQ4NEt1dTlGSEtTcjhvcHVEK1hWYXBRbWpuZVdIYmtQUVo4elMwTGExdHc1V2c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
175+
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBcU1wcmphTU1pd1M3Z1M5eHJ3eVRhSUQ2Z3FMTnJJaTBId0p0c01aTEREU1kyS2VnCnlUK3BoNzE2NzhscHdIeTY2ODd1UnRZelBxT3RxdU1FRHE0M3ZqcTMzTE54NWVSOEp4Uk5Od3dkN1VyWTZreEcKZTVRQXcxd1ZFb05yZlNmTUF1ME4wS0hvUUpGOERkM2UzRU1ZeWJsckhGMzJTeTJ5bjR6VjJmUTA3aVdkVGtsdwpYM1luSlNwWUVFMUMzeTY2MUdVV0ZJdkJmbTdvY244VXhnc0NNVzZMa281WjF4eDhlc2ZuUklOaGR2Z0tQbjd3ClBIS0xQRDNEM01RR3AzZXZBVUhZUTFyWmdNdEk0NDdZVXlZZEhaOTQ1S3FaUWdaaUthQnRNZW5aZnFSZ3cwK3IKQ2R4bmoxNEVhK3hGa08yU1hDTCtFa01pR29oVTdPb1F1Z2svNHdJREFRQUJBb0lCQUNBTUJxMm1wbXdDb3dNZApHZTJOYXJOdHdhSnAvTGprWDZaL2xJbjZyQ2NPR1hNUktKTHRObWZpVHVRV0RyRVFQWUVtRWRGN085R0p6Q0JrCjU5Rk52S0d1amxnbDdkc2pMWHRSL0hNV0p0eDEySWRyb2ZvMm1JcC9BalU0cElEbnZIRlZ4c2kwNU43VmdJTTEKZStuQUI0WE5ZWXZLUDBmNHpqQkMwaHVHcFVJTnJTWEF5NEJUL0RQajF2bWkzQVZ5UGUwazNmV1RhY3RxRUN4dwpPUmRRMDhIeCtnRlNzNlpsYldZUU8xWnRlZ1AySlBKUVR3R0k5MGV3Q0JweCtNWC9Fdk5nRDdqbnhFS0ZRYUIzCko3RkpVVFIrcU5qZEs4c2wxeDhBUSs4R3lxVFo3SkNRRHI5WlRUamxBeW1UY0xNcHFSQXB3Z2hoYVZMNXlCejQKanBNODdIRUNnWUVBeENJdUVGMktFbFoxN29leE5RTUpyMGtBM2prbVVoMlpZbG5sOVdmdU1HNU1paldLNzZxNgpUWnVpVjB1c0dDandldDgvd1lvdEdHOFNqSFBsM2VXR0RzMTFJb1doRmdrK29keTNIbU5Gbm9wVWVSbmVxVnNvCnJLT0I0VGpuVjJpdkl2M1FuclFpV2NETjNGd0JoczlYNlQ0ZUwrSUZrVkk4LzdJUDRlbVlmNHNDZ1lFQTNFK3UKSkxZVHZKYm9YU2l5cHJlVVlnZGs1UjdlNVMvK3FNczJPOTh4d3hQRVgvbmxER0FWZlBXMEJ4ODhTMjk2c1dtTQpqYy8xdW95cDJrTWRBZm9DdVVYSDZncGFZVU1qSlpwQ01Vd1dyUDVuTGFQejhJMjZMQzBtY3M0T3JJNjI3MnFXCm5wQ3d1T1VMbzYyYVZrVWJDVGlmMkg0NkNHNkhUY1JGaHB0ZXpBa0NnWUVBaWtkQ3pMejJCRm02eVpJWFNMVzgKbFQxV0JGYXNnc1psaHFhMDd5RDRHR01iU1hIWVk0S3QyTnQ2U0N1TXlIZk1uQVJiMGRyV1VseTA2aHNvSEJxZgpPajUyY0FGZ2djWEF4Nk54NDFYQUZyZVdPTThaWWJOb2FOYmFVZXlwaGNIRGdGc01RMmZpcy82djVNVmxPaU5pCjZvbW1CTUpJaEoxRGJrNmV6ZnJBVG1NQ2dZRUFnSGl5bTFQV0ZJNkh0L09Jb25IQlJKejlPQ01WWmQ3a0NQaGYKaXZCdnEwdDJvMlV0TFZkR2tKVVRRMmZ5bUNiTkRISDVkYVVFcmFGalZ4VDE4SFlqYW5rSHlESDdYR1p6TTNWTwpEa05Kb2QzRXV6ZTFnOXlSNlRyM0JkR2xldmpLTXJrY1ZpRVgvT29NTEltS3k2NEd3d3pUSWNNU0FtSzU0aDZIClVLUi8xa2tDZ1lCQTN2R1lDTlJDS2hIazdKLzZBVnpESVN2VVMvQk9ma0pMTUplcDZ2cWt2SHl1bU9ISkVVcjAKa25KNVJHY3NqY3VsUE1EM2F1TjJlWWovV1k3dkJIclBiSk9sRkFlUVpCc2dKTEg5ZXlzV29tY1haNzRNQ0tUegpUTXhMWDhhZG9Sa3Y0NnhCdlB0YzR2WWVJUWErVWFxRDhVTDY3S3NaWnJVekdDdVRNdnIwWEE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
176+
177+
`)

pkg/cloud/services/eks/service.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package eks
1818

1919
import (
20+
"net/http"
21+
2022
"github.com/aws/aws-sdk-go/aws/request"
2123
"github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface"
2224
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
@@ -50,9 +52,18 @@ type Service struct {
5052
STSClient stsiface.STSAPI
5153
}
5254

55+
type ServiceOpts func(s *Service)
56+
57+
// WithIAMClient creates an access spec with a custom http client.
58+
func WithIAMClient(client *http.Client) ServiceOpts {
59+
return func(s *Service) {
60+
s.IAMService.Client = client
61+
}
62+
}
63+
5364
// NewService returns a new service given the api clients.
54-
func NewService(controlPlaneScope *scope.ManagedControlPlaneScope) *Service {
55-
return &Service{
65+
func NewService(controlPlaneScope *scope.ManagedControlPlaneScope, opts ...ServiceOpts) *Service {
66+
s := &Service{
5667
scope: controlPlaneScope,
5768
EC2Client: scope.NewEC2Client(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
5869
EKSClient: EKSClient{
@@ -61,9 +72,16 @@ func NewService(controlPlaneScope *scope.ManagedControlPlaneScope) *Service {
6172
IAMService: iam.IAMService{
6273
Logger: controlPlaneScope.Logger,
6374
IAMClient: scope.NewIAMClient(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
75+
Client: http.DefaultClient,
6476
},
6577
STSClient: scope.NewSTSClient(controlPlaneScope, controlPlaneScope, controlPlaneScope, controlPlaneScope.ControlPlane),
6678
}
79+
80+
for _, opt := range opts {
81+
opt(s)
82+
}
83+
84+
return s
6785
}
6886

6987
// NodegroupService holds a collection of interfaces.

0 commit comments

Comments
 (0)