mirror of
https://github.com/ghndrx/k8s-manifests.git
synced 2026-02-09 22:35:01 +00:00
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:
@@ -15,12 +15,14 @@ Production-ready Kubernetes manifests with security best practices, resource lim
|
||||
├── secrets/ # Secret management patterns
|
||||
├── networkpolicies/ # Network isolation
|
||||
├── rbac/ # Role-based access control
|
||||
└── monitoring/ # Prometheus, alerts, ServiceMonitors
|
||||
├── monitoring/ # Prometheus, alerts, ServiceMonitors
|
||||
└── pod-security/ # Pod Security Standards (PSA) configuration
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ Security contexts and pod security standards
|
||||
- ✅ **Pod Security Admission (PSA)** namespace configurations
|
||||
- ✅ Resource requests/limits
|
||||
- ✅ Liveness/readiness probes
|
||||
- ✅ Network policies for isolation
|
||||
|
||||
57
pod-security/README.md
Normal file
57
pod-security/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Pod Security Standards (PSS) Configuration
|
||||
|
||||
Kubernetes Pod Security Admission (PSA) enforces the [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) at the namespace level.
|
||||
|
||||
## Security Levels
|
||||
|
||||
| Level | Description | Use Case |
|
||||
|-------|-------------|----------|
|
||||
| **Privileged** | Unrestricted, allows all capabilities | System workloads, CNI, monitoring agents |
|
||||
| **Baseline** | Prevents known privilege escalations | Most application workloads |
|
||||
| **Restricted** | Hardened, follows best practices | Sensitive/untrusted workloads |
|
||||
|
||||
## Enforcement Modes
|
||||
|
||||
- `enforce` - Rejects pods that violate the policy
|
||||
- `audit` - Logs violations but allows pods
|
||||
- `warn` - Sends warnings to users but allows pods
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Apply all namespace configurations
|
||||
kubectl apply -f namespaces/
|
||||
|
||||
# Test a deployment against restricted namespace
|
||||
kubectl apply -f examples/restricted-deployment.yaml -n restricted-apps
|
||||
```
|
||||
|
||||
## Namespace Configuration
|
||||
|
||||
Each namespace is configured with PSA labels:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
pod-security.kubernetes.io/enforce: restricted
|
||||
pod-security.kubernetes.io/enforce-version: latest
|
||||
pod-security.kubernetes.io/audit: restricted
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
1. Start with `audit` and `warn` modes to identify violations
|
||||
2. Fix non-compliant workloads
|
||||
3. Enable `enforce` mode
|
||||
|
||||
## Files
|
||||
|
||||
- `namespaces/` - Pre-configured namespaces for each security level
|
||||
- `examples/` - Compliant deployment examples for each level
|
||||
- `migration/` - Tools for auditing existing namespaces
|
||||
|
||||
## References
|
||||
|
||||
- [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
|
||||
- [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
|
||||
- [Migrate from PSP](https://kubernetes.io/docs/tasks/configure-pod-container/migrate-from-psp/)
|
||||
74
pod-security/examples/baseline-deployment.yaml
Normal file
74
pod-security/examples/baseline-deployment.yaml
Normal 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
|
||||
105
pod-security/examples/restricted-deployment.yaml
Normal file
105
pod-security/examples/restricted-deployment.yaml
Normal 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
|
||||
52
pod-security/migration/audit-namespaces.sh
Executable file
52
pod-security/migration/audit-namespaces.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# audit-namespaces.sh - Check PSA compliance across all namespaces
|
||||
# Usage: ./audit-namespaces.sh [restricted|baseline]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
LEVEL="${1:-restricted}"
|
||||
|
||||
echo "=== Pod Security Standards Compliance Audit ==="
|
||||
echo "Target level: $LEVEL"
|
||||
echo "Date: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo ""
|
||||
|
||||
# Get all namespaces
|
||||
NAMESPACES=$(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}')
|
||||
|
||||
for NS in $NAMESPACES; do
|
||||
# Skip system namespaces
|
||||
if [[ "$NS" == "kube-system" || "$NS" == "kube-public" || "$NS" == "kube-node-lease" ]]; then
|
||||
echo "[$NS] SKIPPED (system namespace)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check current PSA labels
|
||||
CURRENT_LEVEL=$(kubectl get namespace "$NS" -o jsonpath='{.metadata.labels.pod-security\.kubernetes\.io/enforce}' 2>/dev/null || echo "none")
|
||||
|
||||
# Dry-run label to check violations
|
||||
echo ""
|
||||
echo "=== Namespace: $NS (current: $CURRENT_LEVEL) ==="
|
||||
|
||||
# Use --dry-run to preview what would be blocked
|
||||
kubectl label namespace "$NS" \
|
||||
"pod-security.kubernetes.io/enforce=$LEVEL" \
|
||||
"pod-security.kubernetes.io/warn=$LEVEL" \
|
||||
--dry-run=server \
|
||||
--overwrite 2>&1 | grep -E "(Warning|Error)" || echo "✓ No violations detected"
|
||||
|
||||
# List pods that might violate
|
||||
echo ""
|
||||
echo "Pods in namespace:"
|
||||
kubectl get pods -n "$NS" -o wide --no-headers 2>/dev/null | head -5 || echo " (no pods)"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Audit Complete ==="
|
||||
echo ""
|
||||
echo "To apply restricted level to a namespace:"
|
||||
echo " kubectl label namespace <name> \\"
|
||||
echo " pod-security.kubernetes.io/enforce=restricted \\"
|
||||
echo " pod-security.kubernetes.io/audit=restricted \\"
|
||||
echo " pod-security.kubernetes.io/warn=restricted \\"
|
||||
echo " --overwrite"
|
||||
30
pod-security/namespaces/baseline.yaml
Normal file
30
pod-security/namespaces/baseline.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
# Baseline namespace - for most application workloads
|
||||
# Prevents known privilege escalations while allowing common configurations
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: baseline-apps
|
||||
labels:
|
||||
# PSA labels - baseline enforcement with restricted auditing
|
||||
pod-security.kubernetes.io/enforce: baseline
|
||||
pod-security.kubernetes.io/enforce-version: latest
|
||||
pod-security.kubernetes.io/audit: restricted # Audit at higher level
|
||||
pod-security.kubernetes.io/audit-version: latest
|
||||
pod-security.kubernetes.io/warn: restricted # Warn about restricted violations
|
||||
pod-security.kubernetes.io/warn-version: latest
|
||||
# Metadata
|
||||
environment: production
|
||||
security-level: baseline
|
||||
annotations:
|
||||
description: "Baseline security for standard application workloads"
|
||||
---
|
||||
# Baseline allows:
|
||||
# - Default container configurations
|
||||
# - Non-privileged containers
|
||||
# - Standard capabilities (NET_BIND_SERVICE, etc.)
|
||||
#
|
||||
# Baseline blocks:
|
||||
# - Privileged containers
|
||||
# - Host namespaces (hostPID, hostIPC, hostNetwork)
|
||||
# - Host path volumes
|
||||
# - Privileged capabilities
|
||||
25
pod-security/namespaces/privileged.yaml
Normal file
25
pod-security/namespaces/privileged.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
# Privileged namespace - for system-level workloads only
|
||||
# Use sparingly: CNI plugins, monitoring agents, storage drivers
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: privileged-system
|
||||
labels:
|
||||
# PSA labels - privileged level
|
||||
pod-security.kubernetes.io/enforce: privileged
|
||||
pod-security.kubernetes.io/enforce-version: latest
|
||||
pod-security.kubernetes.io/audit: privileged
|
||||
pod-security.kubernetes.io/warn: privileged
|
||||
# Metadata
|
||||
environment: system
|
||||
security-level: privileged
|
||||
annotations:
|
||||
description: "Privileged namespace for system workloads requiring host access"
|
||||
---
|
||||
# Example: kube-system should typically be privileged
|
||||
# To label an existing namespace:
|
||||
# kubectl label namespace kube-system \
|
||||
# pod-security.kubernetes.io/enforce=privileged \
|
||||
# pod-security.kubernetes.io/audit=privileged \
|
||||
# pod-security.kubernetes.io/warn=privileged \
|
||||
# --overwrite
|
||||
34
pod-security/namespaces/restricted.yaml
Normal file
34
pod-security/namespaces/restricted.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
# Restricted namespace - maximum security hardening
|
||||
# For sensitive workloads and untrusted code
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: restricted-apps
|
||||
labels:
|
||||
# PSA labels - restricted at all levels
|
||||
pod-security.kubernetes.io/enforce: restricted
|
||||
pod-security.kubernetes.io/enforce-version: latest
|
||||
pod-security.kubernetes.io/audit: restricted
|
||||
pod-security.kubernetes.io/audit-version: latest
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
pod-security.kubernetes.io/warn-version: latest
|
||||
# Metadata
|
||||
environment: production
|
||||
security-level: restricted
|
||||
annotations:
|
||||
description: "Restricted security for sensitive and untrusted workloads"
|
||||
---
|
||||
# Restricted REQUIRES:
|
||||
# - runAsNonRoot: true
|
||||
# - allowPrivilegeEscalation: false
|
||||
# - Drop ALL capabilities (except NET_BIND_SERVICE)
|
||||
# - seccompProfile: RuntimeDefault or Localhost
|
||||
# - Read-only root filesystem (recommended)
|
||||
#
|
||||
# Restricted BLOCKS:
|
||||
# - Everything baseline blocks, plus:
|
||||
# - Running as root
|
||||
# - Privilege escalation
|
||||
# - Most capabilities
|
||||
# - HostPath volumes
|
||||
# - Writable root filesystems (warning only)
|
||||
Reference in New Issue
Block a user