This guide demonstrates how to configure Kyverno to prevent container escape attacks by blocking high-risk container configurations that could allow containers to break out of their isolation boundaries.
Container escape prevention involves detecting and blocking dangerous container configurations that could allow attackers to escape container isolation and gain access to the host system. This includes:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
annotations:
policies.kyverno.io/title: Disallow Privileged Containers
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Privileged mode disables most security mechanisms and must not be allowed.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: privileged-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Privileged mode is disallowed. The fields spec.containers[*].securityContext.privileged,
spec.initContainers[*].securityContext.privileged, and spec.ephemeralContainers[*].securityContext.privileged
must be unset or set to false.
pattern:
spec:
=(ephemeralContainers):
- =(securityContext):
=(privileged): "false"
=(initContainers):
- =(securityContext):
=(privileged): "false"
containers:
- =(securityContext):
=(privileged): "false"
# Apply the policy
kubectl apply -f disallow-privileged-containers.yaml
# Try to create a privileged container (should fail)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-privileged
spec:
containers:
- name: nginx
image: nginx
securityContext:
privileged: true
EOF
# Try to create a normal container (should work)
kubectl run test-normal --image=nginx
# Clean up
kubectl delete pod test-privileged test-normal --ignore-not-found
Prevent containers from accessing host namespaces:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-namespaces
annotations:
policies.kyverno.io/title: Disallow Host Namespaces
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Host namespaces (Process ID namespace, Inter-Process Communication namespace, and
network namespace) allow access to shared information and can be used to elevate
privileges. Pods should not be allowed access to host namespaces.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: host-namespaces
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Sharing the host namespaces is disallowed. The fields spec.hostNetwork,
spec.hostIPC, and spec.hostPID must be unset or set to false.
pattern:
spec:
=(hostPID): "false"
=(hostIPC): "false"
=(hostNetwork): "false"
Block containers from mounting host filesystem paths:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
annotations:
policies.kyverno.io/title: Disallow Host Path
policies.kyverno.io/category: Pod Security Standards (Baseline)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod,Volume
policies.kyverno.io/description: >-
HostPath volumes let Pods use host directories and volumes in containers.
Using host resources can be used to access shared data or escalate privileges
and should not be allowed.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
HostPath volumes are forbidden. The field spec.volumes[*].hostPath must be unset.
pattern:
spec:
=(volumes):
- X(hostPath): "null"
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
Block containers from adding dangerous Linux capabilities:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-capabilities-strict
annotations:
policies.kyverno.io/title: Disallow Capabilities (Strict)
policies.kyverno.io/category: Pod Security Standards (Restricted)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Adding capabilities other than `NET_BIND_SERVICE` is disallowed. In addition,
all containers must explicitly drop `ALL` capabilities.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-drop-all
match:
any:
- resources:
kinds:
- Pod
preconditions:
all:
- key: "{{ request.operation || 'BACKGROUND' }}"
operator: NotEquals
value: DELETE
validate:
message: >-
Containers must drop `ALL` capabilities.
foreach:
- list: request.object.spec.[ephemeralContainers, initContainers, containers][]
deny:
conditions:
all:
- key: ALL
operator: AnyNotIn
value: "{{ element.securityContext.capabilities.drop || `[]` }}"
- name: adding-capabilities
match:
any:
- resources:
kinds:
- Pod
preconditions:
all:
- key: "{{ request.operation || 'BACKGROUND' }}"
operator: NotEquals
value: DELETE
validate:
message: >-
Any capabilities added other than NET_BIND_SERVICE are disallowed.
foreach:
- list: request.object.spec.[ephemeralContainers, initContainers, containers][]
deny:
conditions:
any:
- key: "{{ element.securityContext.capabilities.add || `[]` }}"
operator: AnyNotIn
value:
- NET_BIND_SERVICE
Ensure containers run as non-root users:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-nonroot
annotations:
policies.kyverno.io/title: Require Run As Non-Root User
policies.kyverno.io/category: Pod Security Standards (Restricted)
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Containers must run as a non-root user. This policy ensures runAsNonRoot is set to true.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: run-as-non-root
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Running as root is not allowed. Either the field spec.securityContext.runAsNonRoot
must be set to true, or the field spec.containers[*].securityContext.runAsNonRoot
must be set to true.
anyPattern:
- spec:
securityContext:
runAsNonRoot: "true"
- spec:
containers:
- securityContext:
runAsNonRoot: "true"
Different security levels for different environments:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: environment-container-security
spec:
validationFailureAction: Enforce
background: true
rules:
# Production: Strict security
- name: production-strict-security
match:
any:
- resources:
kinds:
- Pod
namespaces:
- production
- prod-*
validate:
message: "Production environments require strict container security"
pattern:
spec:
=(hostPID): "false"
=(hostIPC): "false"
=(hostNetwork): "false"
securityContext:
runAsNonRoot: "true"
containers:
- securityContext:
privileged: "false"
runAsNonRoot: "true"
capabilities:
drop:
- ALL
# Development: More permissive but still secure
- name: development-basic-security
match:
any:
- resources:
kinds:
- Pod
namespaces:
- development
- dev-*
- staging
validate:
message: "Development environments require basic container security"
pattern:
spec:
=(hostPID): "false"
=(hostIPC): "false"
containers:
- securityContext:
=(privileged): "false"
Allow specific workloads with controlled exceptions:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: workload-specific-security
spec:
validationFailureAction: Enforce
background: true
rules:
- name: system-workloads-exception
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
- kyverno
- resources:
kinds:
- Pod
names:
- "monitoring-*"
- "logging-*"
validate:
message: "Container security policies apply to application workloads"
pattern:
spec:
=(hostNetwork): "false"
containers:
- securityContext:
=(privileged): "false"
# This should be blocked
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-privileged
spec:
containers:
- name: test
image: nginx
securityContext:
privileged: true
EOF
# This should be blocked
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-host-network
spec:
hostNetwork: true
containers:
- name: test
image: nginx
EOF
# This should be blocked
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- name: test
image: nginx
volumeMounts:
- name: host-vol
mountPath: /host
volumes:
- name: host-vol
hostPath:
path: /
EOF
# This should be allowed
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-secure
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: test
image: nginx
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
EOF
spec:
validationFailureAction: Audit # Start with warnings, not blocking
exclude:
any:
- resources:
namespaces:
- kube-system
- kyverno
- kube-public