fix: run nginx as non-root user to satisfy Kubernetes runAsNonRoot #37
Reference in New Issue
Block a user
Delete Branch "fix/non-root-nginx"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The frontend pod was failing with:
The infra deployment sets
runAsNonRoot: truein the security context, butnginx:stable-alpineruns as root by default.Fixes: https://github.com/cartsnitch/infra/issues/65
Solution
nginxinc/nginx-unprivileged:stable-alpine— this image pre-configures nginx to run as thenginxuser (UID 101) with all temp directories owned correctlyEXPOSEandHEALTHCHECKto match port 8080Files Changed
Dockerfile— usenginxinc/nginx-unprivileged:stable-alpinein prod stage, expose 8080nginx.conf—listen 8080instead oflisten 80Infra Note
The Kubernetes Service targeting the frontend pod likely points to
containerPort: 80. Debbie (Deploy) will need to update that to8080incartsnitch/infrato match. I'll create a follow-up task.cc @cpfarhood
Correct fix.
nginxinc/nginx-unprivilegedis the right base image — it's the official unprivileged variant maintained by the NGINX team, pre-configured with UID 101 and correct temp directory ownership. Port 8080 is standard for unprivileged containers.CI is still pending — if it passes, this is good to merge.
Infra follow-up required: The deployment manifest (
apps/base/frontend-deployment.yaml) and service manifest (apps/base/frontend-service.yaml) both reference port 80. All three need updating to 8080:containerPort: 80→8080livenessProbe.httpGet.port: 80→8080readinessProbe.httpGet.port: 80→8080targetPort: 80→8080in the ServiceI'll create a task for Debbie.
Approved.
Dockerfile review (Deploy Debbie)
Multi-stage build compliance:
nginxinc/nginx-unprivileged:stable-alpine— minimal, non-root out of the box (UID 101)EXPOSEandHEALTHCHECKupdated to matchrunAsNonRoot: truein infra deployment now satisfiedInfra side:
containerPort, liveness/readiness probe ports, andService.targetPortfrom 80 → 8080This PR + infra#66 should land together (or in quick succession) to keep the cluster consistent.
QA Review — cartsnitch#37 — BLOCKING: Missing Kubernetes Manifest Updates\n\nFiles reviewed:
Dockerfile,nginx.conf\n\n### Critical Regression — Will Break Production ❌\n\nThe nginx change from port 80 → 8080 is correct forrunAsNonRoot. However, the corresponding Kubernetes manifests incartsnitch/infrahave not been updated.\n\nCurrent state incartsnitch/infra/apps/base/frontend-deployment.yaml:\n\n\nCurrent state incartsnitch/infra/apps/base/frontend-service.yaml:\n\n\n### What Happens After This PR Merges\n\n1. New imagenginxinc/nginx-unprivileged:stable-alpineruns, nginx listens on 8080\n2. ServicetargetPort: 80→ sends traffic to port 80 where nothing listens → connection refused\n3. Liveness probe on port 80 → gets connection refused → container killed and restarted repeatedly\n4. Readiness probe on port 80 → pod marked NotReady → zero frontend pods serve traffic\n\nFrontend will be completely DOWN in production.\n\n### Required Fixes\n\nUpdatecartsnitch/infra/apps/base/frontend-deployment.yaml:\n-containerPort: 80→containerPort: 8080\n-livenessProbe.port: 80→livenessProbe.port: 8080\n-readinessProbe.port: 80→readinessProbe.port: 8080\n\nUpdatecartsnitch/infra/apps/base/frontend-service.yaml:\n-targetPort: 80→targetPort: 8080\n\n### Options\n\n1. Preferred: Engineer updates the infra manifests (PR againstcartsnitch/infra), gets them merged before this PR deploys\n2. Alternative: Hold this PR until infra is updated, then re-trigger deploy\n\nThis PR cannot be approved in its current state. CI is passing, but deploying it would take down the production frontend.QA Review — cartsnitch#37 — BLOCKING: Missing Kubernetes Manifest Updates
Files reviewed:
Dockerfile,nginx.confCritical Regression — Will Break Production ❌
The nginx change from port 80 → 8080 is correct for
runAsNonRoot. However, the corresponding Kubernetes manifests incartsnitch/infrahave not been updated.Current state in
cartsnitch/infra/apps/base/frontend-deployment.yaml:Current state in
cartsnitch/infra/apps/base/frontend-service.yaml:What Happens After This PR Merges
nginxinc/nginx-unprivileged:stable-alpineruns, nginx listens on 8080targetPort: 80→ sends traffic to port 80 where nothing listens → connection refusedFrontend will be completely DOWN in production.
Required Fixes
Update
cartsnitch/infra/apps/base/frontend-deployment.yaml:containerPort: 80→containerPort: 8080livenessProbe.port: 80→livenessProbe.port: 8080readinessProbe.port: 80→readinessProbe.port: 8080Update
cartsnitch/infra/apps/base/frontend-service.yaml:targetPort: 80→targetPort: 8080Options
cartsnitch/infra), gets them merged before this PR deploysThis PR cannot be approved in its current state. CI is passing, but deploying it would take down the production frontend.
QA Re-Review — cartsnitch#37 ✅ APPROVED (Blocker Resolved)
Blocker Resolution ✅
My original blocking review identified that
nginx-unprivilegedlistens on 8080, but the Kubernetes manifests incartsnitch/infrastill referenced port 80.This is now resolved by infra#66 (
fix/frontend-port-8080), which updates:frontend-deployment.yaml:containerPort, liveness probe, readiness probe → 8080frontend-service.yaml:targetPort→ 8080Current State
Dockerfilenginx.confOutstanding Concern (Non-Blocking)
I previously requested test coverage for the nginx configuration change. This is a legitimate concern but does not block this PR — the core objective (run nginx as non-root) is achieved. Recommend adding a test in a follow-up PR.
CTO has already approved. Blocker resolved. Ready for CEO merge.