diff options
| author | Chao Xu <xuchao@google.com> | 2017-05-02 13:29:30 -0700 |
|---|---|---|
| committer | Chao Xu <xuchao@google.com> | 2017-05-09 17:33:10 -0700 |
| commit | b81ec0a141338dd6e21d43bda422e67a91c1442e (patch) | |
| tree | 0c709ccc4d355383fdb48b0a05209d145d443ded | |
| parent | 2a9aa2e5b035026c0347112304f02ae4feeb132b (diff) | |
proposal for dynamic admission controller configuration
| -rw-r--r-- | contributors/design-proposals/dynamic-admission-control-configuration.md | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/contributors/design-proposals/dynamic-admission-control-configuration.md b/contributors/design-proposals/dynamic-admission-control-configuration.md new file mode 100644 index 00000000..bb9b231e --- /dev/null +++ b/contributors/design-proposals/dynamic-admission-control-configuration.md @@ -0,0 +1,202 @@ +# Dynamic admission control configuration + +## Background + +[#132](https://github.com/kubernetes/community/pull/132) proposed making +admission control extensible. In the proposal, the `initializer admission +controller` and the `generic webhook admission controller` are the two +controllers that set default initializers and external admission hooks for +resources newly created. These two admission controllers are in the same binary +as the apiserver. This [section](https://github.com/smarterclayton/community/blob/be132e88f7597ab3927b788a3de6d5ab6de673d2/contributors/design-proposals/admission_control_extension.md#dynamic-configuration) +of #132 gave a preliminary design of the dynamic configuration of the list of +the default admission controls. This document hashes out the implementation +details. + +## Goals + +* Admins are able to predict what initializers/webhooks will be applied to newly + created objects. + +* Do not block the entire cluster if the intializers/webhooks are not ready + after registration. + +## Specification + +We assume initializers could be "fail open". We need to update #132 if this is +accepted. + +The schema is copied from +[#132](https://github.com/kubernetes/community/pull/132) with a few +modifications. + +```golang +type AdmissionControlConfiguration struct { + TypeMeta // although this object could simply be serialized like ComponentConfig + + // ResourceInitializers is a list of resources and their default initializers + ResourceInitializers []ResourceDefaultInitializer + + ExternalAdmissionHooks []ExternalAdmissionHook +} + +// Because the order of initializers matters, and each resource might need +// differnt order, the ResourceDefaultInitializers are indexed by Resource. +type ResourceDefaultInitializer struct { + // Resource identifies the type of resource to be initialized that should be + // initialized + Resource GroupResource + // Initializers are the default names that will be registered to this resource + Initializers []Initializer +} + +type Initializer struct { + // Name is the string that will be registered to the resource that needs + // initialization. + Name string + + // **Optional for alpha implement** + // FailurePolicy defines what happens if there is no initializer controller + // takes action. Allowed values are Ignore, or Fail. If "Ignore" is set, + // apiserver removes initilizer from the initializers list of the resource + // if the timeout is reached; If "Fail" is set, apiserver returns timeout + // error if the timeout is reached. + FailurePolicy FailurePolicyType + + // **Optional for alpha implement** + // If timeout is reached, the intializer is removed from the resource's + // initializer list by the apiserver. + // Default to XXX seconds. + Timeout *int64 +} + +type ExternalAdmissionHook struct { + // Operations is the list of operations this hook will be invoked on - Create, Update, or * + // for all operations. Defaults to '*'. + Operations []string + // Resources are the resources this hook should be invoked on. '*' is all resources. + Resources []string + // Subresources are the list of subresources this hook should be invoked on. '*' is all resources. + Subresources []string + + // ClientConfig defines how to talk to the hook. + ClientConfig AdmissionHookClientConfig + + // FailurePolicy defines how unrecognized errors from the admission endpoint are handled - + // allowed values are Ignore, Retry, Fail. Default value is Fail + FailurePolicy FailurePolicyType +} + +// AdmissionHookClientConfig contains the information to make a TLS +// connection with the webhook +// **very similar to the schema of kubeconfig** +type AdmissionHookClientConfig struct { + // Address of the external admission hook, could be a host string, + // a host:port pair, or a URL. + Address string + // ClientCertificate is the path to a client cert file for TLS. + ClientCertificate string + // ClientCertificateData contains PEM-encoded data from a client cert file + for TLS. Overrides ClientCertificate + ClientCertificateData []byte + // ClientKey is the path to a client key file for TLS. + ClientKey string + // ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey + ClientKeyData []byte + // CertificateAuthority is the path to a cert file for the certificate authority. + CertificateAuthority string + // CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority + CertificateAuthorityData []byte +} +``` + +## Synchronization of AdmissionControlConfiguration (**optional for alpha implement**) + +If the `initializer admission controller` and the `generic webhook admission +controller` watch the `AdmissionControlConfiguration` and act upon deltas, their +cached version of the configuration might be arbitrarily delayed. This makes it +impossible to predicate what initializer/hooks will be applied to newly created +objects. + +We considered a few ways to make the behavior of the `initializer admission +controller` and the `generic webhook admission controller` predictable. + +(I prefer #2. #1 is inefficient, #3 requires complex schema and is not intuitive) + +#### 1. Always do consistent read + +The `initializer admission controller` and the `generic webhook admission +controller` always do consistent read of the `AdmissionControlConfiguration` +before applying the configuration to the incoming objects. This adds latency to +every CREATE request. Because the two admission controllers are in the same +process as the apiserver, the latency mainly consists of the consistent read +latency of the backend storage (etcd), and the proto unmarshalling. + +#### 2. Optimized version of #1, do consistent read of a smaller object + +Instead of having the two controllers do consistent read of the entire +`AdmissionControlConfiguration` object, we let the registry store the +resourceVersion of the `AdmissionControlConfiguration` (perhaps in a configMap), +and let the two controllers always do consistent read of the resourceVersion and +only read the entire `AdmissionControlConfiguration` if the local version is +lower than the stored one. + +#### 3. Don't synchronize, but report what is the cached version + +The main goal is *NOT* to always apply the latest +`AdmissionControlConfiguration`, but to make it predictable what +initializers/hooks will be applied. If we introduce the +`generation/observedGeneration` concept to the `AdmissionControlConfiguration`, +then a human (e.g., a cluster admin) can compare the generation with the +observedGeneration and predict if all the initializer/hooks listed in the +`AdmissionControlConfiguration` will be applied. + +In the HA setup, the `observedGeneration` reported by of every apiserver's +`initializer admission controller` and `generic webhook admission controller` +are different, so the API needs to record multiple `observedGeneration`. + +A tentative schema: + +```golang +Type AdmissionControlConfiguration struct { + ... + // Generation is set by the registry + Geneartion int64 + // ObserverdGenerations is set by `initializer admission controller` and + // `generic webhook admission controller` in each apiserver. + ObserverdGenerations []ObservedGenerationByServer +} + +type ObservedGenerationByServer struct { + // Address of this server + // This can be a hostname, hostname:port, IP or IP:port + Server string + // The entity that reports the observedGeneration + AdmissionController AdmissionControllerType + ObservedGeneration int64 +} + +type AdmissionControllerType string + +const ( + InitializerAdmissionController AdmissionControllerType = "initializer admission controller" + GenericWebhookAdmissionController AdmissionControllerType = "generic webhook admission controller" +) +``` + +## What if an initializer controller/webhook is not ready after registered? (**optional for alpha implement**) + +This will block the entire cluster. We have a few options: + +1. only allow initializers/webhooks to be created as "fail open". They can + upgrade themselves to "fail closed" via the normal Update operation. A human + can also update them to "fail closed" later. + +2. less preferred: add readiness check to initializer and webhooks, `initializer + admission controller` and `generic webhook admission controller` only apply + those have passed readiness check. Specifically, we add `readiness` fields to + `AdmissionControllerConfiguration`; then we either create yet another + controller to probe for the readiness and update the + `AdmissionControllerConfiguration`, or ask each initializer/webhook to update + their readiness in the `AdmissionControllerConfigure`. The former is complex. + The latter is essentially the same as the first approach, except that we need + to introduce the additional concept of "readiness". |
