Amazon EKS — Pod Security and Policy Engines
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
- Enforce
restrictedPSS on production namespaces —baselineas minimum - Use a policy engine (Kyverno or Gatekeeper) for custom organizational policies
- Enable GuardDuty EKS Protection — automated threat detection
- Drop all capabilities — add back only what’s needed (NET_BIND_SERVICE, etc.)
- Use
readOnlyRootFilesystem: true— prevents writes to container filesystem - Run as non-root —
runAsNonRoot: trueshould be enforced cluster-wide