kubernetesValidating

This binding transforms a hook into a handler for ValidatingWebhookConfiguration. The Shell-operator creates ValidatingWebhookConfiguration, starts HTTPS server, and runs hooks to handle AdmissionReview requests.

Note: shell-operator use admissionregistration.k8s.io/v1, so Kubernetes 1.16+ is needed.

Syntax

configVersion: v1 onStartup: 10 kubernetes: - name: myCrdObjects ... kubernetesValidating: - name: my-crd-validator.example.com # include snapshots by binding names includeSnapshotsFrom: ["myCrdObjects"] # or use group name to include all snapshots in a group group: "group name" labelSelector: # equivalent of objectSelector matchLabels: label1: value1 ... namespace: labelSelector: # equivalent of namespaceSelector matchLabels: label1: value1 ... matchExpressions: - key: environment operator: In values: ["prod","staging"] rules: - apiVersions: - v1 apiGroups: - stable.example.com resources: - CronTab operations: - "*" - operations: ["CREATE", "UPDATE"] apiGroups: ["apps"] apiVersions: ["v1", "v1beta1"] resources: ["deployments", "replicasets"] scope: "Namespaced" failurePolicy: Ignore | Fail (default) sideEffects: None (default) | NoneOnDryRun timeoutSeconds: 2 (default is 10) matchConditions: - name: "exclude-user" expression: '("system:apiserver" != request.userInfo.username)'

Parameters

  • name — a required parameter. It should be a domain with at least three segments separated by dots.

  • includeSnapshotsFrom — an array of names of kubernetes bindings in a hook. When specified, a list of monitored objects from these bindings will be added to the binding context in the snapshots field.

  • group — a key to include snapshots from a group of schedule and kubernetes bindings. See grouping.

  • labelSelectorstandard selector of objects by labels (examples of use). See objectSelector.

  • namespace.labelSelector — this filter works like labelSelector but for namespaces. See namespaceSelector.

  • rules — a required list of rules used to determine if a request to the Kubernetes API server should be sent to the hook. See Rules.

  • failurePolicy — defines how errors from the hook are handled. See Failure policy. Default is Fail.

  • sideEffects — determine whether the hook is dryRun-aware. See side effects documentation. Default is None.

  • timeoutSeconds — a seconds API server should wait for a hook to respond before treating the call as a failure. See timeouts. Default is 10 (seconds).

  • matchConditions — an optional list of match conditions for fine-grained request filtering. Available only since v1.27 of Kubernetes.

As you can see, it is the close copy of a Webhook configuration. Differences are:

  • objectSelector is a labelSelector as in the kubernetes binding.
  • namespaceSelector is a namespace.labelSelector as in the kubernetes binding.
  • clientConfig is managed by the Shell-operator. You should provide a Service for the Shell-operator HTTPS endpoint. See example 204-validating-webhook for possible solution.
  • matchPolicy is always “Equivalent”. See Matching requests: matchPolicy.
  • there are additional fields group and includeSnapshotsFrom to include snapshots in the binding context.

Example

configVersion: v1 kubernetesValidating: - name: private-repo-policy.example.com rules: - apiGroups: ["stable.example.com"] apiVersions: ["v1"] operations: ["CREATE"] resources: ["crontabs"] scope: "Namespaced"

The Shell-operator will execute hook with this configuration on every creation of CronTab object.

See example 204-validating-webhook.

Hook input and output

Note that the group parameter is only for including snapshots. kubernetesValidating hook is never executed on schedule or kubernetes events with binding context with "type":"Group".

The hook receives a binding context and should return response in $VALIDATING_RESPONSE_PATH.

$BINDING_CONTEXT_PATH file example:

[{ # Name as defined in binding configuration. "binding": "my-crd-validator.example.com", # Validating to distinguish from other events. "type": "Validating", # Snapshots as defined by includeSnapshotsFrom or group. "snapshots": { ... } # AdmissionReview object. "review": { "apiVersion": "admission.k8s.io/v1", "kind": "AdmissionReview", "request": { # Random uid uniquely identifying this admission call "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", # Fully-qualified group/version/kind of the incoming object "kind": {"group":"autoscaling","version":"v1","kind":"Scale"}, # Fully-qualified group/version/kind of the resource being modified "resource": {"group":"apps","version":"v1","resource":"deployments"}, # subresource, if the request is to a subresource "subResource": "scale", # Fully-qualified group/version/kind of the incoming object in the original request to the API server. # This only differs from `kind` if the webhook specified `matchPolicy: Equivalent` and the # original request to the API server was converted to a version the webhook registered for. "requestKind": {"group":"autoscaling","version":"v1","kind":"Scale"}, # Fully-qualified group/version/kind of the resource being modified in the original request to the API server. # This only differs from `resource` if the webhook specified `matchPolicy: Equivalent` and the # original request to the API server was converted to a version the webhook registered for. "requestResource": {"group":"apps","version":"v1","resource":"deployments"}, # subresource, if the request is to a subresource # This only differs from `subResource` if the webhook specified `matchPolicy: Equivalent` and the # original request to the API server was converted to a version the webhook registered for. "requestSubResource": "scale", # Name of the resource being modified "name": "my-deployment", # Namespace of the resource being modified, if the resource is namespaced (or is a Namespace object) "namespace": "my-namespace", # operation can be CREATE, UPDATE, DELETE, or CONNECT "operation": "UPDATE", "userInfo": { # Username of the authenticated user making the request to the API server "username": "admin", # UID of the authenticated user making the request to the API server "uid": "014fbff9a07c", # Group memberships of the authenticated user making the request to the API server "groups": ["system:authenticated","my-admin-group"], # Arbitrary extra info associated with the user making the request to the API server. # This is populated by the API server authentication layer and should be included # if any SubjectAccessReview checks are performed by the webhook. "extra": { "some-key":["some-value1", "some-value2"] } }, # object is the new object being admitted. # It is null for DELETE operations. "object": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, # oldObject is the existing object. # It is null for CREATE and CONNECT operations. "oldObject": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, # options contains the options for the operation being admitted, like meta.k8s.io/v1 CreateOptions, UpdateOptions, or DeleteOptions. # It is null for CONNECT operations. "options": {"apiVersion":"meta.k8s.io/v1","kind":"UpdateOptions",...}, # dryRun indicates the API request is running in dry run mode and will not be persisted. # Webhooks with side effects should avoid actuating those side effects when dryRun is true. # See http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request for more details. "dryRun": false } } }]

Response example:

cat <<EOF > $VALIDATING_RESPONSE_PATH {"allowed": true} EOF

Allow with warnings (Kubernetes 1.19+):

cat <<EOF > $VALIDATING_RESPONSE_PATH {"allowed": true, "warnings":["It might be risky because it is Tuesday", "It might be risky because your name starts with A"]} EOF

Deny object creation and explain why:

cat <<EOF > $VALIDATING_RESPONSE_PATH {"allowed": false, "message": "You cannot do this because it is Tuesday and your name starts with A"} EOF

User will see an error message:

Error from server: admission webhook "policy.example.com" denied the request: You cannot do this because it is Tuesday and your name starts with A

Empty or invalid $VALIDATING_RESPONSE_PATH file is considered as "allowed": false with a short message about the problem and a more verbose error in the log.

HTTP server and Kubernetes configuration

Shell-operator should create an HTTP endpoint with TLS support and register endpoints in the ValidatingWebhookConfiguration resource.

There should be a Service for shell-operator (see Availability).

Command line options:

--validating-webhook-configuration-name="shell-operator-hooks" A name of a ValidatingWebhookConfiguration resource. Can be set with $VALIDATING_WEBHOOK_CONFIGURATION_NAME. --validating-webhook-service-name="shell-operator-validating-svc" A name of a service used in ValidatingWebhookConfiguration. Can be set with $VALIDATING_WEBHOOK_SERVICE_NAME. --validating-webhook-server-cert="/validating-certs/tls.crt" A path to a server certificate for service used in ValidatingWebhookConfiguration. Can be set with $VALIDATING_WEBHOOK_SERVER_CERT. --validating-webhook-server-key="/validating-certs/tls.key" A path to a server private key for service used in ValidatingWebhookConfiguration. Can be set with $VALIDATING_WEBHOOK_SERVER_KEY. --validating-webhook-ca="/validating-certs/ca.crt" A path to a ca certificate for ValidatingWebhookConfiguration. Can be set with $VALIDATING_WEBHOOK_CA. --validating-webhook-client-ca=VALIDATING-WEBHOOK-CLIENT-CA ... A path to a server certificate for ValidatingWebhookConfiguration. Can be set with $VALIDATING_WEBHOOK_CLIENT_CA.