Skip to content

Commit b3a9b80

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request kubernetes#53823 from deads2k/admission-01-allow-fail
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. allow fail close webhook admission Webhook admission needs to allow failing closed. Even in an alpha state, I don't want to be one DDOS away from having an exposed cluster. /assign caesarxuchao /assign sttts
2 parents 900c076 + f81b600 commit b3a9b80

File tree

4 files changed

+90
-25
lines changed

4 files changed

+90
-25
lines changed

pkg/apis/admissionregistration/validation/validation.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,17 @@ func validateExternalAdmissionHook(hook *admissionregistration.ExternalAdmission
179179
for i, rule := range hook.Rules {
180180
allErrors = append(allErrors, validateRuleWithOperations(&rule, fldPath.Child("rules").Index(i))...)
181181
}
182-
// TODO: relax the validation rule when admissionregistration is beta.
183-
if hook.FailurePolicy != nil && *hook.FailurePolicy != admissionregistration.Ignore {
184-
allErrors = append(allErrors, field.NotSupported(fldPath.Child("failurePolicy"), *hook.FailurePolicy, []string{string(admissionregistration.Ignore)}))
182+
if hook.FailurePolicy != nil && !supportedFailurePolicies.Has(string(*hook.FailurePolicy)) {
183+
allErrors = append(allErrors, field.NotSupported(fldPath.Child("failurePolicy"), *hook.FailurePolicy, supportedFailurePolicies.List()))
185184
}
186185
return allErrors
187186
}
188187

188+
var supportedFailurePolicies = sets.NewString(
189+
string(admissionregistration.Ignore),
190+
string(admissionregistration.Fail),
191+
)
192+
189193
var supportedOperations = sets.NewString(
190194
string(admissionregistration.OperationAll),
191195
string(admissionregistration.Create),

pkg/apis/admissionregistration/validation/validation_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,18 +469,18 @@ func TestValidateExternalAdmissionHookConfiguration(t *testing.T) {
469469
expectedError: `externalAdmissionHooks[0].rules[0].resources: Invalid value: []string{"*/*", "a"}: if '*/*' is present, must not specify other resources`,
470470
},
471471
{
472-
name: "FailurePolicy can only be \"Ignore\"",
472+
name: "FailurePolicy can only be \"Ignore\" or \"Fail\"",
473473
config: getExternalAdmissionHookConfiguration(
474474
[]admissionregistration.ExternalAdmissionHook{
475475
{
476476
Name: "webhook.k8s.io",
477477
FailurePolicy: func() *admissionregistration.FailurePolicyType {
478-
r := admissionregistration.Fail
478+
r := admissionregistration.FailurePolicyType("other")
479479
return &r
480480
}(),
481481
},
482482
}),
483-
expectedError: `failurePolicy: Unsupported value: "Fail": supported values: "Ignore"`,
483+
expectedError: `externalAdmissionHooks[0].failurePolicy: Unsupported value: "other": supported values: "Fail", "Ignore"`,
484484
},
485485
}
486486
for _, test := range tests {

plugin/pkg/admission/webhook/admission.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,28 @@ func (a *GenericAdmissionWebhook) Admit(attr admission.Attributes) error {
192192
for i := range hooks {
193193
go func(hook *v1alpha1.ExternalAdmissionHook) {
194194
defer wg.Done()
195-
if err := a.callHook(ctx, hook, attr); err == nil {
195+
196+
err := a.callHook(ctx, hook, attr)
197+
if err == nil {
196198
return
197-
} else if callErr, ok := err.(*ErrCallingWebhook); ok {
198-
glog.Warningf("Failed calling webhook %v: %v", hook.Name, callErr)
199-
utilruntime.HandleError(callErr)
200-
// Since we are failing open to begin with, we do not send an error down the channel
201-
} else {
202-
glog.Warningf("rejected by webhook %v %t: %v", hook.Name, err, err)
199+
}
200+
201+
ignoreClientCallFailures := hook.FailurePolicy == nil || *hook.FailurePolicy == v1alpha1.Ignore
202+
if callErr, ok := err.(*ErrCallingWebhook); ok {
203+
if ignoreClientCallFailures {
204+
glog.Warningf("Failed calling webhook, failing open %v: %v", hook.Name, callErr)
205+
utilruntime.HandleError(callErr)
206+
// Since we are failing open to begin with, we do not send an error down the channel
207+
return
208+
}
209+
210+
glog.Warningf("Failed calling webhook, failing closed %v: %v", hook.Name, err)
203211
errCh <- err
212+
return
204213
}
214+
215+
glog.Warningf("rejected by webhook %v %t: %v", hook.Name, err, err)
216+
errCh <- err
205217
}(&hooks[i])
206218
}
207219
wg.Wait()

plugin/pkg/admission/webhook/admission_test.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ func TestAdmit(t *testing.T) {
144144
},
145145
}}
146146

147+
policyFail := registrationv1alpha1.Fail
148+
policyIgnore := registrationv1alpha1.Ignore
149+
147150
table := map[string]test{
148151
"no match": {
149152
hookSource: fakeHookSource{
@@ -192,6 +195,28 @@ func TestAdmit(t *testing.T) {
192195
errorContains: "you shall not pass",
193196
},
194197
"match & fail (but allow because fail open)": {
198+
hookSource: fakeHookSource{
199+
hooks: []registrationv1alpha1.ExternalAdmissionHook{{
200+
Name: "internalErr A",
201+
ClientConfig: ccfg,
202+
Rules: matchEverythingRules,
203+
FailurePolicy: &policyIgnore,
204+
}, {
205+
Name: "internalErr B",
206+
ClientConfig: ccfg,
207+
Rules: matchEverythingRules,
208+
FailurePolicy: &policyIgnore,
209+
}, {
210+
Name: "internalErr C",
211+
ClientConfig: ccfg,
212+
Rules: matchEverythingRules,
213+
FailurePolicy: &policyIgnore,
214+
}},
215+
},
216+
path: "internalErr",
217+
expectAllow: true,
218+
},
219+
"match & fail (but allow because fail open on nil)": {
195220
hookSource: fakeHookSource{
196221
hooks: []registrationv1alpha1.ExternalAdmissionHook{{
197222
Name: "internalErr A",
@@ -210,23 +235,47 @@ func TestAdmit(t *testing.T) {
210235
path: "internalErr",
211236
expectAllow: true,
212237
},
238+
"match & fail (but fail because fail closed)": {
239+
hookSource: fakeHookSource{
240+
hooks: []registrationv1alpha1.ExternalAdmissionHook{{
241+
Name: "internalErr A",
242+
ClientConfig: ccfg,
243+
Rules: matchEverythingRules,
244+
FailurePolicy: &policyFail,
245+
}, {
246+
Name: "internalErr B",
247+
ClientConfig: ccfg,
248+
Rules: matchEverythingRules,
249+
FailurePolicy: &policyFail,
250+
}, {
251+
Name: "internalErr C",
252+
ClientConfig: ccfg,
253+
Rules: matchEverythingRules,
254+
FailurePolicy: &policyFail,
255+
}},
256+
},
257+
path: "internalErr",
258+
expectAllow: false,
259+
},
213260
}
214261

215262
for name, tt := range table {
216-
wh.hookSource = &tt.hookSource
217-
wh.serviceResolver = fakeServiceResolver{base: *serverURL, path: tt.path}
218-
wh.SetScheme(legacyscheme.Scheme)
263+
t.Run(name, func(t *testing.T) {
264+
wh.hookSource = &tt.hookSource
265+
wh.serviceResolver = fakeServiceResolver{base: *serverURL, path: tt.path}
266+
wh.SetScheme(legacyscheme.Scheme)
219267

220-
err = wh.Admit(admission.NewAttributesRecord(&object, &oldObject, kind, namespace, name, resource, subResource, operation, &userInfo))
221-
if tt.expectAllow != (err == nil) {
222-
t.Errorf("%q: expected allowed=%v, but got err=%v", name, tt.expectAllow, err)
223-
}
224-
// ErrWebhookRejected is not an error for our purposes
225-
if tt.errorContains != "" {
226-
if err == nil || !strings.Contains(err.Error(), tt.errorContains) {
227-
t.Errorf("%q: expected an error saying %q, but got %v", name, tt.errorContains, err)
268+
err = wh.Admit(admission.NewAttributesRecord(&object, &oldObject, kind, namespace, name, resource, subResource, operation, &userInfo))
269+
if tt.expectAllow != (err == nil) {
270+
t.Errorf("expected allowed=%v, but got err=%v", tt.expectAllow, err)
228271
}
229-
}
272+
// ErrWebhookRejected is not an error for our purposes
273+
if tt.errorContains != "" {
274+
if err == nil || !strings.Contains(err.Error(), tt.errorContains) {
275+
t.Errorf(" expected an error saying %q, but got %v", tt.errorContains, err)
276+
}
277+
}
278+
})
230279
}
231280
}
232281

0 commit comments

Comments
 (0)