Azure / Azure/azure-functions-host

.NET 8 isolated process run Docker image as non-root user

Open
#10,164 7 comments 4 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
2k
Forks
482
Avg merge
2d 12h
Merged PRs (30d)
38

Description

#### Investigative information

Please provide the following:

- Timestamp: 2024-05-15T10:54:06 UTC
- Function App version: v4
- Function App name: func-agsDataRetentionManager-euwe-dev-01
- Region: West Europe

#### Context
We updated our function apps to .NET 8 isolated process, then we created Docker images running as root user.
In the Azure Portal everything works as long as function is run by Docker as root user.
Following best practices, we wanted to run Docker container as non-root user - in-built within .NET 8 base image.

#### Repro steps
1. Update Dockerfile to run container as non-root in-built user
```
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . ./DataRetentionManager
WORKDIR "/src/DataRetentionManager"
RUN mkdir -p /home/site/wwwroot
RUN dotnet publish "DataRetentionManager.csproj" -c Release -o /home/site/wwwroot

FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true

COPY --from=build ["/home/site/wwwroot", "/home/site/wwwroot"]

USER $APP_UID

EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_HTTP_PORTS 80

HEALTHCHECK NONE
```

#### Expected behavior
Azure Function is running correctly.
No additional permissions should be required for in-built user or at least it should be achieved in secure way.

#### Actual behavior
There are runtime exceptions
![image](https://github.com/Azure/azure-functions-host/assets/32565136/7b76147b-90c9-4f35-9783-1cb4cf8ee190)
And here are logs from Azure Portal
```
2024-05-15T10:54:06.692585735Z: [INFO] Starting Host (HostId=func-agsDataRetentionManager-euwe-dev-01, InstanceId=94ce87d9-add2-45fd-8129-cb64f18abcaa, Version=4.34.1.1, ProcessId=9, AppDomainId=1, InDebugMode=True, InDiagnosticMode=False, FunctionsExtensionVersion=~4)
2024-05-15T10:54:06.693834049Z: [INFO] fail: Host.Startup[515]
2024-05-15T10:54:06.693854949Z: [INFO] A host error has occurred during startup operation 'a4e9a887-da42-4883-8330-aa01a0e6f320'.
2024-05-15T10:54:06.695899371Z: [INFO] System.UnauthorizedAccessException: Access to the path '/home/LogFiles/Application/Functions/Host' is denied.
2024-05-15T10:54:06.695919371Z: [INFO] ---> System.IO.IOException: Permission denied
2024-05-15T10:54:06.695925071Z: [INFO] --- End of inner exception stack trace ---
2024-05-15T10:54:06.695929571Z: [INFO] at System.IO.FileSystem.CreateDirectory(String fullPath)
2024-05-15T10:54:06.695934171Z: [INFO] at System.IO.Directory.CreateDirectory(String path)
2024-05-15T10:54:06.696039073Z: [INFO] at System.IO.Abstractions.DirectoryWrapper.CreateDirectory(String path)
2024-05-15T10:54:06.696079873Z: [INFO] at Microsoft.Azure.WebJobs.Script.FileUtility.EnsureDirectoryExists(String path) in /src/azure-functions-host/src/WebJobs.Script/Extensions/FileUtility.cs:line 38
2024-05-15T10:54:06.696176874Z: [INFO] at Microsoft.Azure.WebJobs.Script.ScriptHost.InitializeFileSystem() in /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs:line 488
2024-05-15T10:54:06.696515178Z: [INFO] at Microsoft.Azure.WebJobs.Script.ScriptHost.PreInitialize() in /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs:line 461
2024-05-15T10:54:06.696529978Z: [INFO] at Microsoft.Azure.WebJobs.Script.ScriptHost.InitializeAsync(CancellationToken cancellationToken) in /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs:line 278
2024-05-15T10:54:06.696534778Z: [INFO] at Microsoft.Azure.WebJobs.Script.ScriptHost.StartAsyncCore(CancellationToken cancellationToken) in /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs:line 259
2024-05-15T10:54:06.696539078Z: [INFO] at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
2024-05-15T10:54:06.696543278Z: [INFO] at Microsoft.Azure.WebJobs.Script.WebHost.WebJobsScriptHostService.UnsynchronizedStartHostAsync(ScriptHostStartupOperation activeOperation, Int32 attemptCount, JobHostStartupMode startupMode) in /src/azure-functions-host/src/WebJobs.Script.WebHost/WebJobsScriptHostService.cs:line 376
2024-05-15T10:54:06.696554978Z: [INFO] MS_FUNCTION_AZURE_MONITOR_EVENT 2,func-agsdataretentionmanager-euwe-dev-01.azurewebsites.net,Microsoft.Web/sites/functions/log,FunctionAppLogs,westeurope,"{'appName':'func-agsdataretentionmanager-euwe-dev-01','roleInstance':'6ef9c9795ca7adf6d4220b9465e94987bc1fb6c3766193398f3713e13cd11d7f','message':'A host error has occurred during startup operation a4e9a887-da42-4883-8330-aa01a0e6f320.','category':'Host.Startup','hostVersion':'4.34.1.1','hostInstanceId':'94ce87d9-add2-45fd-8129-cb64f18abcaa','level':'Error','levelId':4,'processId':9,'exceptionDetails':'System.UnauthorizedAccessException : Access to the path /home/LogFiles/Application/Functions/Host is denied. ---> System.IO.IOException : Permission denied\n End of inner exception\n at System.IO.FileSystem.CreateDirectory(String fullPath)\n at System.IO.Directory.CreateDirectory(String path)\n at System.IO.Abstractions.DirectoryWrapper.CreateDirectory(String path)\n at Microsoft.Azure.WebJobs.Script.FileUtility.EnsureDirectoryExists(String path) at /src/azure-functions-host/src/WebJobs.Script/Extensions/FileUtility.cs : 38\n at Microsoft.Azure.WebJobs.Script.ScriptHost.InitializeFileSystem() at /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs : 488\n at Microsoft.Azure.WebJobs.Script.ScriptHost.PreInitialize() at /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs : 461\n at async Microsoft.Azure.WebJobs.Script.ScriptHost.InitializeAsync(CancellationToken cancellationToken) at /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs : 278\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\n at async Microsoft.Azure.WebJobs.Script.ScriptHost.StartAsyncCore(CancellationToken cancellationToken) at /src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs : 259\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\n at async Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\n at async Microsoft.Azure.WebJobs.Script.WebHost.WebJobsScriptHostService.UnsynchronizedStartHostAsync(ScriptHostStartupOperation activeOperation,Int32 attemptCount,JobHostStartupMode startupMode) at /src/azure-functions-host/src/WebJobs.Script.WebHost/WebJobsScriptHostService.cs : 376','exceptionMessage':'Permission denied','exceptionType':'System.IO.IOException','eventId':515,'eventName':'ErrorOccurredDuringStartupOperation'}",05/15/2024 10:54:06
```

#### Known workarounds
Set additional permissions to in-built user
`RUN chown -R $APP_UID:$APP_UID /azure-functions-host && chown -R $APP_UID:$APP_UID /home && chmod g+s /home`

```
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . ./DataRetentionManager
WORKDIR "/src/DataRetentionManager"
RUN mkdir -p /home/site/wwwroot
RUN dotnet publish "DataRetentionManager.csproj" -c Release -o /home/site/wwwroot

FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true

COPY --from=build ["/home/site/wwwroot", "/home/site/wwwroot"]
RUN chown -R $APP_UID:$APP_UID /azure-functions-host && chown -R $APP_UID:$APP_UID /home && chmod g+s /home

USER $APP_UID

EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_HTTP_PORTS 80

HEALTHCHECK NONE
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the .NET 8 isolated container startup with USER $APP_UID and compare it with the documented chown workaround. Start at ScriptHost.InitializeFileSystem in src/azure-functions-host/src/WebJobs.Script/Host/ScriptHost.cs and FileUtility.cs, then trace the /home/LogFiles/Application/Functions/Host access. Done means the host starts as the built-in non-root user without broad extra permissions.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, csharp, docker
Domain
backend, cloud, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.