@@ -17,6 +17,8 @@ limitations under the License.
17
17
package controllers
18
18
19
19
import (
20
+ "context"
21
+ "crypto/tls"
20
22
"encoding/json"
21
23
"net/http"
22
24
"net/http/httptest"
@@ -27,10 +29,13 @@ import (
27
29
"github.com/pkg/errors"
28
30
corev1 "k8s.io/api/core/v1"
29
31
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
+ "k8s.io/apimachinery/pkg/runtime"
33
+ "k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts"
30
34
utilfeature "k8s.io/component-base/featuregate/testing"
31
35
"k8s.io/utils/pointer"
32
36
ctrl "sigs.k8s.io/controller-runtime"
33
37
"sigs.k8s.io/controller-runtime/pkg/client"
38
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
34
39
35
40
runtimev1 "sigs.k8s.io/cluster-api/exp/runtime/api/v1alpha1"
36
41
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
@@ -67,9 +72,18 @@ func TestExtensionReconciler_Reconcile(t *testing.T) {
67
72
RuntimeClient : runtimeClient ,
68
73
}
69
74
70
- server := fakeExtensionServer (discoveryHandler ("first" , "second" , "third" ))
71
- extensionConfig := fakeExtensionConfigForURL (ns .Name , "ext1" , server .URL )
75
+ caCertSecret := fakeCASecret (ns .Name , "ext1-webhook" , testcerts .CACert )
76
+ server , err := fakeSecureExtensionServer (discoveryHandler ("first" , "second" , "third" ))
77
+ g .Expect (err ).NotTo (HaveOccurred ())
72
78
defer server .Close ()
79
+ extensionConfig := fakeExtensionConfigForURL (ns .Name , "ext1" , server .URL )
80
+ extensionConfig .Annotations [runtimev1 .CABundleInjectFromSecretAnnotation ] = caCertSecret .GetNamespace () + "/" + caCertSecret .GetName ()
81
+
82
+ // Create the secret which contains the ca certificate.
83
+ g .Expect (env .CreateAndWait (ctx , caCertSecret )).To (Succeed ())
84
+ defer func () {
85
+ g .Expect (env .CleanupAndWait (ctx , caCertSecret )).To (Succeed ())
86
+ }()
73
87
// Create the ExtensionConfig.
74
88
g .Expect (env .CreateAndWait (ctx , extensionConfig )).To (Succeed ())
75
89
defer func () {
@@ -120,7 +134,8 @@ func TestExtensionReconciler_Reconcile(t *testing.T) {
120
134
121
135
t .Run ("Successful reconcile and discovery on Extension update" , func (t * testing.T ) {
122
136
// Start a new ExtensionServer where the second handler is removed.
123
- updatedServer := fakeExtensionServer (discoveryHandler ("first" , "third" ))
137
+ updatedServer , err := fakeSecureExtensionServer (discoveryHandler ("first" , "third" ))
138
+ g .Expect (err ).ToNot (HaveOccurred ())
124
139
defer updatedServer .Close ()
125
140
// Close the original server it's no longer serving.
126
141
server .Close ()
@@ -195,7 +210,8 @@ func TestExtensionReconciler_discoverExtensionConfig(t *testing.T) {
195
210
registry := runtimeregistry .New ()
196
211
g .Expect (runtimehooksv1 .AddToCatalog (cat )).To (Succeed ())
197
212
extensionName := "ext1"
198
- srv1 := fakeExtensionServer (discoveryHandler ("first" ))
213
+ srv1 , err := fakeSecureExtensionServer (discoveryHandler ("first" ))
214
+ g .Expect (err ).ToNot (HaveOccurred ())
199
215
defer srv1 .Close ()
200
216
201
217
runtimeClient := runtimeclient .New (runtimeclient.Options {
@@ -228,7 +244,7 @@ func TestExtensionReconciler_discoverExtensionConfig(t *testing.T) {
228
244
extensionName := "ext1"
229
245
230
246
// Don't set up a server to run the extensionDiscovery handler.
231
- // srv1 := fakeExtensionServer (discoveryHandler("first"))
247
+ // srv1 := fakeSecureExtensionServer (discoveryHandler("first"))
232
248
// defer srv1.Close()
233
249
234
250
runtimeClient := runtimeclient .New (runtimeclient.Options {
@@ -290,8 +306,9 @@ func fakeExtensionConfigForURL(namespace, name, url string) *runtimev1.Extension
290
306
APIVersion : runtimehooksv1 .GroupVersion .String (),
291
307
},
292
308
ObjectMeta : metav1.ObjectMeta {
293
- Name : name ,
294
- Namespace : namespace ,
309
+ Name : name ,
310
+ Namespace : namespace ,
311
+ Annotations : map [string ]string {},
295
312
},
296
313
Spec : runtimev1.ExtensionConfigSpec {
297
314
ClientConfig : runtimev1.ClientConfig {
@@ -302,9 +319,114 @@ func fakeExtensionConfigForURL(namespace, name, url string) *runtimev1.Extension
302
319
}
303
320
}
304
321
305
- func fakeExtensionServer (discoveryHandler func (w http.ResponseWriter , r * http.Request )) * httptest.Server {
322
+ func fakeSecureExtensionServer (discoveryHandler func (w http.ResponseWriter , r * http.Request )) ( * httptest.Server , error ) {
306
323
mux := http .NewServeMux ()
307
324
mux .HandleFunc ("/" , discoveryHandler )
308
- srv := httptest .NewServer (mux )
309
- return srv
325
+
326
+ sCert , err := tls .X509KeyPair (testcerts .ServerCert , testcerts .ServerKey )
327
+ if err != nil {
328
+ return nil , err
329
+ }
330
+ testServer := httptest .NewUnstartedServer (mux )
331
+ testServer .TLS = & tls.Config {
332
+ Certificates : []tls.Certificate {sCert },
333
+ }
334
+ testServer .StartTLS ()
335
+
336
+ return testServer , nil
337
+ }
338
+
339
+ func fakeCASecret (namespace , name string , caData []byte ) * corev1.Secret {
340
+ secret := & corev1.Secret {
341
+ ObjectMeta : metav1.ObjectMeta {
342
+ Name : name ,
343
+ Namespace : namespace ,
344
+ },
345
+ Data : map [string ][]byte {},
346
+ }
347
+ if caData != nil {
348
+ secret .Data ["ca.crt" ] = caData
349
+ }
350
+ return secret
351
+ }
352
+
353
+ func Test_reconcileCABundle (t * testing.T ) {
354
+ g := NewWithT (t )
355
+
356
+ scheme := runtime .NewScheme ()
357
+ g .Expect (corev1 .AddToScheme (scheme )).To (Succeed ())
358
+
359
+ tests := []struct {
360
+ name string
361
+ client client.Client
362
+ config * runtimev1.ExtensionConfig
363
+ wantCABundle []byte
364
+ wantErr bool
365
+ }{
366
+ {
367
+ name : "No-op because no annotation is set" ,
368
+ client : fake .NewClientBuilder ().WithScheme (scheme ).Build (),
369
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "" , "" ),
370
+ wantErr : false ,
371
+ },
372
+ {
373
+ name : "Inject ca-bundle" ,
374
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
375
+ fakeCASecret ("some-namespace" , "some-ca-secret" , []byte ("some-ca-data" )),
376
+ ).Build (),
377
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
378
+ wantCABundle : []byte (`some-ca-data` ),
379
+ wantErr : false ,
380
+ },
381
+ {
382
+ name : "Update ca-bundle" ,
383
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
384
+ fakeCASecret ("some-namespace" , "some-ca-secret" , []byte ("some-new-data" )),
385
+ ).Build (),
386
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "some-old-ca-data" ),
387
+ wantCABundle : []byte (`some-new-data` ),
388
+ wantErr : false ,
389
+ },
390
+ {
391
+ name : "Fail because secret does not exist" ,
392
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects ().Build (),
393
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
394
+ wantErr : true ,
395
+ },
396
+ {
397
+ name : "Fail because secret does not contain a ca.crt" ,
398
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
399
+ fakeCASecret ("some-namespace" , "some-ca-secret" , nil ),
400
+ ).Build (),
401
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
402
+ wantErr : true ,
403
+ },
404
+ }
405
+ for _ , tt := range tests {
406
+ t .Run (tt .name , func (t * testing.T ) {
407
+ g := NewWithT (t )
408
+
409
+ err := reconcileCABundle (context .TODO (), tt .client , tt .config )
410
+ g .Expect (err != nil ).To (Equal (tt .wantErr ))
411
+
412
+ g .Expect (tt .config .Spec .ClientConfig .CABundle ).To (Equal (tt .wantCABundle ))
413
+ })
414
+ }
415
+ }
416
+
417
+ func fakeCAInjectionRuntimeExtensionConfig (namespace , name , annotationString , caBundleData string ) * runtimev1.ExtensionConfig {
418
+ ext := & runtimev1.ExtensionConfig {
419
+ ObjectMeta : metav1.ObjectMeta {
420
+ Name : name ,
421
+ Namespace : namespace ,
422
+ Annotations : map [string ]string {},
423
+ },
424
+ }
425
+ if annotationString != "" {
426
+ ext .Annotations [runtimev1 .CABundleInjectFromSecretAnnotation ] = annotationString
427
+ }
428
+ if caBundleData != "" {
429
+ ext .Spec .ClientConfig .CABundle = []byte (caBundleData )
430
+ }
431
+ return ext
310
432
}
0 commit comments