Skip to content

Support running under OpenShift arbitrary UIDs (restricted-v2 SCC)#36545

Open
snecklifter wants to merge 1 commit intovespa-engine:masterfrom
snecklifter:openshift-arbitrary-uid-support
Open

Support running under OpenShift arbitrary UIDs (restricted-v2 SCC)#36545
snecklifter wants to merge 1 commit intovespa-engine:masterfrom
snecklifter:openshift-arbitrary-uid-support

Conversation

@snecklifter
Copy link
Copy Markdown

Summary

  • Make Vespa compatible with OpenShift 4.20's default restricted-v2 Security Context Constraint (SCC), which runs containers with arbitrary UIDs and GID 0 (root group)
  • All writable directories are now group-owned by root (GID 0) with group-write permissions, following the OpenShift image creation guidelines
  • User-switching and ownership validation code paths gracefully handle non-root execution with arbitrary UIDs

Background: OpenShift SCCs and the root group

OpenShift uses Security Context Constraints (SCCs) to control what pods can do at runtime. The default restricted-v2 SCC enforces:

  • Arbitrary UID assignment: Containers run as a random UID from a namespace-specific range (e.g. 1000660000+), not the UID specified in the Dockerfile
  • GID 0 (root group): The arbitrary UID is always a member of the root group (GID 0). This is by design — the root group is used as the access mechanism for arbitrary UIDs, while the root user (UID 0) remains prohibited
  • No privilege escalation: setuid()/setgid() are blocked; CAP_SETUID and CAP_SETGID are dropped

As stated in the OpenShift documentation:

"The directories and files that are read from or written to by processes in the image should be owned by the root group and be read/writable by that group. Files to be executed should also have group execute permissions [...] because the container user is always a member of the root group, the container user can read and write these files."

Why root group ownership is safe

Using GID 0 as the group owner does not grant root privileges. It simply allows any UID assigned to the root group (which OpenShift always does) to read/write the directories. The actual user remains unprivileged — it cannot escalate to UID 0, bind privileged ports, or perform any root-level operations.

Changes

RPM spec (dist/vespa.spec)

  • All writable directory %attr directives changed from (-,vespa,vespa) to (0775,vespa,root) — GID 0 with group-write
  • vespa user added to root group via usermod -a -G root
  • /etc/passwd made group-writable to support runtime UID injection

Startup scripts

  • rhel-prestart.sh: Replaced strict user/group name ownership checks with writability checks ([ -w "$4" ]). Non-root processes can no longer fail startup due to ownership mismatch
  • common-env.sh: Added fallback to numeric UID when neither vespa nor nobody user exists in /etc/passwd
  • standalone-container.sh: chown is now conditional on running as root; user validation relaxed for arbitrary UIDs

User switching

  • vespa-run-as-vespa-user (C++): Detects non-root execution and skips setuid()/setgid()/setgroups(), proceeding with execvp() directly
  • Go user code (find_user.go, switch_user.go): Falls back to numeric UID string when user.Current() fails; CheckCorrectUser() and MaybeSwitchUser() proceed with warnings instead of exiting when non-root. Added VESPA_SKIP_USER_CHECK env var for explicit bypass

Systemd services

  • Replaced hardcoded User=vespa with User=@VESPA_USER@ CMake template variable in both service files

Companion PR

The corresponding container image changes are in vespa-engine/docker-image (Dockerfiles and entrypoint script).

Test plan

  • Build RPMs and verify directory permissions are 0775 with root group
  • Run container image with --user=$(id -u):0 to simulate OpenShift arbitrary UID
  • Verify vespa-start-configserver and vespa-start-services succeed under arbitrary UID
  • Verify rhel-prestart.sh passes writability checks without root
  • Verify vespa-run-as-vespa-user executes commands without attempting setuid
  • Confirm no regression when running as the vespa user (UID 1000) in standard Docker

🤖 Generated with Claude Code

Make Vespa containers compatible with OpenShift 4.20's default security
context which assigns arbitrary UIDs with GID 0. Key changes:

- RPM spec: set writable dirs to root group (GID 0) with 0775 perms
- rhel-prestart.sh: use writability checks instead of strict ownership
- vespa-run-as-vespa-user: skip setuid/setgid when non-root
- Go user code: graceful fallback for arbitrary UIDs, add
  VESPA_SKIP_USER_CHECK env var
- standalone-container.sh: conditional chown, relaxed user validation
- common-env.sh: fallback to numeric UID when no known user exists
- systemd services: parameterize User= directive via CMake

Co-Authored-By: Claude Opus 4.7 <[email protected]>
@snecklifter
Copy link
Copy Markdown
Author

Given the restricted-v2 scc partially mitigates CVE-2026-31431 (copy/fail) it might be good to review this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants