Refactor dev container to run without root#1075
Conversation
All services now run as the pulp user (UID 700) instead of requiring root for multi-user process management: - PostgreSQL: initialized and run as pulp (not postgres). PostgreSQL only requires PGDATA ownership, not a specific OS user. - Redis: runs as pulp (no user= directive in supervisord) - Supervisord: runs as pulp (removed user=root), PID/socket files moved to /var/run/supervisord/ owned by pulp - Entrypoint: removed all runuser/su calls, commands run directly as the current user - Dockerfile: USER 700 at the end, all runtime directories owned by pulp at build time This makes the dev container compatible with OpenShift's restricted-v2 SCC which enforces runAsNonRoot and arbitrary UID assignment.
Reviewer's GuideRefactors the dev container image so it runs entirely as a non-root user (UID 700 or arbitrary UID), by changing PostgreSQL initialization, ownership of runtime directories, the Dockerfile user, entrypoint logic, and supervisord configuration to eliminate root- and postgres-specific assumptions. Sequence diagram for rootless dev container startup and initializationsequenceDiagram
participant Dev as Developer
participant Kube as KubernetesPod
participant C as DevContainer
participant E as Entrypoint
participant PG as PostgreSQL
participant RD as Redis
participant PM as PulpcoreManager
participant S as Supervisord
participant Svc as PulpServices
Dev->>Kube: create Pod with runAsNonRoot true
Kube->>C: start container (uid 700 or arbitrary)
C->>E: execute /entrypoint.sh
E->>PG: pg_ctl start using PGDATA owned by current user
E->>PG: pg_isready (loop until ready)
E->>PG: psql -d postgres check pulp database
PG-->>E: database exists or not
E->>PG: psql -d postgres CREATE DATABASE pulp (if missing)
E->>RD: redis-server --daemonize yes (runs as current user)
E->>PM: pulpcore-manager migrate --noinput
E->>PM: pulpcore-manager reset-admin-password
E->>PG: pg_ctl stop -m fast -w
E->>RD: redis-cli shutdown
E->>S: exec supervisord
S->>PG: manage postgres program (no user override)
S->>RD: manage redis program
S->>Svc: start pulp-api, pulp-content, pulp-worker as current user
Dev->>Svc: HTTP request to pulp api status
Svc-->>Dev: status response
Flow diagram for Dockerfile rootless initialization stepsgraph TD
A["Base image with postgres and pulp installed"] --> B["Create /var/run/postgresql and /var/lib/pgsql/16/data"]
B --> C["chown to pulp:pulp for PostgreSQL paths"]
C --> D["Switch to USER pulp:pulp"]
D --> E["Run initdb on /var/lib/pgsql/16/data"]
E --> F["Write trust pg_hba.conf entries"]
F --> G["Switch back to USER root:root"]
G --> H["chown -R pulp:pulp on runtime directories\n/var/run/postgresql /var/lib/pgsql /var/log/pulp /var/lib/pulp /usr/local/lib/pulp /etc/pulp"]
H --> I["mkdir -p /var/run/supervisord and chown pulp:pulp"]
I --> J["chmod 777 /workspace for arbitrary uid write"]
J --> K["Copy settings, supervisord.conf, entrypoint.sh, scripts"]
K --> L["chmod +x entrypoint and scripts"]
L --> M["Final USER 700 for runtime"]
M --> N["Image ready for non-root execution"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The initialization logic no longer creates the
pulpdatabase role and switches to using the current OS user as superuser; double-check that the Django/Pulp DB settings (user/password) are consistent with this change or consider retaining creation of thepulprole for compatibility. - The combination of
USER 700in the Dockerfile andchowning runtime dirs topulp:pulpmay not behave as intended when Kubernetes/OpenShift overrides the user to an arbitrary UID; consider aligning ownership/permissions (e.g., using root-owned but group/other-writable dirs) so the container still works whenrunAsNonRootforces a different UID.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The initialization logic no longer creates the `pulp` database role and switches to using the current OS user as superuser; double-check that the Django/Pulp DB settings (user/password) are consistent with this change or consider retaining creation of the `pulp` role for compatibility.
- The combination of `USER 700` in the Dockerfile and `chown`ing runtime dirs to `pulp:pulp` may not behave as intended when Kubernetes/OpenShift overrides the user to an arbitrary UID; consider aligning ownership/permissions (e.g., using root-owned but group/other-writable dirs) so the container still works when `runAsNonRoot` forces a different UID.
## Individual Comments
### Comment 1
<location path="dev-container/entrypoint.sh" line_range="34-38" />
<code_context>
+# Run database migrations (already running as pulp)
echo "Running database migrations..."
-runuser -u pulp -- bash -c 'PATH=/usr/local/lib/pulp/bin:$PATH pulpcore-manager migrate --noinput'
+pulpcore-manager migrate --noinput
# Set admin password
echo "Setting admin password..."
-runuser -u pulp -- bash -c "PATH=/usr/local/lib/pulp/bin:\$PATH pulpcore-manager reset-admin-password --password '${PULP_DEFAULT_ADMIN_PASSWORD:-password}'" 2>/dev/null || true
+pulpcore-manager reset-admin-password --password "${PULP_DEFAULT_ADMIN_PASSWORD:-password}" 2>/dev/null || true
# Stop PostgreSQL and Redis — supervisord will manage them
</code_context>
<issue_to_address>
**issue (bug_risk):** Dropping the explicit PATH override may break `pulpcore-manager` resolution for the pulp user.
We previously ensured `pulpcore-manager` was resolvable by explicitly setting `PATH=/usr/local/lib/pulp/bin:$PATH` in the command. With that removed, the script now assumes `pulpcore-manager` is already on the PATH for the runtime user, which may not hold in minimal images or if the pulp user’s environment changes. Please either reintroduce the explicit PATH prefix or use an absolute path to `pulpcore-manager` to avoid hard-to-diagnose failures.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| pulpcore-manager migrate --noinput | ||
|
|
||
| # Set admin password | ||
| echo "Setting admin password..." | ||
| runuser -u pulp -- bash -c "PATH=/usr/local/lib/pulp/bin:\$PATH pulpcore-manager reset-admin-password --password '${PULP_DEFAULT_ADMIN_PASSWORD:-password}'" 2>/dev/null || true | ||
| pulpcore-manager reset-admin-password --password "${PULP_DEFAULT_ADMIN_PASSWORD:-password}" 2>/dev/null || true |
There was a problem hiding this comment.
issue (bug_risk): Dropping the explicit PATH override may break pulpcore-manager resolution for the pulp user.
We previously ensured pulpcore-manager was resolvable by explicitly setting PATH=/usr/local/lib/pulp/bin:$PATH in the command. With that removed, the script now assumes pulpcore-manager is already on the PATH for the runtime user, which may not hold in minimal images or if the pulp user’s environment changes. Please either reintroduce the explicit PATH prefix or use an absolute path to pulpcore-manager to avoid hard-to-diagnose failures.
Summary
Refactors the dev container (
ghcr.io/pulp/hosted-pulp-dev-env) to run entirely as a non-root user, making it compatible with OpenShift'srestricted-v2SCC and KubernetesrunAsNonRoot: truesecurity contexts.Changes
Dockerfile:
pulpuser (notpostgres) — PostgreSQL only requires PGDATA ownership, not a specific OS user/var/run/postgresql,/var/lib/pgsql,/var/log/pulp,/usr/local/lib/pulp,/etc/pulp) owned bypulpat build time/var/run/supervisord/(owned bypulp)USER 700directive — container runs as non-root by default/workspaceset tochmod 777for arbitrary UID compatibilityentrypoint.sh:
runusercalls — PostgreSQL, migrations, and admin password all run directly as the current userpsql -d postgres(current user is the DB superuser since they own PGDATA)supervisord.conf:
user=rootfrom[supervisord]sectionuser=postgresfrom[program:postgresql]— runs as current useruser=pulpfrom Pulp service programs — already running as pulp/var/run/supervisord/Why
Alcove dispatches dev containers as Kubernetes sidecars. On OpenShift (ROSA), the
restricted-v2SCC enforcesrunAsNonRoot: trueand assigns arbitrary UIDs from the namespace range. The previous dev container required root forrunusercalls, causing it to crash with "runuser: may not be used by non-root users".Testing
Once the CI builds the image from this branch, verify with:
Summary by Sourcery
Refactor the dev container to run entirely as a non-root user while remaining compatible with PostgreSQL, Redis, and supervisord orchestration.
Enhancements: