Skip to content

Commit f2381df

Browse files
committed
Switching to mocking the http client used to get the OIDC issuer
1 parent 480200c commit f2381df

File tree

3 files changed

+44
-99
lines changed

3 files changed

+44
-99
lines changed

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

Lines changed: 12 additions & 4 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
}
@@ -445,7 +447,7 @@ func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, er
445447
return "", errors.Errorf("invalid scheme for issuer URL %s", issuerURL.String())
446448
}
447449

448-
thumbprint, err := fetchRootCAThumbprint(issuerURL.String())
450+
thumbprint, err := fetchRootCAThumbprint(issuerURL.String(), s.Client)
449451
if err != nil {
450452
return "", err
451453
}
@@ -473,8 +475,14 @@ func (s *IAMService) FindAndVerifyOIDCProvider(cluster *eks.Cluster) (string, er
473475
return "", nil
474476
}
475477

476-
func fetchRootCAThumbprint(issuerURL string) (string, error) {
477-
response, err := http.Get(issuerURL)
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)
478486
if err != nil {
479487
return "", err
480488
}

pkg/cloud/services/eks/oidc_test.go

Lines changed: 12 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
package eks
22

33
import (
4-
"crypto/tls"
5-
"crypto/x509"
6-
"fmt"
7-
"net"
84
"net/http"
95
"net/http/httptest"
10-
"net/url"
116
"testing"
127

138
"github.com/aws/aws-sdk-go/aws"
@@ -53,7 +48,7 @@ func TestOIDCReconcile(t *testing.T) {
5348
}, nil)
5449
m.CreateOpenIDConnectProvider(&iam.CreateOpenIDConnectProviderInput{
5550
ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}),
56-
ThumbprintList: aws.StringSlice([]string{"c7a33e1de97f8bf5413ef9a833da98507c95416c"}),
51+
ThumbprintList: aws.StringSlice([]string{"15dbd260c7465ecca6de2c0b2181187f66ee0d1a"}),
5752
Url: &url,
5853
}).Return(&iam.CreateOpenIDConnectProviderOutput{
5954
OpenIDConnectProviderArn: aws.String("arn::oidc"),
@@ -87,7 +82,7 @@ func TestOIDCReconcile(t *testing.T) {
8782
OpenIDConnectProviderArn: aws.String("arn::oidc"),
8883
}).Return(&iam.GetOpenIDConnectProviderOutput{
8984
ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}),
90-
ThumbprintList: aws.StringSlice([]string{"c7a33e1de97f8bf5413ef9a833da98507c95416c"}),
85+
ThumbprintList: aws.StringSlice([]string{"15dbd260c7465ecca6de2c0b2181187f66ee0d1a"}),
9186
Url: &url,
9287
}, nil)
9388
},
@@ -106,8 +101,11 @@ func TestOIDCReconcile(t *testing.T) {
106101
_ = ekscontrolplanev1.AddToScheme(scheme)
107102
_ = corev1.AddToScheme(scheme)
108103

109-
ts, url, err := testServer()
110-
g.Expect(err).To(Succeed())
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+
}))
111109
defer ts.Close()
112110

113111
controlPlane := &ekscontrolplanev1.AWSManagedControlPlane{
@@ -143,98 +141,19 @@ func TestOIDCReconcile(t *testing.T) {
143141
})
144142

145143
iamMock := mock_iamauth.NewMockIAMAPI(mockControl)
146-
tc.expect(iamMock.EXPECT(), url.String())
147-
s := NewService(scope)
144+
tc.expect(iamMock.EXPECT(), ts.URL)
145+
s := NewService(scope, WithIAMClient(ts.Client()))
148146
s.IAMClient = iamMock
149147

150-
cluster := tc.cluster(url.String())
151-
err = s.reconcileOIDCProvider(&cluster)
148+
cluster := tc.cluster(ts.URL)
149+
err := s.reconcileOIDCProvider(&cluster)
152150
// We reached the trusted policy reconcile which will fail because it tries to connect to the server.
153151
// But at this point, we already know that the critical area has been covered.
154-
g.Expect(err).To(MatchError(ContainSubstring("dial tcp: lookup test-cluster-api.nodomain.example.com: no such host")))
152+
g.Expect(err).To(MatchError(ContainSubstring("dial tcp: lookup test-cluster-api.nodomain.example.com")))
155153
})
156154
}
157155
}
158156

159-
func testServer() (*httptest.Server, *url.URL, error) {
160-
rootCAs := x509.NewCertPool()
161-
162-
cert, err := tls.X509KeyPair(serverCert, serverKey)
163-
if err != nil {
164-
return nil, nil, fmt.Errorf("failed to init x509 cert/key pair: %w", err)
165-
}
166-
tlsConfig := &tls.Config{
167-
Certificates: []tls.Certificate{cert},
168-
RootCAs: rootCAs,
169-
MinVersion: tls.VersionTLS12,
170-
}
171-
172-
tlsServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
173-
w.WriteHeader(http.StatusOK)
174-
w.Write([]byte("ok"))
175-
}))
176-
177-
tlsServer.TLS = tlsConfig
178-
tlsServer.StartTLS()
179-
180-
serverURL, err := url.Parse(tlsServer.URL)
181-
if err != nil {
182-
tlsServer.Close()
183-
return nil, nil, fmt.Errorf("failed to parse the testserver URL: %w", err)
184-
}
185-
serverURL.Host = net.JoinHostPort("localhost", serverURL.Port())
186-
187-
return tlsServer, serverURL, nil
188-
}
189-
190-
// generated with `mkcert example.com "*.example.com" example.test localhost 127.0.0.1 ::1`.
191-
var serverCert = []byte(`-----BEGIN CERTIFICATE-----
192-
MIIC3DCCAcQCCQDKSKIAwGGsezANBgkqhkiG9w0BAQUFADAwMQswCQYDVQQGEwJV
193-
UzENMAsGA1UECAwEVXRhaDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMDkzMDA1
194-
MDk0NVoXDTMyMDkyNzA1MDk0NVowMDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0
195-
YWgxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
196-
AQoCggEBAJet5JFSOFRh4McYs/V7ZWE4NfGwOYrjwExocwuxf+3rZp2LsAHefN01
197-
rps8fDBk57PbolC5WAutGZBS06asT6/j7XGi1SSIr+C1Sr5X5lnrQWlqimYyVK+k
198-
cPqRkgEVVmYdgESIi0UV1ulEIqfeqgo49S/2u46lt1S/Cvb3dV9oX+aP/CBihPal
199-
z00QtqPdgM3ebG0K/V+JKF5VGkduHfCwIR710pbSvrscPhuQBW+FtGkVGgGsT53w
200-
+m+bpUo8w6FIqp6oQ1gqXIZTDWNtqF7RmuzgohSuo0xfuqkazWMKOsucKJirS0Z2
201-
6wbFG1O/e/GrQ/T1Yp3u8dvSG0KPZy8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
202-
JJFduoko6CTlcgJo4bUJUb/nBDvGZ4e52YJlbsKnqT9bWCgEtaiekw08PBFwjIWK
203-
GXNVUHVhCyFk+hFwCx9TkFfpDNTeiv/xoRBi24Nl60x0kv9SfOyaPaeC3g9cN4HU
204-
JEg72P4A47Owj94RVkqZmwmRcZQ/fh8qTuvSmgoJaMfqXLRGFJbWyPUa3wYzHyjY
205-
CGzMRQTnwJ8Ky4xHoVClbcBTXXTm2tdmojzJP1hwt1zBraq/3tBRBYrKvV4Eqsg4
206-
j3OcbtBxfcVpm/tHlS1JkPznTryVNZhoxf/a4LXSwBGsAHTb14FfNbguuoyl0vZZ
207-
qE56RZINYB2h11pH/1sC0g==
208-
-----END CERTIFICATE-----`)
209-
var serverKey = []byte(`-----BEGIN PRIVATE KEY-----
210-
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXreSRUjhUYeDH
211-
GLP1e2VhODXxsDmK48BMaHMLsX/t62adi7AB3nzdNa6bPHwwZOez26JQuVgLrRmQ
212-
UtOmrE+v4+1xotUkiK/gtUq+V+ZZ60FpaopmMlSvpHD6kZIBFVZmHYBEiItFFdbp
213-
RCKn3qoKOPUv9ruOpbdUvwr293VfaF/mj/wgYoT2pc9NELaj3YDN3mxtCv1fiShe
214-
VRpHbh3wsCEe9dKW0r67HD4bkAVvhbRpFRoBrE+d8Ppvm6VKPMOhSKqeqENYKlyG
215-
Uw1jbahe0Zrs4KIUrqNMX7qpGs1jCjrLnCiYq0tGdusGxRtTv3vxq0P09WKd7vHb
216-
0htCj2cvAgMBAAECggEADv66/P7i4Ly4axZvHBKx6BWVh6pDVg7EAQnGbd6DZjMC
217-
dwrLQLQNJhVbiK9HG8Wt/mL1PgPEx4q6X0FA+VZJnnrrC3PsnGsC8DUcCYtJE5Sl
218-
Z9WHjyjkpGSeYrcndwH0A65g8uWI1zCciX0Z6/ygVNhirPY4fpa1dCRa4iV+rgrN
219-
jyZ7+drI3yiiQYds1mF9qBlvDEvomoWlPQ74BMzjQs7BlgRTATwdIztRCiKNUK4G
220-
4PvnNGjDVZsGUeSAaR/+FOE/mCElDE8QR+5eD9iLYUyO0aTXKoMKFZCJMjzqaUlW
221-
XjOE3d6jNzP4qM1vZVc0ozloXsRVuakJduyh/tmL6QKBgQDJ2gmOgTMfj1jKlIOo
222-
T2fa4iAW9PMMErn/x4wTgF+BItuwf8rCVAZYtzMt022CajwHODDpIAiQQZsOOCyE
223-
nd0poYH+IU0PVNvUJRcH7SYSvVlzD9nkM64BLnaX1Fnf4We83GmUhweVqUXTszDn
224-
U0bJcRAxM9kovABkkrHeDQr4mwKBgQDAXlBUtzfSslqsXXLEDfTqaW2u+Z3QaKfQ
225-
VI3z3D1GKmgKzr6Z+oaa6JboKLL9if757GK9xRLTnay775F9x2xlNzz+iq6lZSyb
226-
n1yUaLP1LXa6hmOunP5lo6KduSFP4kqreIHWWuoyKbrB3tEBMqr1Lp2ydL6kP/Dg
227-
0Oz+rnuC/QKBgA55BrRkCSFbKtejnGkGAIFOM1TSDVcxRIrVaPLBApgEwtG95/DV
228-
C3ty70V64mA2c8VkvwUIGfUV7yMu3epIU2I3xVVOV/Mgd36XhjY4R8GSOAaq/UmC
229-
dxh4l2I9hJAr3j9JYnyWzfFqKKqML5Z2fx3UcH/Gouxrxm9voTc1ojK/AoGATPWu
230-
d6XxLFb0VZ7xKiRXRmy1V9o/W8By2rLpM5V54hdXFnPN5zZGIbVJokmeCjbqDjyW
231-
6ErulECxeWKHt2VQJVIrEb6TzlGivgPMewdEb6Mnq8nWGWZvlGQZy7Xj8NyceOs2
232-
Lnai2Ty+nY8x2KPXp01mA54XIwj9qkOLfPx7J1UCgYA7zJ3auVehaKIphx/gLpzL
233-
mWdrQHrrvlS04jy6IfQfKcRo9lGFXgWiPSQomWKbvA2WJik0EP9CQO28oAYKZWP/
234-
jhckhSOsc4+cMSi5b3OqlNiFiL164COTy8I5OLLG1nhIqWAUVYOjQDLlWRCG69xS
235-
VSuwY/kUqjW6vpvWP5j1kg==
236-
-----END PRIVATE KEY-----`)
237-
238157
var kubeConfig = []byte(`apiVersion: v1
239158
clusters:
240159
- cluster:

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)