Amazon EKS — Pod Security and Policy Engines

2 minute read

Pod security ensures containers don’t run with dangerous privileges. Kubernetes provides built-in Pod Security Standards, and EKS integrates with policy engines like OPA Gatekeeper and Kyverno for custom enforcement.


Pod Security Standards (PSS)

Kubernetes defines three security profiles:

Profile Description Use Case
Privileged No restrictions System-level workloads (CNI, CSI drivers)
Baseline Prevents known privilege escalations General workloads
Restricted Heavily restricted — best practice Security-sensitive applications

Pod Security Admission (PSA)

PSA enforces PSS at the namespace level using labels:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

PSA Modes

Mode Behavior
enforce Reject pods that violate the policy
audit Allow but log violations in audit log
warn Allow but show warning to user

Restricted-Compliant Pod

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: production
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: myapp:latest
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        runAsNonRoot: true
        capabilities:
          drop: ["ALL"]

OPA Gatekeeper

Gatekeeper enforces policies using Rego templates:

Install

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system --create-namespace

ConstraintTemplate — Require Labels

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }

Constraint

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
    namespaces: ["production"]
  parameters:
    labels: ["team", "cost-center"]

Kyverno

Kyverno uses Kubernetes-native YAML policies (no Rego):

Install

helm repo add kyverno https://kyverno.github.io/kyverno
helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace

Policy — Require Resource Limits

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "CPU and memory limits are required."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"

Policy — Mutate (Add Default Labels)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
    - name: add-labels
      match:
        any:
          - resources:
              kinds:
                - Deployment
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              managed-by: kyverno

Gatekeeper vs Kyverno

Feature Gatekeeper Kyverno
Policy language Rego (custom DSL) YAML (Kubernetes-native)
Learning curve Steep Low
Validation Yes Yes
Mutation Limited Yes (full)
Generation No Yes (create resources)
Audit Yes Yes (policy reports)
Community CNCF graduated CNCF incubating

Amazon GuardDuty for EKS

GuardDuty monitors EKS audit logs and runtime activity for threats:

# Enable EKS Protection
aws guardduty update-detector \
  --detector-id abcdef123 \
  --features '[{
    "Name": "EKS_AUDIT_LOGS",
    "Status": "ENABLED"
  }, {
    "Name": "EKS_RUNTIME_MONITORING",
    "Status": "ENABLED",
    "AdditionalConfiguration": [{
      "Name": "EKS_ADDON_MANAGEMENT",
      "Status": "ENABLED"
    }]
  }]'

What GuardDuty Detects

Category Examples
Privilege escalation Anonymous API calls, exec into privileged pods
Credential access Kubernetes secrets accessed from unusual sources
Crypto mining DNS queries to known mining pools
Malicious images Containers from known malicious registries
Runtime threats Reverse shells, suspicious file access

Best Practices

  1. Enforce restricted PSS on production namespaces — baseline as minimum
  2. Use a policy engine (Kyverno or Gatekeeper) for custom organizational policies
  3. Enable GuardDuty EKS Protection — automated threat detection
  4. Drop all capabilities — add back only what’s needed (NET_BIND_SERVICE, etc.)
  5. Use readOnlyRootFilesystem: true — prevents writes to container filesystem
  6. Run as non-root — runAsNonRoot: true should be enforced cluster-wide

Updated: