HackBlue

Tools · Containers and Kubernetes security · 16 / 20

Kubernetes requests, limits, ResourceQuota, and LimitRange as security controls

See how missing limits let one workload starve a node, set requests and limits, and use ResourceQuota and LimitRange to keep namespaces within bounds.

8 min read · practice only with authorization

Availability is security

A pod without limits can consume all CPU and memory on a node, whether through a bug, a traffic spike, or abuse such as cryptomining in a compromised container. Requests tell the scheduler what a pod needs; limits cap what it can use. Exceeding a memory limit gets the container OOM-killed; exceeding a CPU limit throttles it.

Namespace guardrails

A LimitRange sets default and maximum requests and limits for containers in a namespace, so pods created without them still get sensible values. A ResourceQuota caps the namespace total: CPU, memory, number of pods, services of type LoadBalancer, and more.

Snippet
apiVersion: v1
kind: LimitRange
metadata: { name: defaults, namespace: team-a }
spec:
  limits:
    - type: Container
      default: { cpu: 500m, memory: 256Mi }
      defaultRequest: { cpu: 100m, memory: 128Mi }
      max: { cpu: '2', memory: 1Gi }
---
apiVersion: v1
kind: ResourceQuota
metadata: { name: team-a-quota, namespace: team-a }
spec:
  hard:
    requests.cpu: '4'
    requests.memory: 8Gi
    limits.memory: 16Gi
    pods: '40'
    services.loadbalancers: '0'

Lab: hit the limits

Apply the objects above to a test namespace, create a pod without resources, and inspect it to see the defaults filled in. Run a memory stress container that inherits the 256Mi default limit and allocate more: kubectl describe shows the container terminated with reason OOMKilled. Try creating a LoadBalancer service and read the quota error.

Snippet
kubectl -n team-a run plain --image=nginx:1.27 && kubectl -n team-a get pod plain -o jsonpath='{.spec.containers[0].resources}'
kubectl -n team-a run hog --image=polinux/stress -- stress --vm 1 --vm-bytes 300M
kubectl -n team-a describe pod hog | grep -A3 'Last State'
kubectl -n team-a describe resourcequota

Monitoring

Unexpected sustained CPU at the limit in a workload that is usually idle is a classic cryptomining signal. Pair limits with alerts on CPU throttling and with runtime detection for unknown processes.

Diagram

Unbounded namespace versus guarded namespace

Defaults and caps contain mistakes and abuse.

Unbounded

Pod without limits. Can use the whole node

Namespace total. Unlimited

LoadBalancers. Anyone can expose one

Guarded

Pod without limits. Gets LimitRange defaults

Namespace total. Capped by ResourceQuota

LoadBalancers. Quota of 0 unless approved

Check yourself

1. A container exceeds its memory limit. What happens?

2. Which object gives pods default limits when none are specified?

3. How can you prevent a namespace from creating LoadBalancer services?