Skip to content

Commit a089146

Browse files
authored
Merge pull request #802 from liggitt/admission
update webhook admission proposal with "convert to webhook-requested version"
2 parents 8087860 + 4219262 commit a089146

File tree

1 file changed

+132
-1
lines changed

1 file changed

+132
-1
lines changed

keps/sig-api-machinery/00xx-admission-webhooks-to-ga.md

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,115 @@ Since the apiserver can convert between all of the versions by which a resource
346346
is made available, this situation can be improved by having the apiserver
347347
convert resources to the group/versions a webhook registered for.
348348

349-
The API representation and behavior for this feature is still under design and will be updated/approved here prior to implementation.
349+
Because admission can be used for out-of-tree defaulting and field enforcement,
350+
admission plugins may intentionally target specific versions of resources.
351+
A `matchPolicy` field will be added to the webhook configuration object,
352+
allowing a configuration to specify whether the apiserver should only route requests
353+
which exactly match the specified rules to the webhook, or whether it should route
354+
requests for equivalent resources via different API groups or versions as well.
355+
For safety, this field defaults to `Exact` in `v1beta1`. In `v1`, we can default it to `Equivalent`.
356+
357+
```golang
358+
// Webhook describes an admission webhook and the resources and operations it applies to.
359+
type Webhook struct {
360+
...
361+
// matchPolicy defines how the "rules" field is applied when a request is made
362+
// to a different API group or version of a resource listed in "rules".
363+
// Allowed values are "Exact" or "Equivalent".
364+
// - Exact: match requests only if they exactly match a given rule. For example, if an object can be modified
365+
// via API versions v1 and v2, and "rules" only includes "v1", do not send a request to "v2" to the webhook.
366+
// - Equivalent: match requests if they modify a resource listed in rules via another API group or version.
367+
// For example, if an object can be modified via API versions v1 and v2, and "rules" only includes "v1",
368+
// a request to "v2" should be converted to "v1" and sent to the webhook.
369+
// Defaults to "Exact"
370+
// +optional
371+
MatchPolicy *MatchPolicyType `json:"matchPolicy,omitempty"`
372+
```
373+
374+
The apiserver will do the following:
375+
376+
1. For each resource, compute the set of other resources that access or affect the same data, and the kind of the expected object. For example:
377+
* `apps,v1,deployments` (`apiVersion: apps/v1, kind: Deployment`) is also available via:
378+
* `apps,v1beta2,deployments` (`apiVersion: apps/v1beta2, kind: Deployment`)
379+
* `apps,v1beta1,deployments` (`apiVersion: apps/v1beta1, kind: Deployment`)
380+
* `extensions,v1beta1,deployments` (`apiVersion: extensions/v1beta1, kind: Deployment`)
381+
* `apps,v1,deployments/scale` (`apiVersion: autoscaling/v1, kind: Scale`) is also available via:
382+
* `apps,v1beta2,deployments/scale` (`apiVersion: apps/v1beta2, kind: Scale`)
383+
* `apps,v1beta1,deployments/scale` (`apiVersion: apps/v1beta1, kind: Scale`)
384+
* `extensions,v1beta1,deployments/scale` (`apiVersion: extensions/v1beta1, kind: Scale`)
385+
2. When evaluating whether to dispatch an incoming request to a webhook with
386+
`matchPolicy: Equivalent`, check the request's resource *and* all equivalent
387+
resources against the ones the webhook had registered for. If needed, convert
388+
the incoming object to one the webhook indicated it understood.
389+
390+
The `AdmissionRequest` sent to a webhook includes the fully-qualified
391+
kind (group/version/kind) and resource (group/version/resource):
392+
393+
```golang
394+
type AdmissionRequest struct {
395+
...
396+
// Kind is the type of object being manipulated. For example: Pod
397+
Kind metav1.GroupVersionKind `json:"kind" protobuf:"bytes,2,opt,name=kind"`
398+
// Resource is the name of the resource being requested. This is not the kind. For example: pods
399+
Resource metav1.GroupVersionResource `json:"resource" protobuf:"bytes,3,opt,name=resource"`
400+
// SubResource is the name of the subresource being requested. This is a different resource, scoped to the parent
401+
// resource, but it may have a different kind. For instance, /pods has the resource "pods" and the kind "Pod", while
402+
// /pods/foo/status has the resource "pods", the sub resource "status", and the kind "Pod" (because status operates on
403+
// pods). The binding resource for a pod though may be /pods/foo/binding, which has resource "pods", subresource
404+
// "binding", and kind "Binding".
405+
// +optional
406+
SubResource string `json:"subResource,omitempty" protobuf:"bytes,4,opt,name=subResource"`
407+
```
408+
409+
Prior to this conversion feature, the resource and kind of the request made to the
410+
API server, and the resource and kind sent in the AdmissionRequest were identical.
411+
412+
When a conversion occurs and the object we send to the webhook is a different kind
413+
than was sent to the API server, or the resource the webhook registered for is different
414+
than the request made to the API server, we have three options for communicating that to the webhook:
415+
1. Do not expose that fact to the webhook:
416+
* Set AdmissionRequest `kind` to the converted kind
417+
* Set AdmissionRequest `resource` to the registered-for resource
418+
2. Expose that fact to the webhook using the existing fields:
419+
* Set AdmissionRequest `kind` to the API request's kind (not matching the object in the AdmissionRequest)
420+
* Set AdmissionRequest `resource` to the API request's resource (not matching the registered-for resource)
421+
3. Expose that fact to the webhook using new AdmissionRequest fields:
422+
* Set AdmissionRequest `kind` to the converted kind
423+
* Set AdmissionRequest `requestKind` to the API request's kind
424+
* Set AdmissionRequest `resource` to the registered-for resource
425+
* Set AdmissionRequest `requestResource` to the API request's resource
426+
427+
Option 1 loses information the webhook could use (for example, to enforce different validation or defaulting rules for newer APIs).
428+
429+
Option 2 risks breaking webhook logic by sending it resources it did not register for, and kinds it did not expect.
430+
431+
Option 3 is preferred, and is the safest option that preserves information for use by the webhook.
432+
433+
To support this, three fields will be added to AdmissionRequest, and populated with the original request's kind, resource, and subResource:
434+
435+
```golang
436+
type AdmissionRequest struct {
437+
...
438+
// RequestKind is the type of object being manipulated by the the original API request. For example: Pod
439+
// If this differs from the value in "kind", an equivalent match and conversion was performed.
440+
// See documentation for the "matchPolicy" field in the webhook configuration type.
441+
// +optional
442+
RequestKind *metav1.GroupVersionKind `json:"requestKind,omitempty"`
443+
// RequestResource is the name of the resource being requested by the the original API request. This is not the kind. For example: ""/v1/pods
444+
// If this differs from the value in "resource", an equivalent match and conversion was performed.
445+
// See documentation for the "matchPolicy" field in the webhook configuration type.
446+
// +optional
447+
RequestResource *metav1.GroupVersionResource `json:"requestResource,omitempty"`
448+
// RequestSubResource is the name of the subresource being requested by the the original API request. This is a different resource, scoped to the parent
449+
// resource, but it may have a different kind. For instance, /pods has the resource "pods" and the kind "Pod", while
450+
// /pods/foo/status has the resource "pods", the sub resource "status", and the kind "Pod" (because status operates on
451+
// pods). The binding resource for a pod though may be /pods/foo/binding, which has resource "pods", subresource
452+
// "binding", and kind "Binding".
453+
// If this differs from the value in "subResource", an equivalent match and conversion was performed.
454+
// See documentation for the "matchPolicy" field in the webhook configuration type.
455+
// +optional
456+
RequestSubResource string `json:"requestSubResource,omitempty"`
457+
```
350458
351459
## V1 API
352460
@@ -410,6 +518,17 @@ type Rule struct {
410518
Scope ScopeType `json:"scope,omitempty" protobuf:"bytes,3,opt,name=scope"`
411519
}
412520

521+
type ConversionPolicyType string
522+
523+
const (
524+
// ConversionIgnore means that requests that do not match a webhook's rules but could be
525+
// converted to a resource the webhook registered for, should be ignored.
526+
ConversionIgnore ConversionPolicyType = "Ignore"
527+
// ConversionConvert means that requests that do not match a webhook's rules but could be
528+
// converted to a resource the webhook registered for, should be converted and sent to the webhook.
529+
ConversionConvert ConversionPolicyType = "Convert"
530+
)
531+
413532
type FailurePolicyType string
414533

415534
const (
@@ -516,6 +635,18 @@ type Webhook struct {
516635
// on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects.
517636
Rules []RuleWithOperations `json:"rules,omitempty" protobuf:"bytes,3,rep,name=rules"`
518637

638+
// matchPolicy defines how the "rules" field is applied when a request is made
639+
// to a different API group or version of a resource listed in "rules".
640+
// Allowed values are "Exact" or "Equivalent".
641+
// - Exact: match requests only if they exactly match a given rule. For example, if an object can be modified
642+
// via API version v1 and v2, and "rules" only includes "v1", do not send a request to "v2" to the webhook.
643+
// - Equivalent: match requests if they modify a resource listed in rules via another API group or version.
644+
// For example, if an object can be modified via API version v1 and v2, and "rules" only includes "v1",
645+
// a request to "v2" should be converted to "v1" and sent to the webhook.
646+
// Defaults to "Equivalent"
647+
// +optional
648+
MatchPolicy *MatchPolicyType `json:"matchPolicy,omitempty"`
649+
519650
// FailurePolicy defines how unrecognized errors from the admission endpoint are handled -
520651
// allowed values are Ignore or Fail. Defaults to Ignore.
521652
// +optional

0 commit comments

Comments
 (0)