KCSA — Resource Limits & DoS Prevention
Why Resource Limits Matter for Security
In Kubernetes, any pod that doesn’t have resource limits can consume unlimited CPU, memory, and storage on a node. This creates a serious security risk:
- A compromised container can starve other workloads of resources
- A fork bomb can crash an entire node
- A memory leak can trigger the OOM killer, disrupting co-located pods
- An attacker can launch a denial-of-service (DoS) attack from within the cluster
Resource limits aren’t just an operational best practice — they’re a security control.
Resource Requests vs Limits
Kubernetes uses two fields to manage container resources:
| Field | Purpose | What Happens |
|---|---|---|
| requests | Minimum resources guaranteed to the container | Used by the scheduler for pod placement |
| limits | Maximum resources the container can use | Enforced by the kubelet at runtime |
YAML Example
containers:
- name: app
image: myapp:1.0
resources:
requests:
cpu: "100m" # Guaranteed 0.1 CPU core
memory: "128Mi" # Guaranteed 128 MiB memory
limits:
cpu: "500m" # Cannot exceed 0.5 CPU core
memory: "256Mi" # Cannot exceed 256 MiB memory
What Happens When Limits Are Exceeded?
The behavior differs between CPU and memory:
| Resource | When Limit Is Exceeded | Effect |
|---|---|---|
| CPU | Container is throttled | Pod continues running but slower — CPU cycles are restricted |
| Memory | Container is OOMKilled | Pod is terminated and restarted (OOM = Out of Memory) |
Key Distinction: CPU is a compressible resource (can be throttled). Memory is an incompressible resource (cannot be reclaimed without killing the process).
LimitRange — Default Limits per Namespace
A LimitRange sets default, minimum, and maximum resource constraints for containers in a namespace. It applies automatically to pods that don’t specify their own resource requests/limits.
Key Features
| Feature | Description |
|---|---|
| Default values | Automatically applied to containers without explicit resources |
| Min/Max enforcement | Rejects pods that request resources outside the range |
| Per-container | Applies to individual containers, not the pod as a whole |
| Namespace-scoped | Each namespace can have its own LimitRange |
YAML Example
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: production
spec:
limits:
- type: Container
default: # Applied if no limit is specified
cpu: "500m"
memory: "256Mi"
defaultRequest: # Applied if no request is specified
cpu: "100m"
memory: "128Mi"
max: # Maximum allowed
cpu: "2"
memory: "1Gi"
min: # Minimum allowed
cpu: "50m"
memory: "64Mi"
With this LimitRange:
- A container with no resources gets
requests: {cpu: 100m, memory: 128Mi}andlimits: {cpu: 500m, memory: 256Mi} - A container requesting more than max (e.g., 4 CPU) is rejected
- A container requesting less than min (e.g., 10m CPU) is rejected
LimitRange for Pods
You can also set limits at the pod level:
spec:
limits:
- type: Pod
max:
cpu: "4"
memory: "4Gi"
ResourceQuota — Aggregate Limits per Namespace
A ResourceQuota sets total resource limits for an entire namespace. Unlike LimitRange (per-container), ResourceQuota limits the sum of all resources consumed by all pods in the namespace.
YAML Example
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
namespace: production
spec:
hard:
requests.cpu: "10" # Total CPU requests across all pods
requests.memory: "20Gi" # Total memory requests across all pods
limits.cpu: "20" # Total CPU limits across all pods
limits.memory: "40Gi" # Total memory limits across all pods
pods: "50" # Maximum 50 pods in this namespace
services: "10" # Maximum 10 services
persistentvolumeclaims: "20" # Maximum 20 PVCs
configmaps: "50" # Maximum 50 ConfigMaps
secrets: "100" # Maximum 100 Secrets
Key Points
- When a ResourceQuota is active, all pods must specify resource requests and limits (or have them applied via LimitRange). Otherwise, the pod is rejected.
- ResourceQuota prevents a single namespace from monopolizing cluster resources
- Especially important in multi-tenant environments
LimitRange vs ResourceQuota
| Aspect | LimitRange | ResourceQuota |
|---|---|---|
| Scope | Per-container/pod | Per-namespace (aggregate) |
| Purpose | Set defaults and min/max per container | Limit total resources for the namespace |
| When applied | At container creation time | Continuously tracked |
| What it controls | Individual container resources | Sum of all resources in namespace |
| Use together? | ✅ Yes — complementary controls | ✅ Yes — complementary controls |
Best Practice: Use both together. LimitRange sets sane defaults per container. ResourceQuota caps the total for the namespace.
Quality of Service (QoS) Classes
Kubernetes assigns a QoS class to each pod based on its resource configuration. The QoS class determines which pods are evicted first when a node runs out of resources.
| QoS Class | Condition | Eviction Priority |
|---|---|---|
| Guaranteed | Every container has requests == limits for both CPU and memory |
Last to evict (highest priority) |
| Burstable | At least one container has requests < limits, or only requests set |
Middle priority |
| BestEffort | No containers have any requests or limits set | First to evict (lowest priority) |
Examples
Guaranteed:
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "500m" # Same as requests
memory: "256Mi" # Same as requests
Burstable:
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m" # Different from requests
memory: "256Mi" # Different from requests
BestEffort:
# No resources section at all
containers:
- name: app
image: myapp:1.0
# No resources specified
Security Implication: BestEffort pods are evicted first but can consume unlimited resources until eviction. In a security context, always ensure at least Burstable QoS (set requests) to avoid unpredictable resource use.
DoS Attack Vectors in Kubernetes
Attackers — or even buggy workloads — can cause denial of service through several vectors:
| Attack Vector | Description | Impact |
|---|---|---|
| Fork bomb | Process creates unlimited child processes | Node CPU and memory exhaustion |
| Memory leak | Container allocates memory without releasing it | OOM kills on the node |
| CPU spin | Infinite loop consuming all CPU | Other pods starved of CPU |
| Pod flooding | Creating thousands of pods via compromised service account | API server overload, node exhaustion |
| Storage exhaustion | Writing unlimited data to volumes or container filesystem | Node disk full, all pods affected |
| Network flooding | Generating massive network traffic | Network saturation, pod unreachability |
| Log bombing | Writing excessive logs to stdout/stderr | Disk exhaustion on the node |
Prevention Strategies
| Attack Vector | Prevention | Kubernetes Resource |
|---|---|---|
| Fork bomb | Set PID limits per pod | kubelet --pod-max-pids or PodPidsLimit feature |
| Memory leak | Set memory limits | resources.limits.memory |
| CPU spin | Set CPU limits | resources.limits.cpu |
| Pod flooding | Limit pod count per namespace | ResourceQuota (pods: N) |
| Storage exhaustion | Set ephemeral storage limits | resources.limits.ephemeral-storage, emptyDir.sizeLimit |
| Network flooding | Apply network policies + rate limits | NetworkPolicy + CNI features |
| Log bombing | Set container log rotation on kubelet | --container-log-max-size, --container-log-max-files |
Ephemeral Storage Limits
Containers can write to the node’s local filesystem (container writable layer, logs, emptyDir). Limit this with:
resources:
requests:
ephemeral-storage: "1Gi"
limits:
ephemeral-storage: "2Gi"
PID Limits
To prevent fork bombs, configure the kubelet to limit PIDs per pod:
# kubelet configuration
podPidsLimit: 1024 # Maximum 1024 processes per pod
Comprehensive Security Example
A namespace with full resource controls:
# Step 1: LimitRange — defaults for every container
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "256Mi"
ephemeral-storage: "1Gi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
ephemeral-storage: "500Mi"
max:
cpu: "2"
memory: "2Gi"
min:
cpu: "50m"
memory: "64Mi"
---
# Step 2: ResourceQuota — cap total namespace usage
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
pods: "100"
services: "20"
persistentvolumeclaims: "50"
Key Takeaways for the Exam
-
Requests = guaranteed minimum (used for scheduling). Limits = enforced maximum (throttle or kill).
-
CPU is compressible (throttled when limit exceeded). Memory is incompressible (OOMKilled when limit exceeded).
-
LimitRange sets per-container defaults, min, and max. ResourceQuota sets per-namespace aggregate limits.
-
QoS classes: Guaranteed (requests == limits, last evicted), Burstable (requests < limits, middle), BestEffort (no requests/limits, first evicted).
-
Always use resource limits — pods without limits can consume unlimited resources, enabling DoS attacks.
-
Use ResourceQuota with
pods: Nto prevent pod flooding attacks. -
LimitRange and ResourceQuota are complementary — use both for comprehensive resource control.
-
When ResourceQuota is active, all pods must specify resources (manually or via LimitRange defaults).
Next: Practice Questions — test your knowledge of pod and network security concepts.