✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes CRD Validation Management

Kubernetes CRD Validation Management ensures consistent and secure configuration of custom resources through structured validation rules and policy enforcement.

Kubernetes CRD Validation Management is the discipline of deciding which validation layer — OpenAPI schema constraints, embedded CEL rules, admission webhooks, or controller-side reconcile-time checks — enforces a given constraint on a custom resource, and of coordinating those layers so that invalid states are rejected as early and as cheaply as possible without duplicating logic across layers that then drift out of sync.


The Validation Layers, in Order of Execution

Layer One: OpenAPI Schema Constraints

The cheapest and earliest validation layer is the schema itself, checked synchronously by the API server before any webhook is invoked, covering type correctness, enum membership, numeric ranges, string patterns, and required fields.

schema:
  openAPIV3Schema:
    type: object
    properties:
      spec:
        type: object
        required: ["replicas"]
        properties:
          replicas:
            type: integer
            minimum: 1
            maximum: 20

Layer Two: Embedded CEL Rules

For constraints that span multiple fields but still require no external state, x-kubernetes-validations rules execute immediately after schema validation, still inside the API server, still without a network round trip.

schema:
  openAPIV3Schema:
    type: object
    properties:
      spec:
        type: object
        x-kubernetes-validations:
          - rule: "self.minReplicas <= self.maxReplicas"
            message: "minReplicas must not exceed maxReplicas"

Layer Three: Validating Admission Webhooks

Constraints that require querying external state — checking a referenced Secret exists, verifying a quota against a value not visible to the object itself, or applying an organization-specific policy engine — require a validating webhook, which runs after schema and CEL validation and can reject the request with a specific error message.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: postgrescluster-validator
webhooks:
  - name: validate.databases.example.com
    rules:
      - apiGroups: ["databases.example.com"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["postgresclusters"]
    clientConfig:
      service:
        name: postgres-validator
        namespace: databases-system
        path: "/validate-postgrescluster"
    failurePolicy: Fail
    admissionReviewVersions: ["v1"]

Layer Four: Controller-Side Reconcile Validation

Constraints that can only be evaluated against the live state of the cluster at reconcile time, such as "the referenced StorageClass still exists" possibly changing after admission but before reconciliation runs, are checked inside the controller's reconcile loop and surfaced through status.conditions rather than rejected at admission, since the object has already been accepted and persisted.

status:
  conditions:
    - type: ReferencesValid
      status: "False"
      reason: StorageClassNotFound
      message: "referenced StorageClass 'fast-ssd' does not exist"
Cost ( Schema ) < Cost ( CEL ) < Cost ( Webhook )

Choosing the Right Layer for a Given Rule

Push Constraints as Early as Possible

The governing principle of validation management is to implement every constraint at the earliest layer capable of expressing it: a range check belongs in the schema, not a webhook; a cross-field comparison belongs in CEL, not a webhook, if it requires no external lookup; only genuinely external-state-dependent or organization-policy-dependent checks belong in a webhook, since each layer down adds latency, a new network dependency, and a new potential point of failure to every write of that resource type.

Avoiding Duplicated, Drifting Logic

A common failure mode is implementing the same constraint at two layers (a range check present in both the schema and a webhook) written independently and allowed to drift as the resource evolves, eventually producing contradictory validation outcomes; validation management treats each constraint as owned by exactly one layer, with lower layers deliberately left permissive where a higher layer already enforces the rule.


Webhook Failure Policy and Availability

failurePolicy Trade-off

webhooks:
  - failurePolicy: Fail

Setting failurePolicy: Fail (the safer default for validation) means requests are rejected if the webhook is unreachable, guaranteeing the validation rule is never silently skipped, at the cost of making the webhook's own availability a hard dependency for every write to the resource; Ignore trades that guarantee away in exchange for availability, which is rarely appropriate for validation webhooks enforcing correctness rather than best-effort policy.


Testing Validation Layers

envtest for Integration Testing

testEnv := &envtest.Environment{
    CRDDirectoryPaths: []string{"../config/crd/bases"},
    WebhookInstallOptions: envtest.WebhookInstallOptions{
        Paths: []string{"../config/webhook"},
    },
}
cfg, err := testEnv.Start()

The envtest package spins up a real API server and etcd instance (without a full kubelet or scheduler) so that schema validation, CEL rules, and webhook behavior can all be exercised together in automated tests, catching validation layer inconsistencies before they reach a live cluster.


Relationship to CRD Schema and Version Management

Validation management is the cross-cutting policy layer that determines how the mechanisms described in CRD schema management (schema constraints, CEL rules) and the broader CRD lifecycle (webhooks, controller reconciliation) are actually allocated to specific business rules, and it directly affects version management: a validation rule tightened in a new CRD version is exactly the kind of change that must be checked against existing stored objects before that version is promoted to become the storage version.

Schema CEL rules Webhook Controller