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)

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).

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.