@@ -76,7 +76,7 @@ const (
76
76
addedLabelValue = "yes"
77
77
)
78
78
79
- var _ = SIGDescribe ("AdmissionWebhook" , func () {
79
+ var _ = SIGDescribe ("AdmissionWebhook [Privileged:ClusterAdmin] " , func () {
80
80
var context * certContext
81
81
f := framework .NewDefaultFramework ("webhook" )
82
82
servicePort := int32 (8443 )
@@ -104,7 +104,15 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
104
104
cleanWebhookTest (client , namespaceName )
105
105
})
106
106
107
- ginkgo .It ("should include webhook resources in discovery documents" , func () {
107
+ /*
108
+ Release : v1.16
109
+ Testname: Admission webhook, discovery document
110
+ Description: The admissionregistration.k8s.io API group MUST exists in the /apis discovery document.
111
+ The admissionregistration.k8s.io/v1 API group/version MUST exists in the /apis discovery document.
112
+ The mutatingwebhookconfigurations and validatingwebhookconfigurations resources MUST exist in the
113
+ /apis/admissionregistration.k8s.io/v1 discovery document.
114
+ */
115
+ framework .ConformanceIt ("should include webhook resources in discovery documents" , func () {
108
116
{
109
117
ginkgo .By ("fetching the /apis discovery document" )
110
118
apiGroupList := & metav1.APIGroupList {}
@@ -175,19 +183,40 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
175
183
}
176
184
})
177
185
178
- ginkgo .It ("Should be able to deny pod and configmap creation" , func () {
186
+ /*
187
+ Release : v1.16
188
+ Testname: Admission webhook, deny create
189
+ Description: Register an admission webhook configuration that admits pod and configmap. Attempts to create
190
+ non-compliant pods and configmaps, or update/patch compliant pods and configmaps to be non-compliant MUST
191
+ be denied. An attempt to create a pod that causes a webhook to hang MUST result in a webhook timeout error,
192
+ and the pod creation MUST be denied. An attempt to create a non-compliant configmap in a whitelisted
193
+ namespace based on the webhook namespace selector MUST be allowed.
194
+ */
195
+ framework .ConformanceIt ("should be able to deny pod and configmap creation" , func () {
179
196
webhookCleanup := registerWebhook (f , f .UniqueName , context , servicePort )
180
197
defer webhookCleanup ()
181
198
testWebhook (f )
182
199
})
183
200
184
- ginkgo .It ("Should be able to deny attaching pod" , func () {
201
+ /*
202
+ Release : v1.16
203
+ Testname: Admission webhook, deny attach
204
+ Description: Register an admission webhook configuration that denies connecting to a pod's attach sub-resource.
205
+ Attempts to attach MUST be denied.
206
+ */
207
+ framework .ConformanceIt ("should be able to deny attaching pod" , func () {
185
208
webhookCleanup := registerWebhookForAttachingPod (f , f .UniqueName , context , servicePort )
186
209
defer webhookCleanup ()
187
210
testAttachingPodWebhook (f )
188
211
})
189
212
190
- ginkgo .It ("Should be able to deny custom resource creation and deletion" , func () {
213
+ /*
214
+ Release : v1.16
215
+ Testname: Admission webhook, deny custom resource create and delete
216
+ Description: Register an admission webhook configuration that denies creation, update and deletion of
217
+ custom resources. Attempts to create, update and delete custom resources MUST be denied.
218
+ */
219
+ framework .ConformanceIt ("should be able to deny custom resource creation, update and deletion" , func () {
191
220
testcrd , err := crd .CreateTestCRD (f )
192
221
if err != nil {
193
222
return
@@ -196,36 +225,68 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
196
225
webhookCleanup := registerWebhookForCustomResource (f , f .UniqueName , context , testcrd , servicePort )
197
226
defer webhookCleanup ()
198
227
testCustomResourceWebhook (f , testcrd .Crd , testcrd .DynamicClients ["v1" ])
199
- testBlockingCustomResourceDeletion (f , testcrd .Crd , testcrd .DynamicClients ["v1" ])
228
+ testBlockingCustomResourceUpdateDeletion (f , testcrd .Crd , testcrd .DynamicClients ["v1" ])
200
229
})
201
230
202
- ginkgo .It ("Should unconditionally reject operations on fail closed webhook" , func () {
231
+ /*
232
+ Release : v1.16
233
+ Testname: Admission webhook, fail closed
234
+ Description: Register a webhook with a fail closed policy and without CA bundle so that it cannot be called.
235
+ Attempt operations that require the admission webhook; all MUST be denied.
236
+ */
237
+ framework .ConformanceIt ("should unconditionally reject operations on fail closed webhook" , func () {
203
238
webhookCleanup := registerFailClosedWebhook (f , f .UniqueName , context , servicePort )
204
239
defer webhookCleanup ()
205
240
testFailClosedWebhook (f )
206
241
})
207
242
208
- ginkgo .It ("Should mutate configmap" , func () {
243
+ /*
244
+ Release : v1.16
245
+ Testname: Admission webhook, ordered mutation
246
+ Description: Register a mutating webhook configuration with two webhooks that admit configmaps, one that
247
+ adds a data key if the configmap already has a specific key, and another that adds a key if the key added by
248
+ the first webhook is present. Attempt to create a config map; both keys MUST be added to the config map.
249
+ */
250
+ framework .ConformanceIt ("should mutate configmap" , func () {
209
251
webhookCleanup := registerMutatingWebhookForConfigMap (f , f .UniqueName , context , servicePort )
210
252
defer webhookCleanup ()
211
253
testMutatingConfigMapWebhook (f )
212
254
})
213
255
214
- ginkgo .It ("Should mutate pod and apply defaults after mutation" , func () {
256
+ /*
257
+ Release : v1.16
258
+ Testname: Admission webhook, mutation with defaulting
259
+ Description: Register a mutating webhook that adds an InitContainer to pods. Attempt to create a pod;
260
+ the InitContainer MUST be added the TerminationMessagePolicy MUST be defaulted.
261
+ */
262
+ framework .ConformanceIt ("should mutate pod and apply defaults after mutation" , func () {
215
263
webhookCleanup := registerMutatingWebhookForPod (f , f .UniqueName , context , servicePort )
216
264
defer webhookCleanup ()
217
265
testMutatingPodWebhook (f )
218
266
})
219
267
220
- ginkgo .It ("Should not be able to mutate or prevent deletion of webhook configuration objects" , func () {
268
+ /*
269
+ Release : v1.16
270
+ Testname: Admission webhook, admission control not allowed on webhook configuration objects
271
+ Description: Register webhooks that mutate and deny deletion of webhook configuration objects. Attempt to create
272
+ and delete a webhook configuration object; both operations MUST be allowed and the webhook configuration object
273
+ MUST NOT be mutated the the webhooks.
274
+ */
275
+ framework .ConformanceIt ("should not be able to mutate or prevent deletion of webhook configuration objects" , func () {
221
276
validatingWebhookCleanup := registerValidatingWebhookForWebhookConfigurations (f , f .UniqueName + "blocking" , context , servicePort )
222
277
defer validatingWebhookCleanup ()
223
278
mutatingWebhookCleanup := registerMutatingWebhookForWebhookConfigurations (f , f .UniqueName + "blocking" , context , servicePort )
224
279
defer mutatingWebhookCleanup ()
225
280
testWebhooksForWebhookConfigurations (f , f .UniqueName , context , servicePort )
226
281
})
227
282
228
- ginkgo .It ("Should mutate custom resource" , func () {
283
+ /*
284
+ Release : v1.16
285
+ Testname: Admission webhook, mutate custom resource
286
+ Description: Register a webhook that mutates a custom resource. Attempt to create custom resource object;
287
+ the custom resource MUST be mutated.
288
+ */
289
+ framework .ConformanceIt ("should mutate custom resource" , func () {
229
290
testcrd , err := crd .CreateTestCRD (f )
230
291
if err != nil {
231
292
return
@@ -236,14 +297,28 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
236
297
testMutatingCustomResourceWebhook (f , testcrd .Crd , testcrd .DynamicClients ["v1" ], false )
237
298
})
238
299
239
- ginkgo .It ("Should deny crd creation" , func () {
300
+ /*
301
+ Release : v1.16
302
+ Testname: Admission webhook, deny custom resource definition
303
+ Description: Register a webhook that denies custom resource definition create. Attempt to create a
304
+ custom resource definition; the create request MUST be denied.
305
+ */
306
+ framework .ConformanceIt ("should deny crd creation" , func () {
240
307
crdWebhookCleanup := registerValidatingWebhookForCRD (f , f .UniqueName , context , servicePort )
241
308
defer crdWebhookCleanup ()
242
309
243
310
testCRDDenyWebhook (f )
244
311
})
245
312
246
- ginkgo .It ("Should mutate custom resource with different stored version" , func () {
313
+ /*
314
+ Release : v1.16
315
+ Testname: Admission webhook, mutate custom resource with different stored version
316
+ Description: Register a webhook that mutates custom resources on create and update. Register a custom resource
317
+ definition using v1 as stored version. Create a custom resource. Patch the custom resource definition to use v2 as
318
+ the stored version. Attempt to patch the custom resource with a new field and value; the patch MUST be applied
319
+ successfully.
320
+ */
321
+ framework .ConformanceIt ("should mutate custom resource with different stored version" , func () {
247
322
testcrd , err := createAdmissionWebhookMultiVersionTestCRDWithV1Storage (f )
248
323
if err != nil {
249
324
return
@@ -254,7 +329,14 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
254
329
testMultiVersionCustomResourceWebhook (f , testcrd )
255
330
})
256
331
257
- ginkgo .It ("Should mutate custom resource with pruning" , func () {
332
+ /*
333
+ Release : v1.16
334
+ Testname: Admission webhook, mutate custom resource with pruning
335
+ Description: Register mutating webhooks that adds fields to custom objects. Register a custom resource definition
336
+ with a schema that includes only one of the data keys added by the webhooks. Attempt to a custom resource;
337
+ the fields included in the schema MUST be present and field not included in the schema MUST NOT be present.
338
+ */
339
+ framework .ConformanceIt ("should mutate custom resource with pruning" , func () {
258
340
const prune = true
259
341
testcrd , err := createAdmissionWebhookMultiVersionTestCRDWithV1Storage (f , func (crd * apiextensionsv1.CustomResourceDefinition ) {
260
342
crd .Spec .PreserveUnknownFields = false
@@ -285,7 +367,16 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
285
367
testMutatingCustomResourceWebhook (f , testcrd .Crd , testcrd .DynamicClients ["v1" ], prune )
286
368
})
287
369
288
- ginkgo .It ("Should honor timeout" , func () {
370
+ /*
371
+ Release : v1.16
372
+ Testname: Admission webhook, honor timeout
373
+ Description: Using a webhook that waits 5 seconds before admitting objects, configure the webhook with combinations
374
+ of timeouts and failure policy values. Attempt to create a config map with each combination. Requests MUST
375
+ timeout if the configured webhook timeout is less than 5 seconds and failure policy is fail. Requests must not timeout if
376
+ the failure policy is ignore. Requests MUST NOT timeout if configured webhook timeout is 10 seconds (much longer
377
+ than the webhook wait duration).
378
+ */
379
+ framework .ConformanceIt ("should honor timeout" , func () {
289
380
policyFail := admissionregistrationv1 .Fail
290
381
policyIgnore := admissionregistrationv1 .Ignore
291
382
@@ -310,7 +401,14 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
310
401
slowWebhookCleanup ()
311
402
})
312
403
313
- ginkgo .It ("patching/updating a validating webhook should work" , func () {
404
+ /*
405
+ Release : v1.16
406
+ Testname: Admission webhook, update validating webhook
407
+ Description: Register a validating admission webhook configuration. Update the webhook to not apply to the create
408
+ operation and attempt to create an object; the webhook MUST NOT deny the create. Patch the webhook to apply to the
409
+ create operation again and attempt to create an object; the webhook MUST deny the create.
410
+ */
411
+ framework .ConformanceIt ("patching/updating a validating webhook should work" , func () {
314
412
client := f .ClientSet
315
413
admissionClient := client .AdmissionregistrationV1 ()
316
414
@@ -393,7 +491,14 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
393
491
framework .ExpectNoError (err , "Waiting for configMap in namespace %s to be denied creation by validating webhook" , f .Namespace .Name )
394
492
})
395
493
396
- ginkgo .It ("patching/updating a mutating webhook should work" , func () {
494
+ /*
495
+ Release : v1.16
496
+ Testname: Admission webhook, update mutating webhook
497
+ Description: Register a mutating admission webhook configuration. Update the webhook to not apply to the create
498
+ operation and attempt to create an object; the webhook MUST NOT mutate the object. Patch the webhook to apply to the
499
+ create operation again and attempt to create an object; the webhook MUST mutate the object.
500
+ */
501
+ framework .ConformanceIt ("patching/updating a mutating webhook should work" , func () {
397
502
client := f .ClientSet
398
503
admissionClient := client .AdmissionregistrationV1 ()
399
504
@@ -455,7 +560,15 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
455
560
framework .ExpectNoError (err , "Waiting for configMap in namespace %s to be mutated" , f .Namespace .Name )
456
561
})
457
562
458
- ginkgo .It ("listing validating webhooks should work" , func () {
563
+ /*
564
+ Release : v1.16
565
+ Testname: Admission webhook, list validating webhooks
566
+ Description: Create 10 validating webhook configurations, all with a label. Attempt to list the webhook
567
+ configurations matching the label; all the created webhook configurations MUST be present. Attempt to create an
568
+ object; the create MUST be denied. Attempt to remove the webhook configurations matching the label with deletecollection;
569
+ all webhook configurations MUST be deleted. Attempt to create an object; the create MUST NOT be denied.
570
+ */
571
+ framework .ConformanceIt ("listing validating webhooks should work" , func () {
459
572
testListSize := 10
460
573
testUUID := string (uuid .NewUUID ())
461
574
@@ -516,7 +629,15 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
516
629
framework .ExpectNoError (err , "Waiting for configMap in namespace %s to be allowed creation since there are no webhooks" , f .Namespace .Name )
517
630
})
518
631
519
- ginkgo .It ("listing mutating webhooks should work" , func () {
632
+ /*
633
+ Release : v1.16
634
+ Testname: Admission webhook, list mutating webhooks
635
+ Description: Create 10 mutating webhook configurations, all with a label. Attempt to list the webhook
636
+ configurations matching the label; all the created webhook configurations MUST be present. Attempt to create an
637
+ object; the object MUST be mutated. Attempt to remove the webhook configurations matching the label with deletecollection;
638
+ all webhook configurations MUST be deleted. Attempt to create an object; the object MUST NOT be mutated.
639
+ */
640
+ framework .ConformanceIt ("listing mutating webhooks should work" , func () {
520
641
testListSize := 10
521
642
testUUID := string (uuid .NewUUID ())
522
643
@@ -907,8 +1028,8 @@ func registerMutatingWebhookForPod(f *framework.Framework, configName string, co
907
1028
func testMutatingPodWebhook (f * framework.Framework ) {
908
1029
ginkgo .By ("create a pod that should be updated by the webhook" )
909
1030
client := f .ClientSet
910
- configMap := toBeMutatedPod (f )
911
- mutatedPod , err := client .CoreV1 ().Pods (f .Namespace .Name ).Create (configMap )
1031
+ pod := toBeMutatedPod (f )
1032
+ mutatedPod , err := client .CoreV1 ().Pods (f .Namespace .Name ).Create (pod )
912
1033
gomega .Expect (err ).To (gomega .BeNil ())
913
1034
if len (mutatedPod .Spec .InitContainers ) != 1 {
914
1035
e2elog .Failf ("expect pod to have 1 init container, got %#v" , mutatedPod .Spec .InitContainers )
@@ -1738,7 +1859,7 @@ func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1.Cust
1738
1859
}
1739
1860
}
1740
1861
1741
- func testBlockingCustomResourceDeletion (f * framework.Framework , crd * apiextensionsv1.CustomResourceDefinition , customResourceClient dynamic.ResourceInterface ) {
1862
+ func testBlockingCustomResourceUpdateDeletion (f * framework.Framework , crd * apiextensionsv1.CustomResourceDefinition , customResourceClient dynamic.ResourceInterface ) {
1742
1863
ginkgo .By ("Creating a custom resource whose deletion would be denied by the webhook" )
1743
1864
crInstanceName := "cr-instance-2"
1744
1865
crInstance := & unstructured.Unstructured {
@@ -1757,6 +1878,22 @@ func testBlockingCustomResourceDeletion(f *framework.Framework, crd *apiextensio
1757
1878
_ , err := customResourceClient .Create (crInstance , metav1.CreateOptions {})
1758
1879
framework .ExpectNoError (err , "failed to create custom resource %s in namespace: %s" , crInstanceName , f .Namespace .Name )
1759
1880
1881
+ ginkgo .By ("Updating the custom resource with disallowed data should be denied" )
1882
+ toNonCompliantFn := func (cr * unstructured.Unstructured ) {
1883
+ if _ , ok := cr .Object ["data" ]; ! ok {
1884
+ cr .Object ["data" ] = map [string ]interface {}{}
1885
+ }
1886
+ data := cr .Object ["data" ].(map [string ]interface {})
1887
+ data ["webhook-e2e-test" ] = "webhook-disallow"
1888
+ }
1889
+ _ , err = updateCustomResource (customResourceClient , f .Namespace .Name , crInstanceName , toNonCompliantFn )
1890
+ framework .ExpectError (err , "updating custom resource %s in namespace: %s should be denied" , crInstanceName , f .Namespace .Name )
1891
+
1892
+ expectedErrMsg := "the custom resource contains unwanted data"
1893
+ if ! strings .Contains (err .Error (), expectedErrMsg ) {
1894
+ e2elog .Failf ("expect error contains %q, got %q" , expectedErrMsg , err .Error ())
1895
+ }
1896
+
1760
1897
ginkgo .By ("Deleting the custom resource should be denied" )
1761
1898
err = customResourceClient .Delete (crInstanceName , & metav1.DeleteOptions {})
1762
1899
framework .ExpectError (err , "deleting custom resource %s in namespace: %s should be denied" , crInstanceName , f .Namespace .Name )
@@ -1860,8 +1997,19 @@ func testMultiVersionCustomResourceWebhook(f *framework.Framework, testcrd *crd.
1860
1997
1861
1998
ginkgo .By ("Patching the custom resource while v2 is storage version" )
1862
1999
crDummyPatch := fmt .Sprint (`[{ "op": "add", "path": "/dummy", "value": "test" }]` )
1863
- _ , err = testcrd .DynamicClients ["v2" ].Patch (crName , types .JSONPatchType , []byte (crDummyPatch ), metav1.PatchOptions {})
2000
+ mutatedCR , err : = testcrd .DynamicClients ["v2" ].Patch (crName , types .JSONPatchType , []byte (crDummyPatch ), metav1.PatchOptions {})
1864
2001
framework .ExpectNoError (err , "failed to patch custom resource %s in namespace: %s" , crName , f .Namespace .Name )
2002
+ expectedCRData := map [string ]interface {}{
2003
+ "mutation-start" : "yes" ,
2004
+ "mutation-stage-1" : "yes" ,
2005
+ "mutation-stage-2" : "yes" ,
2006
+ }
2007
+ if ! reflect .DeepEqual (expectedCRData , mutatedCR .Object ["data" ]) {
2008
+ e2elog .Failf ("\n expected %#v\n , got %#v\n " , expectedCRData , mutatedCR .Object ["data" ])
2009
+ }
2010
+ if ! reflect .DeepEqual ("test" , mutatedCR .Object ["dummy" ]) {
2011
+ e2elog .Failf ("\n expected %#v\n , got %#v\n " , "test" , mutatedCR .Object ["dummy" ])
2012
+ }
1865
2013
}
1866
2014
1867
2015
func registerValidatingWebhookForCRD (f * framework.Framework , configName string , context * certContext , servicePort int32 ) func () {
0 commit comments