feat(deployments): add PSS-restricted base template with Kustomize

- Namespace with Pod Security Standards restricted enforcement
- Deployment with full security context (non-root, read-only fs, no caps)
- Resource limits, health probes, topology spread
- Service and comprehensive README
- Kustomize structure for overlay-based customization
This commit is contained in:
2026-01-31 18:01:18 +00:00
parent 2b8954d54b
commit ef86c1a6c7
5 changed files with 220 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
# Deployment Base Template
Production-ready Kubernetes deployment with **Pod Security Standards (PSS) restricted** compliance.
## Security Features
This template enforces the most restrictive Pod Security Standard:
-**Non-root execution** - Pods run as UID 1000
-**Read-only root filesystem** - Prevents runtime modifications
-**No privilege escalation** - `allowPrivilegeEscalation: false`
-**All capabilities dropped** - Minimal Linux capabilities
-**Seccomp profile** - RuntimeDefault seccomp filtering
-**Resource limits** - CPU and memory constraints
## Usage
### Deploy directly
```bash
kubectl apply -k .
```
### Use as a base with overlays
```yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: replicas-patch.yaml
```
## Customization Points
| Field | Default | Description |
|-------|---------|-------------|
| `replicas` | 2 | Number of pod replicas |
| `image` | nginx:1.27-alpine | Container image |
| `resources.requests.cpu` | 100m | CPU request |
| `resources.requests.memory` | 128Mi | Memory request |
| `resources.limits.cpu` | 500m | CPU limit |
| `resources.limits.memory` | 256Mi | Memory limit |
## Pod Security Standards Reference
The namespace is configured with PSS labels:
```yaml
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
```
See: https://kubernetes.io/docs/concepts/security/pod-security-standards/
## Health Probes
- **Liveness**: `/healthz` - Restart if unhealthy
- **Readiness**: `/ready` - Remove from service if not ready
- **Startup**: `/healthz` - Allow up to 150s for startup

View File

@@ -0,0 +1,116 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app.kubernetes.io/name: app
app.kubernetes.io/component: server
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: app
template:
metadata:
labels:
app.kubernetes.io/name: app
app.kubernetes.io/component: server
spec:
# Pod-level security context for PSS restricted compliance
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
# Graceful shutdown
terminationGracePeriodSeconds: 30
containers:
- name: app
image: nginx:1.27-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
# Container-level security context (PSS restricted)
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
# Resource management - ALWAYS set these
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
# Health probes
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Startup probe for slow-starting apps
startupProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30 # 150 seconds max startup
# Volume mounts for read-only root filesystem
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
# Spread pods across nodes
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: app

View File

@@ -0,0 +1,15 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- deployment.yaml
- service.yaml
labels:
- pairs:
app.kubernetes.io/managed-by: kustomize
includeSelectors: false
# Default namespace for all resources
namespace: app-production

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Namespace
metadata:
name: app-production
labels:
# Pod Security Standards - enforce restricted profile
# See: https://kubernetes.io/docs/concepts/security/pod-security-standards/
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

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: app
labels:
app.kubernetes.io/name: app
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: app
ports:
- name: http
port: 80
targetPort: http
protocol: TCP