@@ -7,11 +7,78 @@ WORKDIR /src
77COPY ["." , "./" ]
88RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -c Docker -o /out -r linux-x64
99
10- FROM mcr.microsoft.com/dotnet/aspnet:10.0-azurelinux3.0 AS runtime
10+ # ---------------------------------------------------------------------------
11+ # Common runtime base.
12+ #
13+ # Not intended as a final build target. Both the `runtime` (root, default)
14+ # and `runtime-nonroot` (non-root, scanner-friendly) variants derive from
15+ # this stage so the shared setup stays in one place.
16+ # ---------------------------------------------------------------------------
17+ FROM mcr.microsoft.com/dotnet/aspnet:10.0-azurelinux3.0 AS runtime-base
1118
1219COPY --from=build /out /App
1320# Add default dab-config.json to /App in the image
1421COPY --from=build /out/dab-config.json /App/dab-config.json
1522WORKDIR /App
1623ENV ASPNETCORE_URLS=http://+:5000
24+ EXPOSE 5000
1725ENTRYPOINT ["dotnet" , "Azure.DataApiBuilder.Service.dll" ]
26+
27+ # ---------------------------------------------------------------------------
28+ # Non-root variant. Build explicitly with:
29+ # docker build --target runtime-nonroot -t <repo>:<version>-nonroot .
30+ #
31+ # Runs as the non-root user that ships with the
32+ # mcr.microsoft.com/dotnet/aspnet base image (UID/GID 1654, exposed via the
33+ # APP_UID env var, on the azurelinux3.0 variant). DAB does not require root,
34+ # and declaring USER explicitly sets the image's Config.User field so image
35+ # scanners (e.g. Checkmarx One) that require a non-root user in the final
36+ # stage are satisfied. We use the numeric `USER $APP_UID` form (rather than
37+ # `USER app`) per .NET container guidance: a numeric UID is friendlier to
38+ # image scanners and to Kubernetes `runAsNonRoot`/`runAsUser` checks, which
39+ # cannot resolve a username to a UID at admission time.
40+ #
41+ # Safeguards applied to minimize the chance of runtime breakage:
42+ # * Pre-create /App/logs and `chown app:app /App/logs` (non-recursive) so
43+ # the documented default file-sink path ("logs/dab-log.txt", relative to
44+ # WORKDIR /App) is writable. Ownership of the published assemblies under
45+ # /App is intentionally left unchanged - a recursive chown would
46+ # duplicate every assembly layer and roughly double the image size for
47+ # no runtime benefit, since DAB only needs write access to /App/logs.
48+ # * Default port stays at 5000, which is above 1024, so binding works
49+ # without CAP_NET_BIND_SERVICE. Users overriding ASPNETCORE_URLS to a
50+ # privileged port (<1024) must add `--cap-add=NET_BIND_SERVICE` to
51+ # `docker run` or front DAB with a reverse proxy.
52+ #
53+ # Notes for consumers of this image:
54+ # * Host bind-mounts (config, logs, certs, etc.) must be readable - and
55+ # writable, if DAB needs to write them - by UID 1654 on the host.
56+ # Either `chown -R 1654:1654 /host/path` or, in Kubernetes, set
57+ # `securityContext.fsGroup: 1654`.
58+ # * `docker exec` defaults to UID 1654. Use `docker exec --user 0`
59+ # for administrative actions inside a running container.
60+ # * Downstream Dockerfiles (FROM <this image>) that need to install
61+ # packages or write outside /App should add `USER 0` before those
62+ # instructions, then restore `USER $APP_UID` at the end.
63+ # ---------------------------------------------------------------------------
64+ FROM runtime-base AS runtime-nonroot
65+
66+ RUN mkdir -p /App/logs && chown $APP_UID:$APP_UID /App/logs
67+ USER $APP_UID
68+
69+ LABEL org.opencontainers.image.title="Data API builder (non-root)" \
70+ org.opencontainers.image.description="Data API builder running as the non-root 'app' user (UID 1654 on azurelinux3.0)." \
71+ org.opencontainers.image.source="https://github.com/Azure/data-api-builder"
72+
73+ # ---------------------------------------------------------------------------
74+ # Default (root-running) variant. Build with either:
75+ # docker build -t <repo>:<version> . # no --target needed
76+ # docker build --target runtime -t <repo>:<version> .
77+ #
78+ # This is the LAST stage in the file, so a plain `docker build` with no
79+ # --target argument produces this image. Keeping the root-running variant
80+ # as the default preserves backwards compatibility with the previously
81+ # published image - existing users see no behavior change. The non-root
82+ # variant is opt-in via `--target runtime-nonroot`.
83+ # ---------------------------------------------------------------------------
84+ FROM runtime-base AS runtime
0 commit comments