apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: canonical-cilium-cidrs annotations: policies.kyverno.io/title: Canonical Cilium CIDRs policies.kyverno.io/category: Network Security policies.kyverno.io/severity: high policies.kyverno.io/description: >- Require canonical, non-redundant Cilium CIDRs and reject generic RFC1918 ranges in favor of explicit routed subnets. spec: validationFailureAction: Enforce background: true rules: - name: require-canonical-cidrs match: any: - resources: kinds: - CiliumNetworkPolicy - CiliumClusterwideNetworkPolicy operations: - CREATE - UPDATE validate: cel: variables: - name: policySpecs expression: "has(object.spec) ? [object.spec] : object.specs" - name: genericPrivateRanges expression: "['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']" expressions: - expression: >- variables.policySpecs.all(policy, (!has(policy.ingress) || policy.ingress.all(rule, (!has(rule.fromCIDR) || rule.fromCIDR.all(value, isCIDR(value) && value == string(cidr(value).masked()) )) && (!has(rule.fromCIDRSet) || rule.fromCIDRSet.all(entry, (!has(entry.cidr) || (isCIDR(entry.cidr) && entry.cidr == string(cidr(entry.cidr).masked()) && (!has(entry.except) || entry.except.all(value, isCIDR(value) && value == string(cidr(value).masked()) )))) )) )) && (!has(policy.egress) || policy.egress.all(rule, (!has(rule.toCIDR) || rule.toCIDR.all(value, isCIDR(value) && value == string(cidr(value).masked()) )) && (!has(rule.toCIDRSet) || rule.toCIDRSet.all(entry, (!has(entry.cidr) || (isCIDR(entry.cidr) && entry.cidr == string(cidr(entry.cidr).masked()) && (!has(entry.except) || entry.except.all(value, isCIDR(value) && value == string(cidr(value).masked()) )))) )) )) ) message: Cilium policy CIDRs must use canonical network prefixes. - expression: >- variables.policySpecs.all(policy, (!has(policy.ingress) || policy.ingress.all(rule, !has(rule.fromCIDR) || rule.fromCIDR.all(value, rule.fromCIDR.filter(other, other == value).size() == 1 && !rule.fromCIDR.exists(other, other != value && cidr(other).containsCIDR(cidr(value)) ) ) )) && (!has(policy.egress) || policy.egress.all(rule, !has(rule.toCIDR) || rule.toCIDR.all(value, rule.toCIDR.filter(other, other == value).size() == 1 && !rule.toCIDR.exists(other, other != value && cidr(other).containsCIDR(cidr(value)) ) ) )) ) message: >- Cilium fromCIDR and toCIDR lists must not contain duplicate or redundant ranges. - expression: >- variables.policySpecs.all(policy, (!has(policy.ingress) || policy.ingress.all(rule, (!has(rule.fromCIDR) || rule.fromCIDR.all(value, !variables.genericPrivateRanges.exists(block, block == value) )) && (!has(rule.fromCIDRSet) || rule.fromCIDRSet.all(entry, !has(entry.cidr) || !variables.genericPrivateRanges.exists(block, block == entry.cidr) )) )) && (!has(policy.egress) || policy.egress.all(rule, (!has(rule.toCIDR) || rule.toCIDR.all(value, !variables.genericPrivateRanges.exists(block, block == value) )) && (!has(rule.toCIDRSet) || rule.toCIDRSet.all(entry, !has(entry.cidr) || !variables.genericPrivateRanges.exists(block, block == entry.cidr) )) )) ) message: >- Cilium policies must use explicit routed subnets instead of generic RFC1918 ranges.