k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/integration/examples/webhook_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package apiserver 18 19 import ( 20 "sync/atomic" 21 "testing" 22 "time" 23 24 admissionregistrationv1 "k8s.io/api/admissionregistration/v1" 25 26 v1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/util/wait" 29 auditinternal "k8s.io/apiserver/pkg/apis/audit" 30 "k8s.io/apiserver/pkg/audit" 31 "k8s.io/apiserver/pkg/authorization/authorizer" 32 "k8s.io/kubernetes/cmd/kube-apiserver/app/options" 33 "k8s.io/kubernetes/pkg/controlplane" 34 "k8s.io/kubernetes/pkg/controlplane/reconcilers" 35 "k8s.io/kubernetes/test/integration/framework" 36 "k8s.io/kubernetes/test/utils/ktesting" 37 ) 38 39 func TestWebhookLoopback(t *testing.T) { 40 webhookPath := "/webhook-test" 41 42 called := int32(0) 43 44 tCtx := ktesting.Init(t) 45 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{ 46 ModifyServerRunOptions: func(opts *options.ServerRunOptions) { 47 }, 48 ModifyServerConfig: func(config *controlplane.Config) { 49 // Avoid resolvable kubernetes service 50 config.Extra.EndpointReconcilerType = reconcilers.NoneEndpointReconcilerType 51 52 // Hook into audit to watch requests 53 config.ControlPlane.Generic.AuditBackend = auditSinkFunc(func(events ...*auditinternal.Event) {}) 54 config.ControlPlane.Generic.AuditPolicyRuleEvaluator = auditPolicyRuleEvaluator(func(attrs authorizer.Attributes) audit.RequestAuditConfig { 55 if attrs.GetPath() == webhookPath { 56 if attrs.GetUser().GetName() != "system:apiserver" { 57 t.Errorf("expected user %q, got %q", "system:apiserver", attrs.GetUser().GetName()) 58 } 59 atomic.AddInt32(&called, 1) 60 } 61 return audit.RequestAuditConfig{ 62 Level: auditinternal.LevelNone, 63 } 64 }) 65 }, 66 }) 67 defer tearDownFn() 68 69 fail := admissionregistrationv1.Fail 70 noSideEffects := admissionregistrationv1.SideEffectClassNone 71 _, err := client.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(tCtx, &admissionregistrationv1.MutatingWebhookConfiguration{ 72 ObjectMeta: metav1.ObjectMeta{Name: "webhooktest.example.com"}, 73 Webhooks: []admissionregistrationv1.MutatingWebhook{{ 74 Name: "webhooktest.example.com", 75 ClientConfig: admissionregistrationv1.WebhookClientConfig{ 76 Service: &admissionregistrationv1.ServiceReference{Namespace: "default", Name: "kubernetes", Path: &webhookPath}, 77 }, 78 Rules: []admissionregistrationv1.RuleWithOperations{{ 79 Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.OperationAll}, 80 Rule: admissionregistrationv1.Rule{APIGroups: []string{""}, APIVersions: []string{"v1"}, Resources: []string{"configmaps"}}, 81 }}, 82 FailurePolicy: &fail, 83 SideEffects: &noSideEffects, 84 AdmissionReviewVersions: []string{"v1"}, 85 }}, 86 }, metav1.CreateOptions{}) 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 err = wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (done bool, err error) { 92 _, err = client.CoreV1().ConfigMaps("default").Create(tCtx, &v1.ConfigMap{ 93 ObjectMeta: metav1.ObjectMeta{Name: "webhook-test"}, 94 Data: map[string]string{"invalid key": "value"}, 95 }, metav1.CreateOptions{}) 96 if err == nil { 97 t.Fatal("Unexpected success") 98 } 99 if called > 0 { 100 return true, nil 101 } 102 t.Logf("%v", err) 103 t.Logf("webhook not called yet, continuing...") 104 return false, nil 105 }) 106 if err != nil { 107 t.Fatal(err) 108 } 109 } 110 111 type auditPolicyRuleEvaluator func(authorizer.Attributes) audit.RequestAuditConfig 112 113 func (f auditPolicyRuleEvaluator) EvaluatePolicyRule(attrs authorizer.Attributes) audit.RequestAuditConfig { 114 return f(attrs) 115 } 116 117 type auditSinkFunc func(events ...*auditinternal.Event) 118 119 func (f auditSinkFunc) ProcessEvents(events ...*auditinternal.Event) bool { 120 f(events...) 121 return true 122 } 123 124 func (auditSinkFunc) Run(stopCh <-chan struct{}) error { 125 return nil 126 } 127 128 func (auditSinkFunc) Shutdown() { 129 } 130 131 func (auditSinkFunc) String() string { 132 return "" 133 }