DEV Community

Cover image for 5 Kubernetes YAML Anti-Patterns I Still See in Production (And How to Fix Them)
TheYAMLGuy
TheYAMLGuy

Posted on

5 Kubernetes YAML Anti-Patterns I Still See in Production (And How to Fix Them)

Unfortunately, I still see serious security risks in production environments. Therefore, I would like to highlight five common mistakes, explain their impact, and show how to fix them.


1. Using the latest Image Tag

Classic one.

# BAD: Using the latest tag
spec:
  containers:
  - name: app-container
    image: myregistry.azurecr.io/app:latest
Enter fullscreen mode Exit fullscreen mode

Why it's a problem:

This flaw opens the door to supply chain attacks. An attacker with access to the image registry can publish an infected version; Kubernetes would then deploy that infected version, resulting in a security incident.

Additionally, it breaks deterministic deployments, two pods started on different days might run completely different code versions without you realizing it.
How to fix it:

Always pin your container images to explicit semantic versions or immutable SHA-256 digests.

# GOOD: Using explicit versioning
spec:
  containers:
  - name: app-container
    image: myregistry.azurecr.io/app:v1.4.2
    imagePullPolicy: IfNotPresent
Enter fullscreen mode Exit fullscreen mode

  1. Running Containers as Root

By default, Kubernetes containers run as the root user unless you explicitly tell them not to.

# BAD: No security context defined
spec:
  containers:
  - name: web-app
    image: nginx
Enter fullscreen mode Exit fullscreen mode

Why it's a problem:

If an attacker exploits an application vulnerability (like a Remote Code Execution), they instantly get root privileges inside the container. This makes container escape attacks on the host node significantly easier.
How to fix it:

Enforce non-root execution via the securityContext.

# GOOD: Restricting privileges
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
  containers:
  - name: web-app
    image: nginxinc/nginx-unprivileged:alpine
    securityContext:
      allowPrivilegeEscalation: false
Enter fullscreen mode Exit fullscreen mode

  1. Omitting CPU and Memory Limits

Deploying workloads without setting boundaries for compute resources.

# BAD: Unbounded resource consumption
spec:
  containers:
  - name: backend
    image: backend-service:v1.0
Enter fullscreen mode Exit fullscreen mode

Why it's a problem:

A single pod with a memory leak can consume all available memory on a worker node. This triggers the Node OOM killer, causing unexpected evictions of other critical pods running on the same node.
How to fix it:

Define clear requests for scheduling and limits to set an absolute ceiling.

# GOOD: Explicit resource boundaries
spec:
  containers:
  - name: backend
    image: backend-service:v1.0
    resources:
      requests:
        memory: "256Mi"
        cpu: "100m"
      limits:
        memory: "512Mi"
        cpu: "500m"
Enter fullscreen mode Exit fullscreen mode

  1. Missing Liveness and Readiness Probes

Assuming Kubernetes knows your application state just because the process hasn't crashed.

# BAD: No health checks configured
spec:
  containers:
  - name: api
    image: api-service:v2.0
Enter fullscreen mode Exit fullscreen mode

Why it's a problem:

If your app takes 30 seconds to boot or gets deadlocked in a database connection loop, Kubernetes will still route live user traffic to it, resulting in HTTP 500 errors for your users.
How to fix it:

Add explicit readiness and liveness endpoints.

# GOOD: Probes configured
spec:
  containers:
  - name: api
    image: api-service:v2.0
    readinessProbe:
      httpGet:
        path: /healthz/ready
        port: 8080
    livenessProbe:
      httpGet:
        path: /healthz/live
        port: 8080
Enter fullscreen mode Exit fullscreen mode

  1. Hardcoding Secrets in ConfigMaps

Putting raw API keys, tokens, or passwords directly into plain-text manifests.

# BAD: Plain-text credentials
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DB_PASSWORD: "NothingToSeeHere"
Enter fullscreen mode Exit fullscreen mode

Why it's a problem:

ConfigMaps are stored unencrypted in etcd by default and can be read by anyone with basic namespace read access. They also frequently leak into system logs.
How to fix it:

Use native Kubernetes Secrets (encrypted at rest) or inject them via a Secret Manager (e.g., HashiCorp Vault, AWS Secrets Manager).

# GOOD: Referencing a secret object
spec:
  containers:
  - name: app
    image: app:v1.0
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password
Enter fullscreen mode Exit fullscreen mode

Fixing these five points, makes your cluster a bit safer.

Top comments (0)