Validate Config
It is frustrating when bad config makes it all the way to production. "Bad" config can range from the annoying (whitespace causing a deploy failure) to the catastrophic (pointing to the wrong database).
ConfigHub prevents bad config from reaching production with a flexible system for validating config and gating applies when validation fails.
Validating triggers
Validation is done by adding validating triggers to a space. Jump to the background section to read more about the various types of triggers.
Validate the config format
Let's add a validation trigger to the tutorial space that checks if the config data conforms to Kubernetes schema. vet-schemas is a function that does just that:
cub trigger create --space tutorial valid-k8s Mutation Kubernetes/YAML vet-schemas
A validating trigger will fire when units change and it will place an apply gate if the validation fails. Let's test this by making a non-conforming change to chatapp-dev:
cub run yq-i --unit chatapp-dev '.badspec.field = "value"'
This will add a badspec top level entry in the yaml structure. You can see what it did with:
cub unit diff -u chatapp-dev --from=-1
Now let's look at the unit list:
cub unit list --columns Name,ApplyGates
You should see something like:
NAME APPLY-GATES
chatapp-dev valid-k8s/vet-schemas
chatapp-prod None
This indicates that chatapp-dev has a problem that must be fixed before it can be applied. If you try to apply:
cub unit apply chatapp-dev
You will get an error saying the unit has outstanding apply gates. To fix the problem you can restore a previous revision or you can delete the bad element with:
cub run yq-i --unit chatapp-dev 'del(.badspec)'
Validate security posture
In addition to checking for syntax problems, you can also validate that a unit meets certain standards. For example, you may require that all containers run as non-root. You can enforce this with a validating trigger that uses the vet-celexpr function:
cub trigger create ensure-nonroot Mutation Kubernetes/YAML vet-celexpr \
"r.kind != 'Deployment' || (r.spec.template.spec.securityContext.runAsNonRoot == true)"
This trigger will fail if a unit has a Deployment resource and the resource does not have runAsNonRoot set to true.
Note
Existing units will not be affected by a newly created trigger until they are changed. This limitation will be addressed in the future.
To see the effect of this trigger, let's create a new unit as a clone:
cub unit create chatapp-prod2 --upstream-unit chatapp-dev
Now if you run
cub unit list --columns Name,ApplyGates
You'll see:
NAME APPLY-GATES
chatapp-dev None
chatapp-prod None
chatapp-prod2 ensure-nonroot/vet-celexpr
To fix this, you can use a convenience function that sets sensible security defaults:
cub run set-pod-defaults --unit chatapp-prod2 --security-context true
Now if you check the unit list, the apply gate should be gone. You can see what the function did with a diff:
cub unit diff -u chatapp-prod2 --from=-1
You will see that the function made several improvements, including setting runAsRoot to false.
Summary
- Validating triggers makes it easy to prevent broken or non-compliant configuration from being applied.
- Validating triggers set Apply Gates when the validation fails.
- Units cannot be applied until Apply Gates have been cleared by fixing the problem in the config data.
- Validating triggers are simply function invocations which makes them very flexible. You can write your own function from scratch if you have a specific need that is not met by standard functions.
- Validating triggers are set on a space and apply to all units in the space.