From b66b99e8dc2ee23a37efa9284501cb6e66bcdbad Mon Sep 17 00:00:00 2001 From: Don Cruver Date: Fri, 20 Feb 2026 08:30:59 -0700 Subject: [PATCH 1/2] Fix runAsNonRoot with non-numeric USER in container images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kubernetes cannot verify a named user is non-root. Pin appuser/appgroup to UID/GID 999 and use numeric USER directive in both webapp and keip-integration Dockerfiles. Configure Jib to run as UID 999. Add runAsUser: 999 to webhook deployment and generated pod securityContexts. Bump keip-integration 0.5.0 → 0.6.0, webapp 0.19.0 → 0.20.0, operator 0.16.0 → 0.17.0. Co-Authored-By: Claude Opus 4.6 --- keip-integration/Dockerfile | 6 +++--- keip-integration/pom.xml | 3 ++- operator/Makefile | 2 +- operator/controller/keip-controller-props.yaml | 2 +- operator/controller/webhook-deployment.yaml | 3 ++- webapp/Dockerfile | 4 ++-- webapp/Makefile | 2 +- webapp/core/sync.py | 1 + webapp/core/test/json/full-response.json | 1 + webapp/routes/test/json/full-route-response.json | 1 + 10 files changed, 15 insertions(+), 10 deletions(-) diff --git a/keip-integration/Dockerfile b/keip-integration/Dockerfile index afaad59..fefcd37 100644 --- a/keip-integration/Dockerfile +++ b/keip-integration/Dockerfile @@ -1,7 +1,7 @@ # Local development Dockerfile. CI releases use the Jib Maven plugin (see pom.xml). FROM eclipse-temurin:21-jre@sha256:34a58218d838035428163eb35abb629944c5906d1bedcfef8bc8864cce11dfe5 -RUN groupadd --system appgroup && useradd --system --gid appgroup appuser +RUN groupadd --system --gid 999 appgroup && useradd --system --uid 999 --gid appgroup appuser COPY target/app.jar /app/app.jar -RUN chown -R appuser:appgroup /app -USER appuser +RUN chown -R 999:999 /app +USER 999 ENTRYPOINT ["java", "-Djdk.httpclient.HttpClient.log=errors,requests", "-Dspring.config.location=/var/spring/config/", "-jar", "/app/app.jar"] diff --git a/keip-integration/pom.xml b/keip-integration/pom.xml index 5d484bb..512f65d 100644 --- a/keip-integration/pom.xml +++ b/keip-integration/pom.xml @@ -12,7 +12,7 @@ org.codice.keip keip-integration - 0.5.0 + 0.6.0 ghcr.io/codice @@ -108,6 +108,7 @@ eclipse-temurin:21-jre@sha256:34a58218d838035428163eb35abb629944c5906d1bedcfef8bc8864cce11dfe5 + 999 ${maven.build.timestamp} -Dspring.config.location=/var/spring/config/ diff --git a/operator/Makefile b/operator/Makefile index 82633de..6d0d541 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -1,4 +1,4 @@ -VERSION ?= 0.16.0 +VERSION ?= 0.17.0 GIT_TAG := operator_v$(VERSION) KUBECTL := kubectl diff --git a/operator/controller/keip-controller-props.yaml b/operator/controller/keip-controller-props.yaml index f9830a7..4c3f871 100644 --- a/operator/controller/keip-controller-props.yaml +++ b/operator/controller/keip-controller-props.yaml @@ -4,4 +4,4 @@ metadata: name: keip-controller-props namespace: keip data: - integration-image: "ghcr.io/codice/keip/keip-integration:0.5.0" + integration-image: "ghcr.io/codice/keip/keip-integration:0.6.0" diff --git a/operator/controller/webhook-deployment.yaml b/operator/controller/webhook-deployment.yaml index 0199343..0e7dc46 100644 --- a/operator/controller/webhook-deployment.yaml +++ b/operator/controller/webhook-deployment.yaml @@ -27,11 +27,12 @@ spec: serviceAccountName: keip-controller-service securityContext: runAsNonRoot: true + runAsUser: 999 seccompProfile: type: RuntimeDefault containers: - name: webhook - image: ghcr.io/codice/keip/webapp:0.19.0 + image: ghcr.io/codice/keip/webapp:0.20.0 ports: - containerPort: 7080 name: webhook-http diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 2c73022..ff29cdb 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.11-slim LABEL org.opencontainers.image.source=https://github.com/codice/keip -RUN groupadd --system appgroup && useradd --system --gid appgroup appuser +RUN groupadd --system --gid 999 appgroup && useradd --system --uid 999 --gid appgroup appuser WORKDIR /code/webapp @@ -13,6 +13,6 @@ COPY . . RUN chown -R appuser:appgroup /code ENV PYTHONDONTWRITEBYTECODE=1 -USER appuser +USER 999 ENTRYPOINT ["python", "-m", "uvicorn", "webapp.app:app", "--host", "0.0.0.0", "--port", "7080", "--app-dir", "/code"] diff --git a/webapp/Makefile b/webapp/Makefile index d2426a5..d67239c 100644 --- a/webapp/Makefile +++ b/webapp/Makefile @@ -1,4 +1,4 @@ -VERSION ?= 0.19.0 +VERSION ?= 0.20.0 HOST_PORT ?= 7080 GIT_TAG := webapp_v$(VERSION) diff --git a/webapp/core/sync.py b/webapp/core/sync.py index ae916c5..c75920d 100644 --- a/webapp/core/sync.py +++ b/webapp/core/sync.py @@ -341,6 +341,7 @@ def _create_pod_template(parent, labels, integration_image) -> Mapping[str, Any] "serviceAccountName": "integrationroute-service", "securityContext": { "runAsNonRoot": True, + "runAsUser": 999, "seccompProfile": {"type": "RuntimeDefault"}, }, "containers": [ diff --git a/webapp/core/test/json/full-response.json b/webapp/core/test/json/full-response.json index ce3df87..631f4fc 100644 --- a/webapp/core/test/json/full-response.json +++ b/webapp/core/test/json/full-response.json @@ -38,6 +38,7 @@ "serviceAccountName": "integrationroute-service", "securityContext": { "runAsNonRoot": true, + "runAsUser": 999, "seccompProfile": { "type": "RuntimeDefault" } diff --git a/webapp/routes/test/json/full-route-response.json b/webapp/routes/test/json/full-route-response.json index 00797e9..5ed2cff 100644 --- a/webapp/routes/test/json/full-route-response.json +++ b/webapp/routes/test/json/full-route-response.json @@ -31,6 +31,7 @@ "serviceAccountName": "integrationroute-service", "securityContext": { "runAsNonRoot": true, + "runAsUser": 999, "seccompProfile": { "type": "RuntimeDefault" } From 99a24a652d5851a95b6139efc35bc61025b23057 Mon Sep 17 00:00:00 2001 From: Don Cruver Date: Fri, 20 Feb 2026 14:26:55 -0700 Subject: [PATCH 2/2] Add fsGroup and increase startup probe threshold Add fsGroup: 999 to pod security context so PVC-mounted volumes are writable by the non-root container user. Increase startup probe failureThreshold from 12 to 24 (240s) to accommodate Spring Boot 4's longer startup times. Co-Authored-By: Claude Opus 4.6 --- webapp/core/sync.py | 3 ++- webapp/core/test/json/full-response.json | 3 ++- webapp/routes/test/json/full-route-response.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/webapp/core/sync.py b/webapp/core/sync.py index c75920d..82c7a9e 100644 --- a/webapp/core/sync.py +++ b/webapp/core/sync.py @@ -342,6 +342,7 @@ def _create_pod_template(parent, labels, integration_image) -> Mapping[str, Any] "securityContext": { "runAsNonRoot": True, "runAsUser": 999, + "fsGroup": 999, "seccompProfile": {"type": "RuntimeDefault"}, }, "containers": [ @@ -373,7 +374,7 @@ def _create_pod_template(parent, labels, integration_image) -> Mapping[str, Any] "port": management_port, "scheme": scheme, }, - "failureThreshold": 12, + "failureThreshold": 24, "timeoutSeconds": 3, }, }, diff --git a/webapp/core/test/json/full-response.json b/webapp/core/test/json/full-response.json index 631f4fc..ea04f91 100644 --- a/webapp/core/test/json/full-response.json +++ b/webapp/core/test/json/full-response.json @@ -39,6 +39,7 @@ "securityContext": { "runAsNonRoot": true, "runAsUser": 999, + "fsGroup": 999, "seccompProfile": { "type": "RuntimeDefault" } @@ -104,7 +105,7 @@ "port": 8443, "scheme": "HTTPS" }, - "failureThreshold": 12, + "failureThreshold": 24, "timeoutSeconds": 3 }, "env": [ diff --git a/webapp/routes/test/json/full-route-response.json b/webapp/routes/test/json/full-route-response.json index 5ed2cff..eb06911 100644 --- a/webapp/routes/test/json/full-route-response.json +++ b/webapp/routes/test/json/full-route-response.json @@ -32,6 +32,7 @@ "securityContext": { "runAsNonRoot": true, "runAsUser": 999, + "fsGroup": 999, "seccompProfile": { "type": "RuntimeDefault" } @@ -80,7 +81,7 @@ "port": 8443, "scheme": "HTTPS" }, - "failureThreshold": 12, + "failureThreshold": 24, "timeoutSeconds": 3 }, "env": [