Security improvements for prod #1
Some checks failed
CI/CD Pipeline with Secure Ephemeral PiP / test-backend (push) Has been cancelled
CI/CD Pipeline with Secure Ephemeral PiP / test-frontend (push) Has been cancelled
CI/CD Pipeline with Secure Ephemeral PiP / build-backend (push) Has been cancelled
CI/CD Pipeline with Secure Ephemeral PiP / build-frontend (push) Has been cancelled

This commit is contained in:
continuist 2025-09-06 14:09:42 -04:00
parent 411d9f3f35
commit 18b88d6128
2 changed files with 33 additions and 11 deletions

View file

@ -2010,6 +2010,13 @@ The `prod-pod.yml` file is specifically designed for production deployment and u
- **Persistent storage**: PostgreSQL data is stored in a named volume for persistence - **Persistent storage**: PostgreSQL data is stored in a named volume for persistence
- **Environment variables**: Uses environment variables for configuration (set by the CI/CD workflow) - **Environment variables**: Uses environment variables for configuration (set by the CI/CD workflow)
**Security Enhancements**:
- **Rootless operation**: All containers run as non-root user (UID/GID 1000)
- **Read-only filesystems**: Containers have read-only root filesystems with writable volumes only for data
- **Dropped capabilities**: All Linux capabilities are dropped for maximum security
- **No privilege escalation**: Containers cannot escalate privileges
- **Simplified configuration**: No external configmaps - all configuration is inline for easier management
**Service Architecture**: **Service Architecture**:
1. **PostgreSQL**: Database with health checks and persistent storage 1. **PostgreSQL**: Database with health checks and persistent storage
2. **Backend**: Rust API service that waits for PostgreSQL to be healthy 2. **Backend**: Rust API service that waits for PostgreSQL to be healthy

View file

@ -1,14 +1,14 @@
apiVersion: v1 apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
name: prod-pod name: sharenet-production-pod
labels: labels:
app: sharenet-production app: sharenet-production
annotations: annotations:
io.containers.no-new-privileges: "true" io.containers.no-new-privileges: "true"
spec: spec:
hostname: prod-pod hostname: sharenet-production-pod
# Security: run as non-root user with specific UID/GID # Security: run as non-root user with specific UID/GID (matches PROD_SERVICE_USER)
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
runAsUser: 1000 runAsUser: 1000
@ -17,13 +17,20 @@ spec:
containers: containers:
- name: postgres - name: postgres
image: localhost/postgres:deployed image: ${REGISTRY_HOST}/${APP_NAME}/postgres:${IMAGE_TAG}
# Security: drop all capabilities, read-only root filesystem except data volume # Security: drop all capabilities, read-only root filesystem except data volume
securityContext: securityContext:
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop: ["ALL"] drop: ["ALL"]
env:
- name: POSTGRES_DB
value: sharenet
- name: POSTGRES_USER
value: sharenet
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
envFrom: envFrom:
- secretRef: - secretRef:
name: postgres-secrets name: postgres-secrets
@ -58,13 +65,18 @@ spec:
cpu: "500m" cpu: "500m"
- name: backend - name: backend
image: localhost/backend:deployed image: ${REGISTRY_HOST}/${APP_NAME}/backend:${IMAGE_TAG}
# Security: drop all capabilities, read-only root filesystem # Security: drop all capabilities, read-only root filesystem
securityContext: securityContext:
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop: ["ALL"] drop: ["ALL"]
env:
- name: DATABASE_URL
value: postgres://sharenet:${POSTGRES_PASSWORD}@localhost:5432/sharenet
- name: PORT
value: "3001"
envFrom: envFrom:
- secretRef: - secretRef:
name: backend-secrets name: backend-secrets
@ -99,13 +111,18 @@ spec:
cpu: "250m" cpu: "250m"
- name: frontend - name: frontend
image: localhost/frontend:deployed image: ${REGISTRY_HOST}/${APP_NAME}/frontend:${IMAGE_TAG}
# Security: drop all capabilities, read-only root filesystem # Security: drop all capabilities, read-only root filesystem
securityContext: securityContext:
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop: ["ALL"] drop: ["ALL"]
env:
- name: NEXT_PUBLIC_API_URL
value: http://localhost:3001
- name: PORT
value: "3000"
envFrom: envFrom:
- secretRef: - secretRef:
name: frontend-secrets name: frontend-secrets
@ -122,7 +139,7 @@ spec:
cpu: "250m" cpu: "250m"
- name: nginx - name: nginx
image: localhost/nginx:deployed image: ${REGISTRY_HOST}/${APP_NAME}/nginx:${IMAGE_TAG}
# Security: drop all capabilities, read-only root filesystem # Security: drop all capabilities, read-only root filesystem
securityContext: securityContext:
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
@ -132,10 +149,8 @@ spec:
ports: ports:
- containerPort: 80 - containerPort: 80
protocol: TCP protocol: TCP
hostPort: 80
- containerPort: 443 - containerPort: 443
protocol: TCP protocol: TCP
hostPort: 443
volumeMounts: volumeMounts:
- name: nginx-conf - name: nginx-conf
mountPath: /etc/nginx/nginx.conf mountPath: /etc/nginx/nginx.conf
@ -170,7 +185,7 @@ spec:
- name: pgdata - name: pgdata
hostPath: hostPath:
path: /opt/sharenet/volumes/pgdata path: /opt/sharenet/volumes/pgdata
type: Directory type: DirectoryOrCreate
- name: nginx-conf - name: nginx-conf
hostPath: hostPath:
path: /opt/sharenet/nginx path: /opt/sharenet/nginx
@ -178,7 +193,7 @@ spec:
- name: nginx-cache - name: nginx-cache
hostPath: hostPath:
path: /opt/sharenet/volumes/nginx-cache path: /opt/sharenet/volumes/nginx-cache
type: Directory type: DirectoryOrCreate
- name: letsencrypt - name: letsencrypt
hostPath: hostPath:
path: /etc/letsencrypt path: /etc/letsencrypt