Harden Docker containers and Kubernetes clusters against attacks. Learn image scanning, Pod Security Standards, network policies, RBAC, and runtime security with Falco.
Container Security: Docker and Kubernetes Hardening
Secure Dockerfile Best Practices
# Use minimal base image
FROM node:20-alpine3.19 # Not node:latest or node:20
# Run as non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# Don't copy unnecessary files
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production # No devDependencies
COPY --chown=appuser:appgroup src/ ./src/
# Read-only filesystem where possible
RUN mkdir -p /tmp/uploads && chmod 770 /tmp/uploads
# Drop capabilities
# Handled at runtime with: --cap-drop ALL --cap-add NET_BIND_SERVICE
# Health check
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
# No secrets in ENV or ARG
# ENV DATABASE_URL=... <- NEVER DO THIS
EXPOSE 3000
CMD ["node", "src/server.js"]
Image Vulnerability Scanning
# Trivy - comprehensive scanner
trivy image myapp:v1.0 --severity HIGH,CRITICAL
# Fail CI if critical vulnerabilities found
trivy image myapp:v1.0 --exit-code 1 --severity CRITICAL
# Scan filesystem
trivy fs . --severity HIGH,CRITICAL
# Generate SARIF report for GitHub Actions
trivy image myapp:v1.0 --format sarif --output trivy-results.sarif
# GitHub Actions integration
# - uses: aquasecurity/trivy-action@master
# with:
# image-ref: 'myapp:v1.0'
# format: 'sarif'
# severity: 'CRITICAL,HIGH'
# exit-code: '1'
# Grype alternative
grype myapp:v1.0 --fail-on high
Kubernetes Pod Security
# Pod Security Standard - Restricted
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
---
# Secure Pod template
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault # Use default seccomp profile
containers:
- name: myapp
image: myapp:v1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL # Drop all capabilities
add:
- NET_BIND_SERVICE # Only if binding to port < 1024
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
- name: tmp
mountPath: /tmp # For writable temp dir with read-only FS
volumes:
- name: tmp
emptyDir: {}
automountServiceAccountToken: false # Disable unless needed
RBAC Least Privilege
# Service account with minimal permissions
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: production
---
# Role - only what's needed
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp-role
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"] # Read-only
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["myapp-secret"] # Specific secret only
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: myapp-sa
roleRef:
kind: Role
name: myapp-role
apiGroup: rbac.authorization.k8s.io
Runtime Security with Falco
# falco-rules.yaml - custom rules
- rule: Unexpected Network Connection
desc: Detect unexpected outbound connections from containers
condition: >
outbound and
container.name startswith "myapp" and
not fd.net in (allowed_networks)
output: >
Unexpected connection from %container.name
(dest=%fd.net.sport user=%user.name cmd=%proc.cmdline)
priority: WARNING
- rule: Shell in Container
desc: Shell spawned in production container
condition: >
spawned_process and
container.name startswith "myapp" and
proc.name in (shell_binaries)
output: >
Shell spawned in container %container.name
(user=%user.name shell=%proc.name)
priority: CRITICAL
- rule: Write to Sensitive File
desc: Write to sensitive file path
condition: >
write_to_sensitive_file and
container.name startswith "myapp"
priority: HIGH
Container Security Checklist
| Area |
Control |
| Image |
Minimal base, no root, scan vulns |
| Runtime |
Read-only FS, drop capabilities |
| Network |
Network policies, no hostNetwork |
| RBAC |
Least privilege SA, no cluster-admin |
| Secrets |
External secrets, no env vars |
| Monitoring |
Falco runtime, audit logs |