Skip to content

Validation Guidelines

This document provides general developer guidelines on validation practices and conventions used in the Gardener codebase. Developers and reviewers should consult this guide when writing, refactoring, and reviewing Gardener code. If parts are unclear or new learnings arise, this guide should be adapted accordingly.

The Importance of Validation

Validation is a critical part of maintaining the reliability, security, and overall quality of the Gardener project. It is important for several key reasons:

  • Security
    • Validation protects against malicious inputs (like code injection), bypassing intended constraints, exploiting assumptions in the code and other attacks. The unexpected or harmful input is rejected before it can do damage.
  • API Consistency and Robustness
    • Validating the resource ensures that incorrect or ambiguous data is caught early, preventing downstream controllers from acting on invalid input. Ensuring well-formed and valid API resource specifications is fundamental for successful lifecycle operations on these resources (for example successful Shoot cluster creation, consistent Shoot cluster state).
  • System Stability
    • Invalid configurations passed unchecked into the system can result in unpredictable behavior or runtime errors. Early validation helps maintain system stability and predictability.
  • Clear and Immediate Feedback
    • By catching errors in the admission phase of a request, the API users get fast, actionable feedback. The API users don't have to wait for an internal system operation to fail after several minutes to receive feedback that the provided input is invalid.

Validation in Gardener

Kubernetes allows defining custom resources using extension API server and CustomResourceDefinitions. Gardener is using both approaches. The sections below Validation for API resources and Validation for CustomResourceDefinitions describe how validation is handled for these two approaches.

Validation for API Resources

Gardener API server is an extension API server. An extension API server allows validation of a resource to be performed in the storage layer or in admission plugins. The sections below Validation in the Storage Layer and Validation in API Server Admission Plugins describe how validation is handled for these two approaches.

Validation in the Storage Layer

The API resources served by an API server (an extension API server or Kubernetes API server itself) provide a storage layer for a resource by implementing the k8s.io/apiserver/pkg/registry/rest.Storage interface. These implementations usually embed the k8s.io/apiserver/pkg/registry/generic/registry.Store type in order to inherit CRUD semantics of a Kubernetes-like resource. For reference, check out the storage layer implementation:

The registry.Store type allows strategies for create, update and delete operations to be specified. The resources provide a strategy for the storage layer by implementing interfaces like k8s.io/apiserver/pkg/registry/rest.RESTCreateStrategy and k8s.io/apiserver/pkg/registry/rest.RESTUpdateStrategy. The rest.RESTCreateStrategy interface declares a Validate function, the rest.RESTUpdateStrategy interface - ValidateUpdate function.

For reference, check out the Validate and ValidateUpdate functions:

The validation code itself for a resource resides in dedicated validation package. This validation package is API group specific and contains the validation code for all resources from the API group. These validation packages are consumed by the Validate/ValidateUpdate functions of the strategy implementation. For reference, check out the validation packages:

Writing Validation Code in the Storage Layer

  • Write a validation code for a field in the storage layer if the validation logic does not require information from another resource. If the validation logic requires checking the presence of another resource or its specification, write the validation code in a validating API server admission plugin.
    • Example: Shoot's .spec.kubernetes.kubeProxy.mode field can be validated in the storage layer. The validation logic checks if the field value is one of the supported kube-proxy modes (IPTables, IPVS). There is no need to check another resource or its specification in order to validate this field.
  • The Validate function of the strategy implementation must perform validation of an API resource. The ValidateUpdate function must perform validation specific for update operation (e.g. validate field is immutable) and must ensure the new object is valid (usually implemented by reusing the logic that Validate already uses).

Validation in API Server Admission Plugins

An admission plugin (or admission controller) is a piece of code that intercepts requests to the API server prior to persistence of the resource, but after the request is authenticated and authorized. Check out Admission Control in Kubernetes to get an overview of the admission plugins in Kubernetes.

The admission plugins can validate, mutate, or do both. Mutating admission plugins may modify the data for the resource being modified; validating admission plugins may not. The interfaces an admission plugin can implement are:

A validating and mutating admission plugin implements both of them. For reference, check out examples within Gardener for:

The admission plugins are configurable. The API server has a set of admission plugins which are enabled by default. Additionally, the admission plugins can be enabled/disabled for an API server via the flags --enable-admission-plugins/--disable-admission-plugins.

An admission plugin can accept a configuration. The configuration is specified in API server admission configuration. See Gardener API server admission configuration example. For reference, check out Gardener API server admission plugins that accepts configuration:

Writing Validation Code in API Server Admission Plugins

  • Write the validation code for a field in an API server admission plugin if the validation logic requires checking the presence of another resource or its specification. Otherwise, write the validation code in the storage layer.
    • Example: Shoot's .spec.region field cannot be validated only in the storage layer. The validation logic for this field checks if the Shoot's CloudProfile supports the region in question. See the (Shoot .spec.region validation) in the ShootValidator admission plugin. This is an example of validation logic that requires cross checking against another resource's specification. Hence, validation must be performed in an admission plugin.
  • An admission plugin should embed the *admission.Handler type. admission.Handler is a base type for admission plugins. When initializing the admission plugin, create a new handler with admission.Handler and specify the operations the admission plugins supports. Example: SeedValidator initialization.
  • An admission plugin should filter out resources and subresources it is not interested in. Example: SeedValidator checks for resource and subresource
  • An admission plugin should use listers for fetching resources.
  • Perform validation in a validating admission plugin. Do not use a mutating admission plugin for validation purposes. Example: https://github.com/gardener/gardener/pull/12786
  • An admission plugin can only be added for resources served by the corresponding API server. Gardener API server can have an admission plugin only for resources it serves. For validation of resources served by the Kubernetes API server, use a validating webhook.

Validation for CustomResourceDefinitions

The CustomResourceDefinitions (CRDs) allow validation to be specified using OpenAPI v3.0 validation. It is convenient to perform relatively simple validation checks. For example, validate field is immutable or validate a slice contains at least one item. However, more advanced validation is hard to express via these means and is performed by validating webhooks.

extensions.gardener.cloud API group

The extensibility story is based on the CRDs from the extensions.gardener.cloud API group. They are validated by the gardener-resource-manager's validating webhook. See Extension Resource Validation. The validation functions are defined in the github.com/gardener/gardener/pkg/apis/extensions/validation package.

operator.gardener.cloud API group

The gardener-operator is responsible for the management of the garden cluster environment. It does this by using the Garden and Extension CRDs from the operator.gardener.cloud API group. The CRDs are validated by the gardener-operator's validating webhook. See gardener-operator validation section. The validation functions are defined in the github.com/gardener/gardener/pkg/apis/operator/v1alpha1/validation package.

Validation of Component Configurations

Most Gardener components have a component configuration that follows similar validation principles to those of the Gardener API. Although the component configuration APIs are internal ones, they are also subject to validation. For reference, check out the validation packages:

Utility Functions

This section provides a collection of utility functions designed to simplify and standardize validation across the Gardener codebase. These reusable helpers can be used to validate common data types, formats, and constraints — ensuring consistency, reducing code duplication, and improving overall reliability.

Utility functions from Kubernetes

Kubernetes offers several packages that contain validation utilities:

Frequently used validation functions for creation:

Frequently used validation functions for update:

Utility functions from Gardener

Gardener offers several packages that contain validation utilities:

Frequently used validation functions:

Field-level Validation Errors

The k8s.io/apimachinery/pkg/util/validation/field package contains the predefined field-level errors. These are commonly used by the validation logic to return detailed error information about specific fields in API resources. Frequently used ones are:

  • field.Duplicate
    • It indicates "duplicate value". This is used to report collisions of values that must be unique (e.g. names or IDs).
  • field.Forbidden
    • It indicates "forbidden". This is used to report valid (as per formatting rules) values which would be accepted under some conditions, but which are not permitted by current conditions (e.g. security policy).
  • field.InternalError
    • It indicates "internal error". This is used to signal that an error was found that was not directly related to user input.
  • field.Invalid
    • It indicates "invalid value". This is used to report malformed values (e.g. failed regex match, too long, out of bounds).
  • field.NotFound
    • It indicates "value not found". This is used to report failure to find a requested value (e.g. looking up an ID).
  • field.NotSupported
    • It indicates "unsupported value". This is used to report unknown values for enumerated fields (e.g. a list of valid values).
  • field.Required
    • It indicates "value required". This is used to report required values that are not provided (e.g. empty strings, null values, or empty arrays).

General Guidelines

  • Validation is a strict requirement when contributing a new or enhancing existing API.
    • If you add a new resource or if you add a new field to existing resource, make sure to add validation for it.
  • Strictly follow the Kubernetes API Conventions guides for validation.
  • When working with ValidatingWebhookConfigurations, strictly follow the Admission Webhook Good Practices.
  • When working with ValidatingWebhookConfigurations, ensure end-users cannot bypass the webhook by manipulating the resource labels.
    • A good practice for a webhook is to filter only for the resources it needs to validate by using an objectSelector.
    • Ensure end-users cannot bypass a validation by a webhook by removing resource label(s) which are used in the webhook's objectSelector.
    • Example: The ExtensionLabels admission plugin maintains the provider.extensions.gardener.cloud/<type>=true label on CloudProfile, Seed, Shoot and other resources. The admission components of provider extensions use this label to filter for resources with the corresponding provider type (see example usage). The ExtensionLabels admission plugin ensure the labels on CREATE and UPDATE requests. End-user cannot remove the provider.extensions.gardener.cloud/<type>=true label to bypass the provider extension admission webhook.
  • Use field-level validation errors according to their semantics.
    • Use field.Required for empty or null value; use field.Invalid for invalid value; use field.Duplicate for a duplicate value, etc. See Field-level Validation Errors.
  • When introducing a new field, consider if it should be immutable or not.
    • Consider if updates to the field value should be allowed and are supported by the underlying controller. If not, consider making the field immutable. Add a doc string to the field to denote the immutability constraint.
  • Introducing new validation for existing field or making existing validation more restrictive might be a breaking change.
    • When working with existing field, aim to add validation which is obvious and unlikely to break a working functionality.
    • If breaking change is inevitable and it is likely to break a working functionality:
      • In case the functionality is relevant to end-users , consider imposing the breaking change only with the upcoming minor Kubernetes version. This way, end-users are forced to actively adapt their manifests when performing Kubernetes upgrades.
      • Consider using "ratcheting" validation to incrementally tighten validation. See Ratcheting validation.
      • Consider using a feature gate to roll out the breaking change. The feature gate gives control when to impose the breaking change. In case of issues, it is possible to revert back to the old behavior by disabling the feature gate.
EU and German government funding logos

Funded by the European Union – NextGenerationEU.

The views and opinions expressed are solely those of the author(s) and do not necessarily reflect the views of the European Union or the European Commission. Neither the European Union nor the European Commission can be held responsible for them.