[Developer's community]

Enable SSH for containerized Azure Functions

Very often, in the active development phase, regular logging does not help too much. Azure Functions that process some data or heavier payloads (like images or video files even) tend to store temporary processing data inside the container. By default, there's no way you can get inside the container to take a look at what's going on at the file system level. For such purposes, Secure Shell (SSH) is commonly used to execute administrative commands remotely from a command-line terminal.

If you take a brief look at the options available in the 'Development tools' section in the Azure Function service, you can spot the 'SSH' blade, but everything you can get out of it is this:

The error popping up could be quite misleading, but that's expected behavior. The SSH is disabled by default (for security reasons), and you can temporarily enable it if more in-depth troubleshooting/investigation is needed.

If you initialized the Azure Function using CLI (along with the Dockerfile), you should be seeing the manifest file looking like this:

FROM mcr.microsoft.com/azure-functions/python:3.0-python3.7
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
COPY requirements.txt /
RUN pip install -r /requirements.txt
COPY . /home/site/wwwroot

It looks neat and tidy, and it even comes with the comment now that suggests how to enable the SSH easily:

# To enable ssh & remote debugging on app service, change the base image to the one below
# FROM mcr.microsoft.com/azure-functions/python:2.0-python3.6-appservice

All you need to do is change the base image to the one that already has the SSH enabled and redeploy. The instruction is also well described in the documentation here.

What if you use the Docker image like this, where you need to restore 'WebJobs.Script.WebHost. csproj' first (even though your function is Python or TypeScript-based)? In that case, the base image layer is a .NET Core SDK pulled from here:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS runtime-image

Only when all the mentioned dependencies are restored, you pull another image for Python to restore Python-based dependencies:

FROM python:3.7-slim-buster

What would you do to enable SSH here? Fortunately, there's a way out here. It includes SSH server (OpenSSH) deployment/restore as part of the Docker image build procedure. The repository here contains some of the essential pre-requisites, like 'sshd_config' and 'start.sh', with no answers to the question -  what to do with all that stuff? The config file is all about the systemwide SSH server configuration, and it won't change. The shell script (and I renamed it into 'init.sh' in my case) starts the actual service. In the Dockerfile, you need need to insert a couple of lines to get the OpenSSH, define the password, and get the service started (by executing 'init.sh' at the end). What? Password in the Dockerfile definition??? Well, as we discussed, the SSH is turned-off in containers for a reason, so the change is aimed at troubleshooting purposes only. The change you would need to perform is the following:

# ssh
ENV SSH_PASSWD "root:Docker!"
RUN apt-get update \
    && apt-get install -y --no-install-recommends openssh-server \
    && echo "$SSH_PASSWD" | chpasswd

COPY sshd_config /etc/ssh/
COPY init.sh /usr/local/bin/

RUN chmod u+x /usr/local/bin/init.sh
#CMD [ "/azure-functions-host/Microsoft.Azure.WebJobs.Script.WebHost" ]
EXPOSE 80 2222
ENTRYPOINT ["init.sh"]

After you build the container with something like this:

docker build -t my-func -f Dockerfile .

You're good to give it a try locally first, to make sure it works as expected:

docker run -p 2222:2222 -it my-func

We're mapping a port exposed in a container to a port available in our system. Once the container is up and running, we can connect Putty (or any other SSH client) with the loopback address ( and port 2222. The picture after successful login with the credentials provided should be the following:

Ok, that's basically it. Once this is deployed to Azure Function, you should be able to access your container from either Kudu console or SSH blade:

That's more like it!

The complete solution can be found in my GitHub repository.

Add comment