Kyverno Policies
Nyl supports applying Kyverno policies to Kubernetes manifests at render time. This allows you to mutate and validate resources before they are applied to the cluster.
Overview
Section titled “Overview”Kyverno policies in Nyl are standard Kyverno CRDs annotated with a scope that determines when and where they are applied during rendering. Policies without the scope annotation are treated as normal Kubernetes resources and passed through to the output.
Quick Start
Section titled “Quick Start”apiVersion: policies.kyverno.io/v1kind: MutatingPolicymetadata: name: add-managed-by-label annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: Globalspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps', 'services'] mutations: - patchType: ApplyConfiguration applyConfiguration: expression: >- Object{metadata: Object.metadata{labels: Object.metadata.labels{managedBy: "nyl"}}}Supported Policy Types
Section titled “Supported Policy Types”Nyl supports standard Kyverno policy CRDs:
Working Policy Types
Section titled “Working Policy Types”These policy types work with kyverno apply in offline mode:
- ClusterPolicy (
kyverno.io/v1) - Cluster-wide policies using traditional Kyverno format - MutatingPolicy (
policies.kyverno.io/v1) - Namespace or cluster-scoped mutation policies - ValidatingPolicy (
policies.kyverno.io/v1) - Namespace or cluster-scoped validation policies
Detected but Not Evaluable
Section titled “Detected but Not Evaluable”These policy types are detected but require a live Kubernetes cluster:
- GeneratingPolicy (
policies.kyverno.io/v1) - Generate new resources - DeletingPolicy (
policies.kyverno.io/v1) - Delete resources - ImageValidatingPolicy (
policies.kyverno.io/v1) - Validate container images
Scope Annotation
Section titled “Scope Annotation”Policies must include the nyl.niklasrosenstein.github.com/apply-policy-scope annotation to be processed by Nyl.
Available Scopes
Section titled “Available Scopes”Global (Currently Supported)
Section titled “Global (Currently Supported)”Applies to all resources in the rendered file. Since Nyl processes single files, this means all resources from the manifest being rendered.
metadata: annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: GlobalUse cases:
- Organization-wide labeling standards
- Security policies applied to all resources
- Compliance requirements
Future Scopes (Not Yet Implemented)
Section titled “Future Scopes (Not Yet Implemented)”- Subtree: Applies to siblings and all descendant resources
- Immediate: Applies to sibling resources only
Policies with these scopes will trigger a warning but won’t cause errors.
Policy Examples
Section titled “Policy Examples”Mutation Policy
Section titled “Mutation Policy”Add labels to all ConfigMaps and Secrets:
apiVersion: policies.kyverno.io/v1kind: MutatingPolicymetadata: name: add-labels annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: Globalspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps', 'secrets'] mutations: - patchType: ApplyConfiguration applyConfiguration: expression: >- Object{ metadata: Object.metadata{ labels: Object.metadata.labels{ environment: "production", managedBy: "nyl" } } }Validation Policy
Section titled “Validation Policy”Require specific labels on all resources:
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: require-labels annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: Globalspec: matchConstraints: resourceRules: - apiGroups: ['*'] apiVersions: ['*'] operations: ['CREATE'] resources: ['*'] validations: - expression: >- has(object.metadata.labels) && 'environment' in object.metadata.labels && 'team' in object.metadata.labels message: "All resources must have 'environment' and 'team' labels"ClusterPolicy (Traditional Format)
Section titled “ClusterPolicy (Traditional Format)”Using the older kyverno.io/v1 ClusterPolicy format:
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: add-default-network-policy annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: Globalspec: rules: - name: add-network-policy-annotation match: any: - resources: kinds: - Namespace mutate: patchStrategicMerge: metadata: annotations: networking.policy: "default-deny"Service Load Balancer Configuration
Section titled “Service Load Balancer Configuration”Automatically configure LoadBalancer services:
apiVersion: policies.kyverno.io/v1kind: MutatingPolicymetadata: name: configure-loadbalancer annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: Globalspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['services'] mutations: - patchType: ApplyConfiguration applyConfiguration: expression: >- object.spec.type == 'LoadBalancer' ? Object{ spec: Object.spec{ loadBalancerClass: "ngrok", allocateLoadBalancerNodePorts: false } } : objectUnannotated Policies
Section titled “Unannotated Policies”Policies without the scope annotation are treated as normal Kubernetes resources and included in the output. This allows you to:
- Deploy policies to the cluster along with your applications
- Manage policies as part of your GitOps workflow
- Use Nyl for some policies (with annotations) and deploy others normally
# This policy will be included in output but NOT applied by NylapiVersion: policies.kyverno.io/v1kind: MutatingPolicymetadata: name: cluster-policy # No scope annotationspec: matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE'] resources: ['deployments'] mutations: - patchType: ApplyConfiguration applyConfiguration: expression: "object"Policy Processing
Section titled “Policy Processing”Processing Order
Section titled “Processing Order”- Policy Detection: Nyl scans all manifests for Kyverno policy CRDs
- Scope Extraction: Policies with the scope annotation are extracted and grouped by scope
- Policy Application: Global policies are applied to all non-policy resources
- Output: Mutated resources are output; annotated policy resources are excluded
Policy Exclusion
Section titled “Policy Exclusion”Policy resources themselves are automatically excluded from mutation by other policies. This prevents circular mutations and ensures policies remain unchanged.
Validation Failures
Section titled “Validation Failures”If a validation policy fails, the nyl render command will fail with an error:
$ nyl renderERROR: Configuration error: Kyverno apply failed with exit code Some(1):...Validation error: ConfigMap must have 'environment' labelCEL Expressions
Section titled “CEL Expressions”Kyverno policies use Common Expression Language (CEL) for mutations and validations.
Common Patterns
Section titled “Common Patterns”Check if field exists:
has(object.metadata.labels)Check if key exists in map:
'environment' in object.metadata.labelsConditional mutation:
object.spec.type == 'LoadBalancer' ? Object{spec: Object.spec{loadBalancerClass: "ngrok"}} : objectAdd or merge labels:
Object{ metadata: Object.metadata{ labels: Object.metadata.labels{ newLabel: "value" } }}Set deeply nested field:
Object{ spec: Object.spec{ template: Object.spec.template{ spec: Object.spec.template.spec{ securityContext: Object{runAsNonRoot: true} } } }}Requirements
Section titled “Requirements”- Kyverno CLI: Must be installed and available in PATH
Terminal window # Install on Linuxcurl -LO https://github.com/kyverno/kyverno/releases/download/v1.17.0/kyverno-cli_v1.17.0_linux_x86_64.tar.gztar -xzf kyverno-cli_v1.17.0_linux_x86_64.tar.gzsudo mv kyverno /usr/local/bin/# Install on macOSbrew install kyverno# Verify installationkyverno version
Best Practices
Section titled “Best Practices”- Use Global scope sparingly: Global policies affect all resources and can have wide-reaching effects
- Test policies locally: Use
nyl renderto verify policy behavior before deployment - Provide clear error messages: Include descriptive messages in validation policies
- Document policy intent: Use metadata annotations to document why policies exist
- Prefer immutable labels: Add labels rather than modifying existing ones
- Version your policies: Include version information in policy names or labels
Troubleshooting
Section titled “Troubleshooting”Policy Not Applied
Section titled “Policy Not Applied”Issue: Policy appears in output but isn’t being applied
Solution: Check that the policy has the scope annotation:
metadata: annotations: nyl.niklasrosenstein.github.com/apply-policy-scope: GlobalKyverno CLI Not Found
Section titled “Kyverno CLI Not Found”Issue: Kyverno CLI is not installed but Kyverno policies were found
Solution: Install the Kyverno CLI (see Requirements section above)
Validation Policy Passes But Shouldn’t
Section titled “Validation Policy Passes But Shouldn’t”Issue: Resources that should fail validation are passing
Solution: Verify the CEL expression logic and matchConstraints are correct. Test with kyverno apply directly:
kyverno apply policy.yaml --resource resource.yamlMultiple Policies Conflict
Section titled “Multiple Policies Conflict”Issue: Multiple policies are mutating the same field differently
Solution: Ensure policies are orthogonal (affect different fields) or use proper scoping to control application order