Skip to the content.

UID Model — restricted-v2 (Legacy)

Applies to: OCP 4.11–4.19 SCC: restricted-v2 hostUsers: true (default)

How It Works

Under restricted-v2, OpenShift overrides the Containerfile USER directive at pod admission time. The SCC’s runAsUser strategy is MustRunAsRange, which:

  1. Reads the namespace annotation openshift.io/sa.scc.uid-range (default: 1000000000/10000)
  2. If the pod spec does not set runAsUser, injects the first UID from that range (e.g., 1000620000)
  3. If the pod spec sets runAsUser to a value outside the range, rejects the pod

The Containerfile USER 1001 is ignored. The process runs as a UID like 1000620000 — a value the image author cannot predict.

Key Facts

Containerfile Implications

Correct Pattern

FROM registry.access.redhat.com/ubi9/ubi-minimal:latest

RUN microdnf install -y nodejs npm && \
    microdnf clean all

COPY --chown=1001:0 app /app
WORKDIR /app

# Directories the app writes to must be group-writable
RUN chgrp -R 0 /app/data /app/logs && \
    chmod -R g=u /app/data /app/logs

# USER must be non-root for certification, but the actual
# runtime UID will be different (random, from namespace range)
USER 1001

EXPOSE 8080
ENTRYPOINT ["node", "server.js"]

Anti-Patterns

# ❌ USER root — rejected by restricted-v2, fails certification
USER root

# ❌ USER nginx — non-numeric, can't verify non-root
USER nginx

# ❌ Hardcoded file ownership to a specific UID
RUN chown -R 1001:1001 /app
# This fails because runtime UID is not 1001 — it's 1000620000.
# The process can't write to files owned by 1001 unless GID 0
# has write permission.

# ❌ Listening on port 80
EXPOSE 80
# Non-root UID cannot bind ports < 1024

What Happens at Runtime

Containerfile:  USER 1001
                    ↓
SCC admission:  MustRunAsRange → inject UID 1000620000
                    ↓
Container:      Process runs as UID 1000620000, GID 0
                /etc/passwd entry auto-created
                Files must be accessible via GID 0

Sources