diff --git a/CI_CD_PIPELINE_SETUP_GUIDE.md b/CI_CD_PIPELINE_SETUP_GUIDE.md index 2352d1e..9fe2404 100644 --- a/CI_CD_PIPELINE_SETUP_GUIDE.md +++ b/CI_CD_PIPELINE_SETUP_GUIDE.md @@ -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 - **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**: 1. **PostgreSQL**: Database with health checks and persistent storage 2. **Backend**: Rust API service that waits for PostgreSQL to be healthy diff --git a/deploy/prod-pod.yml b/deploy/prod-pod.yml index 8383872..029e1bb 100644 --- a/deploy/prod-pod.yml +++ b/deploy/prod-pod.yml @@ -1,14 +1,14 @@ apiVersion: v1 kind: Pod metadata: - name: prod-pod + name: sharenet-production-pod labels: app: sharenet-production annotations: io.containers.no-new-privileges: "true" spec: - hostname: prod-pod - # Security: run as non-root user with specific UID/GID + hostname: sharenet-production-pod + # Security: run as non-root user with specific UID/GID (matches PROD_SERVICE_USER) securityContext: runAsNonRoot: true runAsUser: 1000 @@ -17,13 +17,20 @@ spec: containers: - 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 securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] + env: + - name: POSTGRES_DB + value: sharenet + - name: POSTGRES_USER + value: sharenet + - name: PGDATA + value: /var/lib/postgresql/data/pgdata envFrom: - secretRef: name: postgres-secrets @@ -58,13 +65,18 @@ spec: cpu: "500m" - name: backend - image: localhost/backend:deployed + image: ${REGISTRY_HOST}/${APP_NAME}/backend:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] + env: + - name: DATABASE_URL + value: postgres://sharenet:${POSTGRES_PASSWORD}@localhost:5432/sharenet + - name: PORT + value: "3001" envFrom: - secretRef: name: backend-secrets @@ -99,13 +111,18 @@ spec: cpu: "250m" - name: frontend - image: localhost/frontend:deployed + image: ${REGISTRY_HOST}/${APP_NAME}/frontend:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL"] + env: + - name: NEXT_PUBLIC_API_URL + value: http://localhost:3001 + - name: PORT + value: "3000" envFrom: - secretRef: name: frontend-secrets @@ -122,7 +139,7 @@ spec: cpu: "250m" - name: nginx - image: localhost/nginx:deployed + image: ${REGISTRY_HOST}/${APP_NAME}/nginx:${IMAGE_TAG} # Security: drop all capabilities, read-only root filesystem securityContext: readOnlyRootFilesystem: true @@ -132,10 +149,8 @@ spec: ports: - containerPort: 80 protocol: TCP - hostPort: 80 - containerPort: 443 protocol: TCP - hostPort: 443 volumeMounts: - name: nginx-conf mountPath: /etc/nginx/nginx.conf @@ -170,7 +185,7 @@ spec: - name: pgdata hostPath: path: /opt/sharenet/volumes/pgdata - type: Directory + type: DirectoryOrCreate - name: nginx-conf hostPath: path: /opt/sharenet/nginx @@ -178,7 +193,7 @@ spec: - name: nginx-cache hostPath: path: /opt/sharenet/volumes/nginx-cache - type: Directory + type: DirectoryOrCreate - name: letsencrypt hostPath: path: /etc/letsencrypt