109 lines
4.8 KiB
YAML
109 lines
4.8 KiB
YAML
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.
|