feat(security): add Pod Security Standards (PSA) namespace configurations

- Add namespace templates for privileged, baseline, and restricted levels
- Include compliant deployment examples for baseline and restricted
- Add migration audit script for checking namespace compliance
- Document PSA levels, enforcement modes, and migration strategy

Follows Kubernetes Pod Security Admission best practices for 2025+.
Reference: https://kubernetes.io/docs/concepts/security/pod-security-standards/
This commit is contained in:
Greg Hendrickson
2026-02-06 18:02:00 +00:00
parent ef86c1a6c7
commit 58e8140f36
8 changed files with 380 additions and 1 deletions

View File

@@ -0,0 +1,74 @@
# Example deployment compliant with BASELINE Pod Security Standard
# Suitable for most application workloads
apiVersion: apps/v1
kind: Deployment
metadata:
name: standard-app
namespace: baseline-apps
labels:
app: standard-app
security.kubernetes.io/compliant: "baseline"
spec:
replicas: 2
selector:
matchLabels:
app: standard-app
template:
metadata:
labels:
app: standard-app
spec:
# Baseline allows running as root, but we still recommend non-root
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.27
ports:
- containerPort: 80
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
# Baseline allows writable root filesystem
# readOnlyRootFilesystem: false # default
capabilities:
drop:
- ALL
add:
# Baseline allows these capabilities
- NET_BIND_SERVICE
- CHOWN
- SETGID
- SETUID
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
# Service account with minimal permissions
serviceAccountName: default
automountServiceAccountToken: false

View File

@@ -0,0 +1,105 @@
# Example deployment compliant with RESTRICTED Pod Security Standard
# This is the gold standard for secure workloads
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: restricted-apps
labels:
app: secure-app
security.kubernetes.io/compliant: "restricted"
spec:
replicas: 2
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
# Pod-level security context
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody user
runAsGroup: 65534
fsGroup: 65534
seccompProfile:
type: RuntimeDefault
# Prevent service account token auto-mount unless needed
automountServiceAccountToken: false
containers:
- name: app
image: nginx:1.27-alpine
ports:
- containerPort: 8080
protocol: TCP
# Container-level security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
capabilities:
drop:
- ALL
# Only add NET_BIND_SERVICE if binding to ports < 1024
# add:
# - NET_BIND_SERVICE
# Resource limits (required for production)
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
# Probes for reliability
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# Volume mounts for writable paths (since root is read-only)
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
# EmptyDir for ephemeral writable storage
- name: tmp
emptyDir:
sizeLimit: 100Mi
- name: cache
emptyDir:
sizeLimit: 100Mi
- name: run
emptyDir:
sizeLimit: 10Mi
# Topology spread for high availability
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: secure-app