k8s.io/apiserver@v0.31.1/pkg/admission/audit_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 admission 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 "testing" 24 25 "k8s.io/apimachinery/pkg/runtime/schema" 26 auditinternal "k8s.io/apiserver/pkg/apis/audit" 27 "k8s.io/apiserver/pkg/audit" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 // fakeHandler implements Interface 34 type fakeHandler struct { 35 // return value of Admit() 36 admit error 37 // annotations add to attributesRecord during Admit() phase 38 admitAnnotations map[string]string 39 // return value of Validate() 40 validate error 41 // annotations add to attributesRecord during Validate() phase 42 validateAnnotations map[string]string 43 // return value of Handles() 44 handles bool 45 } 46 47 var _ Interface = &fakeHandler{} 48 var _ MutationInterface = &fakeHandler{} 49 var _ ValidationInterface = &fakeHandler{} 50 51 func (h fakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { 52 for k, v := range h.admitAnnotations { 53 a.AddAnnotation(k, v) 54 } 55 return h.admit 56 } 57 58 func (h fakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { 59 for k, v := range h.validateAnnotations { 60 a.AddAnnotation(k, v) 61 } 62 return h.validate 63 } 64 65 func (h fakeHandler) Handles(o Operation) bool { 66 return h.handles 67 } 68 69 func attributes() Attributes { 70 return NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", nil, false, nil) 71 } 72 73 func TestWithAudit(t *testing.T) { 74 var testCases = map[string]struct { 75 admit error 76 admitAnnotations map[string]string 77 validate error 78 validateAnnotations map[string]string 79 handles bool 80 }{ 81 "not handle": { 82 nil, 83 nil, 84 nil, 85 nil, 86 false, 87 }, 88 "allow": { 89 nil, 90 nil, 91 nil, 92 nil, 93 true, 94 }, 95 "allow with annotations": { 96 nil, 97 map[string]string{ 98 "plugin.example.com/foo": "bar", 99 }, 100 nil, 101 nil, 102 true, 103 }, 104 "allow with annotations overwrite": { 105 nil, 106 map[string]string{ 107 "plugin.example.com/foo": "bar", 108 }, 109 nil, 110 map[string]string{ 111 "plugin.example.com/foo": "bar", 112 }, 113 true, 114 }, 115 "forbidden error": { 116 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 117 nil, 118 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 119 nil, 120 true, 121 }, 122 "forbidden error with annotations": { 123 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 124 nil, 125 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 126 map[string]string{ 127 "plugin.example.com/foo": "bar", 128 }, 129 true, 130 }, 131 "forbidden error with annotations overwrite": { 132 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 133 map[string]string{ 134 "plugin.example.com/foo": "bar", 135 }, 136 NewForbidden(attributes(), fmt.Errorf("quota exceeded")), 137 map[string]string{ 138 "plugin.example.com/foo": "bar", 139 }, 140 true, 141 }, 142 } 143 for tcName, tc := range testCases { 144 var handler Interface = fakeHandler{tc.admit, tc.admitAnnotations, tc.validate, tc.validateAnnotations, tc.handles} 145 ctx := audit.WithAuditContext(context.Background()) 146 ac := audit.AuditContextFrom(ctx) 147 ae := &ac.Event 148 ae.Level = auditinternal.LevelMetadata 149 auditHandler := WithAudit(handler) 150 a := attributes() 151 152 assert.Equal(t, handler.Handles(Create), auditHandler.Handles(Create), tcName+": WithAudit decorator should not effect the return value") 153 154 mutator, ok := handler.(MutationInterface) 155 require.True(t, ok) 156 auditMutator, ok := auditHandler.(MutationInterface) 157 require.True(t, ok) 158 assert.Equal(t, mutator.Admit(ctx, a, nil), auditMutator.Admit(ctx, a, nil), tcName+": WithAudit decorator should not effect the return value") 159 160 validator, ok := handler.(ValidationInterface) 161 require.True(t, ok) 162 auditValidator, ok := auditHandler.(ValidationInterface) 163 require.True(t, ok) 164 assert.Equal(t, validator.Validate(ctx, a, nil), auditValidator.Validate(ctx, a, nil), tcName+": WithAudit decorator should not effect the return value") 165 166 annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations)) 167 for k, v := range tc.admitAnnotations { 168 annotations[k] = v 169 } 170 for k, v := range tc.validateAnnotations { 171 annotations[k] = v 172 } 173 if len(annotations) == 0 { 174 assert.Nil(t, ae.Annotations, tcName+": unexptected annotations set in audit event") 175 } else { 176 assert.Equal(t, annotations, ae.Annotations, tcName+": unexptected annotations set in audit event") 177 } 178 } 179 } 180 181 func TestWithAuditConcurrency(t *testing.T) { 182 admitAnnotations := map[string]string{ 183 "plugin.example.com/foo": "foo", 184 "plugin.example.com/bar": "bar", 185 "plugin.example.com/baz": "baz", 186 "plugin.example.com/qux": "qux", 187 } 188 var handler Interface = fakeHandler{admitAnnotations: admitAnnotations, handles: true} 189 ctx := audit.WithAuditContext(context.Background()) 190 ac := audit.AuditContextFrom(ctx) 191 ac.Event.Level = auditinternal.LevelMetadata 192 auditHandler := WithAudit(handler) 193 a := attributes() 194 195 // Simulate the scenario store.DeleteCollection 196 workers := 2 197 wg := &sync.WaitGroup{} 198 wg.Add(workers) 199 for i := 0; i < workers; i++ { 200 go func() { 201 defer wg.Done() 202 mutator, ok := handler.(MutationInterface) 203 require.True(t, ok) 204 auditMutator, ok := auditHandler.(MutationInterface) 205 require.True(t, ok) 206 assert.Equal(t, mutator.Admit(ctx, a, nil), auditMutator.Admit(ctx, a, nil), "WithAudit decorator should not effect the return value") 207 }() 208 } 209 wg.Wait() 210 }