diff --git a/Dockerfile b/Dockerfile index 59190b6374..00592cb9f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,11 +7,75 @@ WORKDIR /src COPY [".", "./"] RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -c Docker -o /out -r linux-x64 -FROM mcr.microsoft.com/dotnet/aspnet:8.0-cbl-mariner2.0 AS runtime +# --------------------------------------------------------------------------- +# Common runtime base. +# +# Not intended as a final build target. Both the `runtime` (root, default) +# and `runtime-nonroot` (non-root, scanner-friendly) variants derive from +# this stage so the shared setup stays in one place. +# --------------------------------------------------------------------------- +FROM mcr.microsoft.com/dotnet/aspnet:8.0-cbl-mariner2.0 AS runtime-base COPY --from=build /out /App # Add default dab-config.json to /App in the image COPY dab-config.json /App/dab-config.json WORKDIR /App ENV ASPNETCORE_URLS=http://+:5000 +EXPOSE 5000 ENTRYPOINT ["dotnet", "Azure.DataApiBuilder.Service.dll"] + +# --------------------------------------------------------------------------- +# Non-root variant. Build explicitly with: +# docker build --target runtime-nonroot -t :-nonroot . +# +# Runs as the "app" user that ships with the mcr.microsoft.com/dotnet/aspnet +# base image (UID/GID 1654 on the cbl-mariner variant; 64198 on the +# Debian/chiseled variants). DAB does not require root, and declaring USER +# explicitly sets the image's Config.User field so image scanners +# (e.g. Checkmarx One) that require a non-root user in the final stage are +# satisfied. +# +# Safeguards applied to minimize the chance of runtime breakage: +# * `chown -R app:app /App` so any feature that writes to a relative path +# under WORKDIR works (e.g. runtime.telemetry.file with the default path +# "logs/dab-log.txt", or any future relative-path artifact). File modes +# are unchanged - only ownership. +# * Pre-create /App/logs so the documented default file-sink path works +# with no additional volume/permission setup. +# * 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` to +# `docker run` or front DAB with a reverse proxy. +# +# Notes for consumers of this image: +# * 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 the `app` user. Use `docker exec --user 0` +# for administrative actions inside a running container. +# * Downstream Dockerfiles (FROM ) that need to install +# packages or write outside /App should add `USER 0` before those +# instructions, then restore `USER app` at the end. +# --------------------------------------------------------------------------- +FROM runtime-base AS runtime-nonroot + +RUN mkdir -p /App/logs && chown -R app:app /App +USER app + +LABEL org.opencontainers.image.title="Data API builder (non-root)" \ + org.opencontainers.image.description="Data API builder running as the non-root 'app' user (UID 1654 on cbl-mariner)." \ + org.opencontainers.image.source="https://github.com/Azure/data-api-builder" + +# --------------------------------------------------------------------------- +# Default (root-running) variant. Build with either: +# docker build -t : . # no --target needed +# docker build --target runtime -t : . +# +# This is the LAST stage in the file, so a plain `docker build` with no +# --target argument produces this image. Keeping the root-running variant +# as the default preserves backwards compatibility with the previously +# published image - existing users see no behavior change. The non-root +# variant is opt-in via `--target runtime-nonroot`. +# --------------------------------------------------------------------------- +FROM runtime-base AS runtime