Workload Hardening

Workload hardening involves applying multiple layers of security controls to your containers and pods. Think of it like securing a house—you don’t rely on just a front door lock; you add window locks, an alarm system, and security cameras. Similarly, workload hardening uses multiple security mechanisms working together.

Defense in Depth

Workload hardening follows the principle of defense in depth—multiple security layers that protect your applications even if one layer fails:

graph TB A[Application] --> B[Container SecurityContext] B --> C[Linux Capabilities] C --> D[Seccomp Profile] D --> E[AppArmor Profile] E --> F[Network Policies] F --> G[RBAC] style A fill:#e1f5ff style B fill:#fff4e1 style C fill:#fff4e1 style D fill:#fff4e1 style E fill:#fff4e1 style F fill:#e8f5e9 style G fill:#e8f5e9

Security Layers

1. SecurityContext

Controls fundamental security settings at the pod and container level:

  • User and group IDs
  • File system permissions
  • Privilege escalation
  • Read-only root filesystem

2. Linux Capabilities

Grants specific privileges instead of full root access:

  • Drop unnecessary capabilities
  • Add only required capabilities
  • Prevents privilege escalation

3. Seccomp Profiles

Restricts system calls available to containers:

  • Blocks dangerous system calls
  • Reduces attack surface
  • Prevents kernel exploitation

4. AppArmor Profiles

Defines what resources a container can access:

  • File system access control
  • Network access restrictions
  • Process execution limits

Why Hardening Matters

Without proper hardening, containers run with excessive privileges:

  • Root access - Containers can modify system files
  • All capabilities - Containers can perform privileged operations
  • All system calls - Containers can make dangerous kernel calls
  • Full network access - Containers can communicate with any service

Hardening reduces the attack surface and limits damage from compromised containers.

Practical Example

Here’s a hardened pod configuration using multiple security layers:

apiVersion: v1
kind: Pod
metadata:
  name: hardened-app
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:latest
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
        add:
        - NET_BIND_SERVICE
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: cache
      mountPath: /var/cache/nginx
  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

This configuration:

  • Runs as non-root user (UID 1000)
  • Uses read-only root filesystem
  • Drops all capabilities, adds only NET_BIND_SERVICE
  • Uses default seccomp profile
  • Prevents privilege escalation

Best Practices

  1. Start with SecurityContext - Set basic security parameters first
  2. Drop all capabilities - Add back only what’s needed
  3. Use read-only root filesystem - Mount writable directories as volumes
  4. Run as non-root - Always use non-zero user IDs
  5. Enable seccomp - Use RuntimeDefault or custom profiles
  6. Test thoroughly - Ensure applications work with restrictions
  7. Document exceptions - If privileged access is needed, document why

Common Patterns

Web Application

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  seccompProfile:
    type: RuntimeDefault
containers:
- securityContext:
    allowPrivilegeEscalation: false
    readOnlyRootFilesystem: true
    capabilities:
      drop: ["ALL"]

Database Container

May need additional capabilities for performance:

securityContext:
  runAsNonRoot: true
  runAsUser: 999
containers:
- securityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop: ["ALL"]
      add: ["CHOWN", "DAC_OVERRIDE"]

System Container

For containers that need more privileges (use sparingly):

securityContext:
  runAsUser: 0
containers:
- securityContext:
    privileged: false
    capabilities:
      add: ["SYS_ADMIN", "NET_ADMIN"]

Migration Strategy

  1. Audit current state - Identify which workloads need hardening
  2. Start with low-risk workloads - Begin with stateless applications
  3. Test incrementally - Add restrictions one at a time
  4. Monitor for issues - Watch for permission denied errors
  5. Document exceptions - Keep track of workloads that need special permissions

Topics

See Also