IotEdge: Setting file permissions

When you implement .NET Core module in C#, which reads/writes files, you might run in several permission related issues. For example, your module outputs some configuration file in the output folder of build process. You can do it typically by setting file property in solution explorer to "copy always" or "copy if newer".

This is all fine, but if you build image for Linux containers, your application might (will) fail with following exception, when file is touched:

System.IO.IOException: Permission denied

The reason for this is that your application by default has no permission to read any file copied to output folder. If you run container with bash and list permissions, you will see following:

docker run -it --entrypoint bash IMAGENAME

Then execute following in container to see file permissions:

ls -la

Here is a typical result:

8 -rwxr-xr-x 1 root root 4530

Workaround

In my example, I have a Machine Learning model file model.json and want to set extra permissions. The workaround for this issue is to place RUN chmod inside of dockerfile. However the command must be placed before USER moduleuser.

This is dockerfile, which sets correrctly permissions:

FROM microsoft/dotnet:2.0-sdk AS build-env
WORKDIR /app

COPY *.csproj ./
RUN dotnet restore

COPY . ./
RUN dotnet publish -c Release -o out

FROM microsoft/dotnet:2.0-runtime
WORKDIR /app
COPY --from=build-env /app/out ./
# Note, this is before USER moduleuser
RUN chmod 777 /app/model.json

RUN useradd -ms /bin/bash moduleuser
USER moduleuser

ENTRYPOINT ["dotnet", "xyz.dll"]

This is an example of dockerfile, which will NOT set permissions on file. It will fail with error:

chmod: changing permissions of '/app/model.json': Operation not permitted

FROM microsoft/dotnet:2.0-sdk AS build-env
WORKDIR /app

COPY *.csproj ./
RUN dotnet restore

COPY . ./
RUN dotnet publish -c Release -o out

FROM microsoft/dotnet:2.0-runtime
WORKDIR /app
COPY --from=build-env /app/out ./

RUN useradd -ms /bin/bash moduleuser
USER moduleuser
# This does not work, because it is executing after USER moduleuser
RUN chmod 777 /app/model.json

ENTRYPOINT ["dotnet", "xyz.dll"]

You can follow this issue on github.