Made with ❤️ by and for policy lovers
Validating Kubernetes resources offline - kubeconform review
In this article, we will explore kubeconform, the successor to kubeval.
Kubeconform is based on the same principles as kubeval, but it is actively maintained and has some unique features.
Introduction#
As the two tools are very similar, I invite you to consult the article on kubeval which also applies to kubeconform.
Resource Schemas#
Kubeconform uses JSON schemas to validate (or invalidate) the proposed resources. These JSON schemas are created from the OpenAPI schemas published within the Kubernetes GitHub repository.
Unlike kubeval, which is no longer maintained, kubeconform maintains an up-to-date repository of JSON schemas converted from the native schemas published by Kubernetes (kubeconform fork of kubernetes-json-schema). The most recent version supported as of today is v1.30.0
.
Installing kubeconform#
The kubeconform project documentation suggests installing the binary directly or using a package manager, or using it through a Docker image.
For this article, we will use brew to install it locally:
brew install kubeconform
The docker image can be found at https://ghcr.io/yannh/kubeconform.
Validation with kubeconform#
Unlike kubeval, kubeconform supports the validation of custom resources, provided that you supply the corresponding JSON schemas. We will see more about this later.
Let’s start by validating native resources.
Validating native resources#
Let’s try to validate the simple (yet invalid) manifest below:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
# no replicas field exist in DaemonSet resource
replicas: 2
template:
spec:
containers:
- image: nginx
name: nginx
If we run kubeconform without any option the DaemonSet
will be considered invalid:
kubeconform manifests.yaml
manifests.yaml - DaemonSet nginx-ds is invalid: problem validating schema. Check JSON formatting: jsonschema: '/spec' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/daemonset-apps-v1.json#/properties/spec/required: missing properties: 'selector'
As noted above, the selector
field is missing. Let’s provide a valid manifest:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
# no replicas field exist in DaemonSet resource
replicas: 2
selector:
matchLabels:
name: nginx-ds
template:
metadata:
labels:
name: nginx-ds
spec:
containers:
- image: nginx
name: nginx
This time, running kubeconform manifests.yaml
passes. Still, the unexpected replicas
field is not detected.
To make kubeconform detect unexpected fields, we need to specify --strict
:
kubeconform --strict manifests.yaml
manifests.yaml - DaemonSet nginx-ds is invalid: problem validating schema. Check JSON formatting: jsonschema: '/spec' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone-strict/daemonset-apps-v1.json#/properties/spec/additionalProperties: additionalProperties 'replicas' not allowed
Corner cases#
As explained in the article on kubeval, schema-based validation is often approximate.
Property type checks work quite well, but the validation of associated values is less reliable. This is because the validation logic is implemented in specific code and does not always form part of the schema definition.
Let’s take the example of an invalid label:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm
labels:
# ERROR: a label key must start with an alphanumeric character
_: invalid
data:
foo: bar
Let’s try to validate the resource above with:
kubeconform --strict manifests.yaml
This time kubeconform does not detect the invalid label.
Another simple example is the following, which defines a Deployment
with a negative number of replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy
spec:
replicas: -1
selector:
matchLabels:
name: deploy
template:
metadata:
labels:
name: deploy
spec:
containers:
- image: nginx
name: nginx
Here too, kubeconform --strict manifests.yaml
does not detect the problem even though the resource will be rejected by a cluster:
kubectl apply -f manifests.yaml
The Deployment "deploy" is invalid: spec.replicas: Invalid value: -1: must be greater than or equal to 0
Target Kubernetes Version#
In the case of native resources, the target version of the cluster is important, as native resources evolve regularly with the appearance of new properties, new API versions, and some API versions are deprecated and then removed, etc.
Therefore, a resource considered valid given one version of Kubernetes may be considered invalid with an older version of Kubernetes.
It is possible to target a specific version of Kubernetes using the --kubernetes-version
argument.
Let’s take, for example, the API extensions/v1beta1
which was removed from Kubernetes in v1.22:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: frontend
spec:
rules:
- host: frontend.minikube.local
http:
paths:
- path: /
backend:
serviceName: frontend
servicePort: 80
The Ingress
resource above is considered valid with Kubernetes v1.20
:
kubeconform --kubernetes-version 1.20.0 --strict manifests.yaml
While the schema is no longer available in v1.22
:
kubeconform --kubernetes-version 1.22.0 --strict manifests.yaml
manifests.yaml - Ingress frontend failed validation: could not find schema for Ingress
CRDs validation#
Let’s finish with the validation of custom resources (CRDs).
Kubeconform supports custom resources provided that you can supply it with the corresponding JSON schema.
For instance, using an example from kubeconform’s GitHub, we can utilize Datree’s CRDs-catalog which lists the most used CRDs and provides the associated JSON schemas.
Let’s take for example an Issuer
resource of cert manager:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
Without specifying the location of the schema associated with the Issuer
resource type, kubeconform is unable to validate the resource:
kubeconform --strict manifests.yaml
manifests.yaml - Issuer test-selfsigned failed validation: could not find schema for Issuer
In order to enable kubeconform to download the corresponding JSON schema, one can use the --schema-location
argument:
kubeconform --schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' --strict manifests.yaml
This time, kubeconform can validate the Issuer
resource using the schema downloaded from Datree’s GitHub repository.
Note that the --schema-location
argument can be specified as many times as necessary. It is also possible to convert a CRD definition yourself, which is all explained here.
Conclusion#
In conclusion, kubeconform is heavily inspired by kubeval and has taken up the mantle to become its worthy successor.
Both tools operate in exactly the same way based on JSON schema, and kubeconform maintains an up-to-date version of the schemas for native resources.
Finally, kubeconform adds support for custom resources, which significantly broadens the tool’s scope. Their use, however, remains quite complex, especially in the case of a custom resource whose schema is not publicly available on the internet.
In summary, kubeconform is a significant step forward for users of kubeval, providing a satisfactory tool for use without custom resources. However, it remains limited in the case of intensive use of CRDs.
Stay tuned!#
The next article will explore a tool more suited to modern Kubernetes usage with enhanced support for custom resources. Stay tuned for the next episode!