This guide demonstrates how to configure Kyverno to enforce network security policies that control container network access and prevent network-based attacks.
Network security involves controlling how containers access and interact with network resources. Proper network security prevents:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-network
annotations:
policies.kyverno.io/title: Disallow Host Network
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Access to the host network allows potential snooping of network traffic and should not be allowed.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: host-network
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Use of host network is disallowed. The field spec.hostNetwork must be unset or set to false.
pattern:
spec:
=(hostNetwork): "false"
# Apply the policy
kubectl apply -f disallow-host-network.yaml
# Try to create a pod with host network (should fail)
kubectl run test-hostnet --image=nginx --overrides='{"spec":{"hostNetwork":true}}'
# Try to create a normal pod (should work)
kubectl run test-normal --image=nginx
Prevent containers from binding to host network ports:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-ports
annotations:
policies.kyverno.io/title: Disallow Host Ports
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Access to host ports allows potential snooping of network traffic and should not be
allowed, or at minimum restricted to a known list.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: host-ports-none
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Use of host ports is disallowed. The fields spec.containers[*].ports[*].hostPort,
spec.initContainers[*].ports[*].hostPort, and spec.ephemeralContainers[*].ports[*].hostPort
must either be unset or set to 0.
pattern:
spec:
=(ephemeralContainers):
- =(ports):
- =(hostPort): 0
=(initContainers):
- =(ports):
- =(hostPort): 0
containers:
- =(ports):
- =(hostPort): 0
Allow specific host port ranges for controlled access:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-host-port-range
annotations:
policies.kyverno.io/title: Restrict Host Port Range
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Host ports, if used, must be within an allowed range to prevent conflicts and security issues.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: host-port-range
match:
any:
- resources:
kinds:
- Pod
preconditions:
all:
- key: "{{ request.object.spec.containers[].ports[?hostPort] | length(@) }}"
operator: GreaterThan
value: 0
validate:
message: >-
Host ports must be within the allowed range 30000-32767.
foreach:
- list: request.object.spec.[ephemeralContainers, initContainers, containers][].ports[]
preconditions:
any:
- key: "{{ element.hostPort }}"
operator: GreaterThan
value: 0
deny:
conditions:
any:
- key: "{{ element.hostPort }}"
operator: LessThan
value: 30000
- key: "{{ element.hostPort }}"
operator: GreaterThan
value: 32767
Ensure pods have associated NetworkPolicies for traffic control:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-network-policies
annotations:
policies.kyverno.io/title: Require Network Policies
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod,NetworkPolicy
policies.kyverno.io/description: >-
Pods should have associated NetworkPolicies to control network traffic.
spec:
validationFailureAction: Enforce
background: false
rules:
- name: require-netpol
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
- kyverno
context:
- name: netpols
apiCall:
urlPath: "/apis/networking.k8s.io/v1/namespaces/{{ request.namespace }}/networkpolicies"
jmesPath: "items[?spec.podSelector.matchLabels.app == '{{ request.object.metadata.labels.app }}'] | length(@)"
validate:
message: >-
Pods must have an associated NetworkPolicy. Create a NetworkPolicy that selects this pod.
deny:
conditions:
all:
- key: "{{ netpols }}"
operator: Equals
value: 0
Control which service types can be created:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-service-types
annotations:
policies.kyverno.io/title: Restrict Service Types
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Service
policies.kyverno.io/description: >-
Restrict Service types to prevent exposure of services to external networks.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: restrict-nodeport
match:
any:
- resources:
kinds:
- Service
validate:
message: >-
NodePort services are not allowed. Use ClusterIP or LoadBalancer instead.
pattern:
spec:
type: "!NodePort"
- name: restrict-loadbalancer
match:
any:
- resources:
kinds:
- Service
namespaces:
- development
- dev-*
- staging
validate:
message: >-
LoadBalancer services are not allowed in development environments.
pattern:
spec:
type: "!LoadBalancer"
Enforce secure Ingress configurations:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: secure-ingress-configuration
annotations:
policies.kyverno.io/title: Secure Ingress Configuration
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Ingress
policies.kyverno.io/description: >-
Ingress resources must be configured securely with TLS and proper annotations.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-tls
match:
any:
- resources:
kinds:
- Ingress
validate:
message: >-
Ingress must use TLS. The field spec.tls must be specified.
pattern:
spec:
tls:
- hosts:
- "*"
- name: require-security-annotations
match:
any:
- resources:
kinds:
- Ingress
validate:
message: >-
Ingress must have security annotations for SSL redirect and HSTS.
pattern:
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
Control DNS settings to prevent DNS-based attacks:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-dns-configuration
annotations:
policies.kyverno.io/title: Restrict DNS Configuration
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Restrict DNS configuration to prevent DNS hijacking and data exfiltration.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: restrict-dns-policy
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Custom DNS policy is not allowed. Use Default or ClusterFirst only.
pattern:
spec:
=(dnsPolicy): "Default | ClusterFirst"
- name: restrict-custom-dns
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Custom DNS configuration is not allowed in production environments.
pattern:
spec:
X(dnsConfig): "null"
Different network restrictions for different environments:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: environment-network-security
spec:
validationFailureAction: Enforce
background: true
rules:
# Production: Strict network controls
- name: production-network-restrictions
match:
any:
- resources:
kinds:
- Pod
namespaces:
- production
- prod-*
validate:
message: "Production environments require strict network security"
pattern:
spec:
hostNetwork: "false"
dnsPolicy: "ClusterFirst"
containers:
- ports:
- =(hostPort): 0
# Development: Basic network security
- name: development-network-restrictions
match:
any:
- resources:
kinds:
- Pod
namespaces:
- development
- dev-*
- staging
validate:
message: "Development environments require basic network security"
pattern:
spec:
hostNetwork: "false"
Different network policies for different application types:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: application-network-policies
spec:
validationFailureAction: Enforce
background: true
rules:
# Database applications: No external network access
- name: database-network-policy
match:
any:
- resources:
kinds:
- Pod
selector:
matchLabels:
app.type: database
validate:
message: "Database applications cannot use host network or host ports"
pattern:
spec:
hostNetwork: "false"
containers:
- ports:
- =(hostPort): 0
# Web applications: Controlled port access
- name: web-app-network-policy
match:
any:
- resources:
kinds:
- Pod
selector:
matchLabels:
app.type: web
validate:
message: "Web applications can only use standard HTTP/HTTPS ports"
foreach:
- list: request.object.spec.containers[].ports[]
deny:
conditions:
any:
- key: "{{ element.containerPort }}"
operator: AnyNotIn
value:
- 80
- 443
- 8080
- 8443
Enforce network segmentation between different tiers:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: network-segmentation-enforcement
spec:
validationFailureAction: Enforce
background: true
rules:
- name: frontend-backend-separation
match:
any:
- resources:
kinds:
- Pod
selector:
matchLabels:
tier: frontend
validate:
message: "Frontend pods cannot access backend network directly"
deny:
conditions:
any:
- key: "{{ request.object.metadata.labels.tier }}"
operator: Equals
value: backend
- name: require-network-labels
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
- kyverno
validate:
message: "Pods must have network tier labels for segmentation"
pattern:
metadata:
labels:
tier: "frontend | backend | database"
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-host-network
spec:
hostNetwork: true
containers:
- name: test
image: nginx
EOF
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-host-port
spec:
containers:
- name: test
image: nginx
ports:
- containerPort: 80
hostPort: 8080
EOF
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: test-nodeport
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
selector:
app: test
EOF
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-secure-network
labels:
app: web-app
tier: frontend
spec:
dnsPolicy: ClusterFirst
containers:
- name: test
image: nginx
ports:
- containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: test-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: web-app
EOF