I have a python Azure function with a specific business logic.
In the Dockerfile
, I want to run the container as a non-root user, so I did the following:
FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8
.
.
.
RUN useradd -u 1001 -m fem-downloader
RUN chown -R 1001:1001 /home/
# I Changed the AzureWebJobsScriptRoot value to this new user path
ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
USER fem-downloader
COPY --chown=fem-downloader:fem-downloader requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY --chown=fem-downloader:fem-downloader . /home/fem-downloader/wwwroot
WORKDIR /home/fem-downloader/wwwroot/HttpTrigger/
ENV PATH="/home/fem-downloader/.local/bin:/home/.local/bin:${PATH}"
RUN pip install pytest && python3 -m pytest --verbose
When I run the Azure function locally, it works:
docker run -ti -p 8001:80 --name my-azure-function my-azure-function:nonroot
info: Host.Startup[0]
Found the following functions:
Host.Functions.HttpTrigger
info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
Initializing function HTTP routes
Mapped function route 'api/HttpTrigger' [post] to 'HttpTrigger'
info: Host.Startup[412]
Host initialized (202ms)
info: Host.Startup[413]
Host started (211ms)
info: Host.Startup[0]
Job host started
Hosting environment: Production
Content root path: /home/my-project/wwwroot/HttpTrigger
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.
info: Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcFunctionInvocationDispatcher[0]
Worker process started and initialized.
info: Host.General[316]
Host lock lease acquired by instance ID '00000000000000000000000043EEAD9A'.
Even I test it by sending the parameters its expect:
> curl -X POST http://localhost:8001/ -d "stream_id=XXXX&file_type=SCIA&server_url=https://aaaa.bbbbb.cccccc.digital"
<!DOCTYPE html>
<html>
<head>
<title>Your Azure Function App is up and running.</title>
<style type="text/css">
@font-face {
font-family: 'SegoeLight';
src: url(//:) format('no404'), url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAFbcABAAAAAAjewAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABbAAAABsAAAAcWqtaPUdERUYAAAGIAAAAHQAAACABGAADT1MvMgAAAagAAABYAAAAYGrqcLZjbWFwAAACAAAAAaIAAAIKczqUA2N2dCAAAAOkAAAATAAAAEwOEAwRZnBnbQAAA/AAAAGxAAACZQ+0L6dnYXNwAAAFpAAAAAwAAAAMAAMAB2dseWYAAAWwAABJAAAAe3CDYeDNaGVhZAAATrAAAAAxAAAANv
But when I deploy it on Azure, I've checked the logs:
2021-02-12T21:42:12.204812448Z warn: Host.Startup[0]
2021-02-12T21:42:12.205484355Z No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
2021-02-12T21:42:12.212736520Z info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
2021-02-12T21:42:12.212758420Z Initializing function HTTP routes
2021-02-12T21:42:12.212763520Z No HTTP routes mapped
2021-02-12T21:42:12.204812448Z warn: Host.Startup[0]
2021-02-12T21:42:12.205484355Z No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
2021-02-12T21:42:12.212736520Z info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
2021-02-12T21:42:12.212758420Z Initializing function HTTP routes
2021-02-12T21:42:12.212763520Z No HTTP routes mapped
That socket address error is because the container couldn't manage to initialized, due to the configuration value for AzureWebJobsScriptRoot
I provided, I mean the change of the route.
ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
Reading on, I found this issue
it doesn't seem like Azure is honoring the AzureWebJobsScriptRoot setting. If I set it to something like D:\home\site\wwwroot\foo, it is still loading functions from D:\home\site\wwwroot (even though I have host.json and function folders under D:\home\site\wwwroot\foo).
The setting seems to work correctly in local environments, but not on Azure.
Looking at the azure function host project, by default the WebHostScriptPath
is configured of this way: Data[WebHostScriptPathProperty] = Path.Combine(home, "site", "wwwroot");
The config settings also confirm it.
As they discussed in the issue it seems Azure has good reasons behind to don't allow to change this AzureWebJobsScriptRoot
value.
UPDATE
Even I tried by setting this path to the default value, and on the other hand, working with a non-root user giving it permissions over that path (/home/site/wwwroot
) in this way without success:
FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8
RUN useradd -u 1001 -m fem-downloader
RUN chown -R 1001:1001 /home/
# ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
# AzureFunctionsJobHost__Logging__Console__IsEnabled=true
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
USER fem-downloader
COPY --chown=fem-downloader:fem-downloader requirements.txt requirements.txt
RUN pip install -r requirements.txt
# COPY --chown=fem-downloader:fem-downloader . /home/fem-downloader/wwwroot
COPY --chown=fem-downloader:fem-downloader . /home/site/wwwroot
# WORKDIR /home/fem-downloader/wwwroot/HttpTrigger/
WORKDIR /home/site/wwwroot/HttpTrigger/
# ENV PATH="/home/fem-downloader/.local/bin:/home/.local/bin:${PATH}"
ENV PATH="/home/site/.local/bin:/home/.local/bin:${PATH}"
RUN pip install pytest && python3 -m pytest --verbose
I got the same result when the function is deployed on Azure.
Is highly probably this topic can be managed with permissions, so I decided to check the existing permissions on the directory by getting access to the container created and we got 755
, so all permissions for user, execution, and read for group and others:
fem-downloader@cdf0ec64f1ce:~$ pwd
/home
fem-downloader@cdf0ec64f1ce:~$ ls -all
total 48
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 12:36 .
drwxr-xr-x 1 root root 4096 Feb 15 12:36 ..
drwxr-xr-x 3 fem-downloader fem-downloader 4096 Feb 15 12:36 .aspnet
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 10:46 .cache
drwx------ 1 fem-downloader fem-downloader 4096 Feb 15 10:47 .local
drwxr-xr-x 3 fem-downloader fem-downloader 4096 Feb 15 12:36 LogFiles
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 12 20:25 fem-downloader
# /home/site directory
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 10:47 site
fem-downloader@cdf0ec64f1ce:~$
Checking the permissions privileges for /home/site/
directory:
fem-downloader@cdf0ec64f1ce:~$ stat -c "%a %A" site
755 drwxr-xr-x
fem-downloader@cdf0ec64f1ce:~$
Checking the permissions privileges for /home/site/wwwroot/
directory:
fem-downloader@cdf0ec64f1ce:~/site$ stat -c "%a %A" wwwroot/
755 drwxr-xr-x
fem-downloader@cdf0ec64f1ce:~/site$
The only way I manage to successfully deploy the function on azure was by running my container as a root user:
# Intermediate stage when installing pip packages and other requirements
.
.
FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
COPY --from=intermediate /usr/local/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/
ADD requirements.txt /
RUN pip install -r /requirements.txt
ADD . /home/site/wwwroot
WORKDIR /home/site/wwwroot/HttpTrigger/
RUN pip install pytest && pytest --verbose
Then the function manage to contact the storage account to download the resource we are indicating in the request done above:
***"container": "xxxx", "file_name": "PNd5efdCf-SCIA-xxxxxxx.zip", "sas_url": "abc0spec0test0xxxdwblob0.blob.core.windows.net/xxx/PNd5efdCf-SCIA-xxxxxxx.zip?sv=2018-03-28&ss=b&srt=co&sp=r&se=2021-02-12T19%3A45%3A28Z&st=2021-02-12T18%3A40%3A28Z&spr=https&sig=xxxxxxxxxxxxxxxxxx
I just wanted to put here as many details as I can, just to see if perhaps someone has been experienced the same.
Not sure if from a Dockerfile
perspective I can do something to cheat Azure configuration settings, looks like not, but the thing is I don't want to run my container as a root user
Does it seem there is nothing to do about changing the AzureWebJobsScriptRoot
variable?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With