Dockerfile for .Net 7 App with Non-Root User
Tags: devops
Published: 2023-07-09 20:49:33

Here in this post I would like to outline a dockerfile for .Net 7 app with non-root user. This is typically done to enhance security by running the application with a non-root user.

```
FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine AS base
WORKDIR /app
EXPOSE 8080
```

In this very first stage, first of all base image is set. It uses the image _mcr.microsoft.com/dotnet/aspnet_ with the tag 7.0-alpine. The AS base part gives a name ("base") to this stage, which can be referred to later in the Dockerfile.Then the working directory is set inside the container to /app. It means that any subsequent instructions will be executed in this directory unless explicitly changed.TLastly Docker is informed that the container will listen on port 8080 at runtime. 

```
ENV ASPNETCORE_URLS=http://*:8080
ENV COMPlus_EnableDiagnostics=0
```
Here the first line sets an environment variable named ASPNETCORE_URLS with the value http://*:8080. In ASP.NET Core applications, ASPNETCORE_URLS is an environment variable that specifies the URLs or ports on which the application will listen. In this case, it is set to http://*:8080, which means the application will listen on all network interfaces (*) on port 8080.
This second line sets an environment variable named COMPlus_EnableDiagnostics with the value 0. COMPlus_EnableDiagnostics is an environment variable specific to the .NET runtime. Setting it to 0 disables diagnostic features and optimizations in the .NET runtime.

```
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["DemoApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build DemoApp.csproj -c Release -o /app/build
```

In the second stage; the first line sets the base image for the current stage of the build. It uses the image _mcr.microsoft.com/dotnet/sdk_ with the tag 6.0. The AS build part gives a name ("build") to this stage, which can be referred to later in the Dockerfile. 
Then the working directory is set inside the container to /src. The third line copies the DemoApp.csproj file from the local directory (the directory where the Dockerfile resides) to the current working directory (/src) inside the container.
Fourth instruction runs the dotnet restore command inside the container. It restores the dependencies specified in the DemoApp.csproj file.
COPY . . instruction  copies the remaining files and directories from the local directory to the current working directory (/src) inside the container. It copies all the files required for building the application.
The last instruction runs the dotnet build command inside the container, building the application specified by DemoApp.csproj. The -c Release flag specifies the build configuration as "Release". The -o /app/build flag specifies the output directory for the build artifacts as /app/build inside the container.

```
FROM build AS publish
RUN dotnet publish DemoApp.csproj -c Release -o /app/publish
```
Here the first line creates a new stage named publish that will inherit all the files and configurations from the build stage.
The second instruction runs the dotnet publish command inside the container to publish the application. It targets the DemoApp.csproj project file, specifies the build configuration as Release using the -c Release flag, and sets the output directory to /app/publish using the -o /app/publish flag. The dotnet publish command packages the application along with its dependencies into a directory suitable for deployment.

```
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
```
Here the first line creates a new stage named final that will inherit all the files and configurations from the base stage.
The second line sets the working directory inside the container to /app. It means that any subsequent instructions will be executed in this directory unless explicitly changed.
The third line copies the published artifacts from the publish stage into the current final stage. The --from=publish flag specifies the source stage from which to copy the files. In this case, it refers to the publish stage. The /app/publish is the source directory in the publish stage, and the . represents the destination directory in the final stage. This line effectively copies the published application files from the publish stage to the /app directory in the final stage.

This stage is typically used to create the final image for deployment. It starts from the base image, sets up the working directory, and copies the published application artifacts into the image. Additional instructions can be added to configure the runtime environment or perform any necessary setup steps before running the application.

```
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
RUN chown -R appuser:appgroup /app && chmod -R 755 /app
USER appuser
```

These three lines in the Dockerfile build on the previous instructions to set ownership and permissions for the /app directory and switch to the appuser as the user for subsequent commands.
These instructions are commonly used to ensure proper ownership and permissions for the application files and to switch to a non-root user for running the application within the container.
The first line creates a new system group named appgroup using addgroup, and then creates a new system user named appuser and adds it to the appgroup using adduser.
The second line changes the ownership of the /app directory and its contents recursively to the appuser:appgroup user and group using chown. The chown -R command sets ownership recursively for all files and directories within /app. Then, chmod is used to set the permissions of the /app directory and its contents to 755, which allows read, write, and execute permissions for the user (appuser) and read and execute permissions for the group (appgroup) and others.
THe last line sets the user context to appuser, meaning that any subsequent commands will be executed with the permissions and environment of the appuser. This is typically done to enhance security by running the application with a non-root user.

```
ENTRYPOINT ["dotnet", "DemoApp.dll"]
```

This is the last insstruction of our Dockerfile. This line sets the entrypoint of the container to the dotnet command, with DemoApp.dll as the argument. The dotnet command is the .NET CLI command-line tool used to execute .NET applications.
By setting the entrypoint to dotnet, when the container starts, it will automatically execute the specified .NET application (DemoApp.dll in this case) using the dotnet command.
The entrypoint is typically used to specify the main command or process that should be run when the container starts. In this case, it indicates that the container should run the specified .NET application as its main process.

Thank you for reading.