Writing Policies
Writing Policies is the heaviest domain: rule structure, variables, context data, and mutation that does not destroy what users wrote.
Anatomy
apiVersion: kyverno.io/v1, kind: ClusterPolicy, and spec.rules[] where each rule has a required name, a match, and exactly one of validate, mutate, generate, or verifyImages. context gathers external data - ConfigMaps, API calls, image metadata - into variables.
Variables and JMESPath
{{ }} delimits an expression evaluated with JMESPath over context entries and the request.* object. Common anchors are request.object, request.oldObject, request.userInfo.username, request.namespace, and serviceAccountName. Variables are not allowed inside match, which is evaluated before context exists.
Pattern operators
Kyverno patterns extend YAML: * any sequence, ? a single character, ! negation, | OR, & AND, plus < and >. Anchors matter: +(field): value adds the field only when absent, (field): value pins an existing field, and field: X overwrites.
Validation styles
Patterns suit shape checks. deny.conditions with any/all suits multi-field logic, and foreach walks lists such as containers so each element is validated individually rather than as a whole array.
Worked example
A mutate rule sets spec.template.spec.securityContext.runAsNonRoot to true on Deployments, using a strategic-merge patch with +(...) on the field. Reasoning: the conditional anchor leaves an explicit existing value alone instead of silently rewriting it, so teams that already set the field keep control while unset workloads get the safe default.
Traps
Dereferencing request.object on DELETE, where only request.oldObject exists; using * where ?* is required to reject empty strings; nesting the patch under the wrong level for Pod controllers; and forgetting that variables in match fail validation.