Skip to content

Add non-root variant to Dockerfile for dual image publishing#3520

Open
aaronburtle wants to merge 4 commits into
mainfrom
dev/aaronburtle/Add-User-Docker-File
Open

Add non-root variant to Dockerfile for dual image publishing#3520
aaronburtle wants to merge 4 commits into
mainfrom
dev/aaronburtle/Add-User-Docker-File

Conversation

@aaronburtle

@aaronburtle aaronburtle commented May 6, 2026

Copy link
Copy Markdown
Contributor

Why make this change?

Closes #3514

The published runtime image (mcr.microsoft.com/azure-databases/data-api-builder) runs as root because the Dockerfile never issues a USER instruction. Image scanners like Checkmarx One read the image's Config.User field and flag any final stage that's empty or root. Users who have to satisfy those scanners are blocked from adopting DAB unless they override securityContext.runAsUser in their pod spec.

DAB is just an ASP.NET Core process and does not need root privileges, so the fix is to declare a non-root user explicitly. The published mcr.microsoft.com/dotnet/aspnet:10.0-azurelinux3.0 base image already ships with a non-root user (UID/GID 1654, exposed via the APP_UID env var), so no useradd layer is needed.

What is this change?

Restructure the Dockerfile into a multi-target build that publishes two runtime variants from the same source:

Target Tag (proposed) Runs as Backwards compatible? Scanner clean?
runtime (default, last stage) :<version> root identical to today's image No (unchanged)
runtime-nonroot (opt-in via --target) :<version>-nonroot UID 1654 ($APP_UID) n/a new variant Yes

The root variant is the last stage in the Dockerfile, so a plain docker build . with no --target argument still produces the existing root-running image. No existing user sees a behavior change.

Safeguards on the non-root variant

To minimize the chance of runtime breakage when users adopt the non-root tag:

  • chown $APP_UID:$APP_UID /App/logs (non-recursive) so the documented default file-sink path (runtime.telemetry.filelogs/dab-log.txt, relative to WORKDIR /App) is writable by the non-root user. Ownership of the published assemblies under /App is intentionally left unchanged — a recursive chown -R would duplicate every assembly layer and roughly double the non-root image size for no runtime benefit, since DAB only needs write access to /App/logs. Only ownership of /App/logs is changed, not file modes.
  • Pre-create /App/logs so the documented default file-sink path works with no extra volume or permission setup.
  • Numeric USER $APP_UID (rather than USER app) per .NET container guidance — a numeric UID is friendlier to image scanners and to Kubernetes runAsNonRoot/runAsUser checks, which cannot resolve a username to a UID at admission time.
  • Default port stays at 5000, which is above 1024, so binding works without CAP_NET_BIND_SERVICE. Users overriding ASPNETCORE_URLS to a privileged port (<1024) must add --cap-add=NET_BIND_SERVICE or front DAB with a reverse proxy.
  • OCI labels on the non-root variant for clarity in registries/tooling.

Known caveats for consumers of the non-root variant

These are inherent to running any non-root container and cannot be fully eliminated in the image. They should be called out in release notes:

  • Host bind-mounts (config, logs, certs, etc.) must be readable and writable, if DAB needs to write them, by UID 1654 on the host. Either chown -R 1654:1654 /host/path or, in Kubernetes, set securityContext.fsGroup: 1654.
  • docker exec defaults to UID 1654. Use docker exec --user 0 for administrative actions inside a running container.
  • Downstream Dockerfiles (FROM <this image>) that need to install packages or write outside /App should add USER 0 before those instructions, then restore USER $APP_UID at the end.

Manual testing performed

Both variants were built locally and verified end-to-end:

Check :<version> (default) :<version>-nonroot
docker build succeeds yes yes
Config.User (what scanners read) empty (= root) app
Runtime UID inside container 0(root) 1654(app)
/App ownership root:root app:app (recursive)
/App/logs pre-created n/a yes
DAB process starts yes yes
File-sink telemetry writes a log file n/a yes (dab-log20260519.txt written to /App/logs/ by UID 1654)
Behavior matches previously published image yes (byte-for-byte equivalent) n/a (new variant)

Follow-up work (separate PR)

The publish pipeline needs to be updated to build and push the second tag. That change lives outside this repo and will be done after this PR merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the container runtime stage to explicitly run Data API Builder as a non-root user (app) to satisfy container security scanners, aligning the Dockerfile with the base image’s intended default user.

Changes:

  • Add explanatory comments documenting the rationale for running as non-root in the final image stage.
  • Set USER app in the runtime stage so scanners see a non-root Config.User.

Comment thread Dockerfile Outdated

@Aniruddh25 Aniruddh25 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot suggestion is valid.

@Aniruddh25 Aniruddh25 self-assigned this May 6, 2026
@aaronburtle aaronburtle self-assigned this May 7, 2026
@aaronburtle aaronburtle added cri Customer Reported issue docker labels May 7, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Review In Progress in Data API builder May 7, 2026
@aaronburtle aaronburtle added this to the May 2026 milestone May 7, 2026
@aaronburtle aaronburtle closed this May 7, 2026
@github-project-automation github-project-automation Bot moved this from Review In Progress to Done in Data API builder May 7, 2026
@aaronburtle aaronburtle reopened this May 7, 2026
@github-project-automation github-project-automation Bot moved this from Done to Todo in Data API builder May 7, 2026
@aaronburtle aaronburtle marked this pull request as draft May 7, 2026 14:18
@aaronburtle aaronburtle changed the title Add USER "app" to Dockerfile [DRAFT][DO NOT REVIEW] Add USER "app" to Dockerfile May 7, 2026
@aaronburtle aaronburtle moved this from Todo to In Progress in Data API builder May 7, 2026
@aaronburtle aaronburtle force-pushed the dev/aaronburtle/Add-User-Docker-File branch from 6eb720f to 4cf4f53 Compare May 19, 2026 22:04
@aaronburtle aaronburtle marked this pull request as ready for review May 20, 2026 03:31
@aaronburtle aaronburtle changed the title [DRAFT][DO NOT REVIEW] Add USER "app" to Dockerfile Add non-root variant to Dockerfile for dual image publishing May 20, 2026
Comment thread Dockerfile Outdated
@github-project-automation github-project-automation Bot moved this from In Progress to Review In Progress in Data API builder Jun 10, 2026
@Aniruddh25 Aniruddh25 modified the milestones: May 2026, July 2026 Jun 30, 2026
Comment thread Dockerfile
Comment thread Dockerfile
Comment thread Dockerfile
Comment thread Dockerfile

@Aniruddh25 Aniruddh25 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need some clarifications.

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

Labels

cri Customer Reported issue docker

Projects

Status: Review In Progress

Development

Successfully merging this pull request may close these issues.

Add USER to the Dockerfile

4 participants