@@ -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 .InjectCAFromSecretAnnotation ] = 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 {
@@ -254,6 +270,70 @@ func TestExtensionReconciler_discoverExtensionConfig(t *testing.T) {
254
270
})
255
271
}
256
272
273
+ func Test_reconcileCABundle (t * testing.T ) {
274
+ g := NewWithT (t )
275
+
276
+ scheme := runtime .NewScheme ()
277
+ g .Expect (corev1 .AddToScheme (scheme )).To (Succeed ())
278
+
279
+ tests := []struct {
280
+ name string
281
+ client client.Client
282
+ config * runtimev1.ExtensionConfig
283
+ wantCABundle []byte
284
+ wantErr bool
285
+ }{
286
+ {
287
+ name : "No-op because no annotation is set" ,
288
+ client : fake .NewClientBuilder ().WithScheme (scheme ).Build (),
289
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "" , "" ),
290
+ wantErr : false ,
291
+ },
292
+ {
293
+ name : "Inject ca-bundle" ,
294
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
295
+ fakeCASecret ("some-namespace" , "some-ca-secret" , []byte ("some-ca-data" )),
296
+ ).Build (),
297
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
298
+ wantCABundle : []byte (`some-ca-data` ),
299
+ wantErr : false ,
300
+ },
301
+ {
302
+ name : "Update ca-bundle" ,
303
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
304
+ fakeCASecret ("some-namespace" , "some-ca-secret" , []byte ("some-new-data" )),
305
+ ).Build (),
306
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "some-old-ca-data" ),
307
+ wantCABundle : []byte (`some-new-data` ),
308
+ wantErr : false ,
309
+ },
310
+ {
311
+ name : "Fail because secret does not exist" ,
312
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects ().Build (),
313
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
314
+ wantErr : true ,
315
+ },
316
+ {
317
+ name : "Fail because secret does not contain a ca.crt" ,
318
+ client : fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (
319
+ fakeCASecret ("some-namespace" , "some-ca-secret" , nil ),
320
+ ).Build (),
321
+ config : fakeCAInjectionRuntimeExtensionConfig ("some-namespace" , "some-extension-config" , "some-namespace/some-ca-secret" , "" ),
322
+ wantErr : true ,
323
+ },
324
+ }
325
+ for _ , tt := range tests {
326
+ t .Run (tt .name , func (t * testing.T ) {
327
+ g := NewWithT (t )
328
+
329
+ err := reconcileCABundle (context .TODO (), tt .client , tt .config )
330
+ g .Expect (err != nil ).To (Equal (tt .wantErr ))
331
+
332
+ g .Expect (tt .config .Spec .ClientConfig .CABundle ).To (Equal (tt .wantCABundle ))
333
+ })
334
+ }
335
+ }
336
+
257
337
func discoveryHandler (handlerList ... string ) func (http.ResponseWriter , * http.Request ) {
258
338
handlers := []runtimehooksv1.ExtensionHandler {}
259
339
for _ , name := range handlerList {
@@ -290,8 +370,9 @@ func fakeExtensionConfigForURL(namespace, name, url string) *runtimev1.Extension
290
370
APIVersion : runtimehooksv1 .GroupVersion .String (),
291
371
},
292
372
ObjectMeta : metav1.ObjectMeta {
293
- Name : name ,
294
- Namespace : namespace ,
373
+ Name : name ,
374
+ Namespace : namespace ,
375
+ Annotations : map [string ]string {},
295
376
},
296
377
Spec : runtimev1.ExtensionConfigSpec {
297
378
ClientConfig : runtimev1.ClientConfig {
@@ -302,9 +383,51 @@ func fakeExtensionConfigForURL(namespace, name, url string) *runtimev1.Extension
302
383
}
303
384
}
304
385
305
- func fakeExtensionServer (discoveryHandler func (w http.ResponseWriter , r * http.Request )) * httptest.Server {
386
+ func fakeSecureExtensionServer (discoveryHandler func (w http.ResponseWriter , r * http.Request )) ( * httptest.Server , error ) {
306
387
mux := http .NewServeMux ()
307
388
mux .HandleFunc ("/" , discoveryHandler )
308
- srv := httptest .NewServer (mux )
309
- return srv
389
+
390
+ sCert , err := tls .X509KeyPair (testcerts .ServerCert , testcerts .ServerKey )
391
+ if err != nil {
392
+ return nil , err
393
+ }
394
+ testServer := httptest .NewUnstartedServer (mux )
395
+ testServer .TLS = & tls.Config {
396
+ MinVersion : tls .VersionTLS13 ,
397
+ Certificates : []tls.Certificate {sCert },
398
+ }
399
+ testServer .StartTLS ()
400
+
401
+ return testServer , nil
402
+ }
403
+
404
+ func fakeCASecret (namespace , name string , caData []byte ) * corev1.Secret {
405
+ secret := & corev1.Secret {
406
+ ObjectMeta : metav1.ObjectMeta {
407
+ Name : name ,
408
+ Namespace : namespace ,
409
+ },
410
+ Data : map [string ][]byte {},
411
+ }
412
+ if caData != nil {
413
+ secret .Data ["ca.crt" ] = caData
414
+ }
415
+ return secret
416
+ }
417
+
418
+ func fakeCAInjectionRuntimeExtensionConfig (namespace , name , annotationString , caBundleData string ) * runtimev1.ExtensionConfig {
419
+ ext := & runtimev1.ExtensionConfig {
420
+ ObjectMeta : metav1.ObjectMeta {
421
+ Name : name ,
422
+ Namespace : namespace ,
423
+ Annotations : map [string ]string {},
424
+ },
425
+ }
426
+ if annotationString != "" {
427
+ ext .Annotations [runtimev1 .InjectCAFromSecretAnnotation ] = annotationString
428
+ }
429
+ if caBundleData != "" {
430
+ ext .Spec .ClientConfig .CABundle = []byte (caBundleData )
431
+ }
432
+ return ext
310
433
}
0 commit comments