Scanning Blob storage for viruses with Azure Functions and Docker

While working on a side project, someone asked me how to scan for viruses in a cloud native and serverless landscape. That made me think about a project I did a couple of years back. During that project we used ClamAV that was installed on a VM. We scanned files that end-users uploaded within an ASP.NET application, and everything was hosted on datacenter VMs somewhere in the Netherlands.

ClamAV® is an open source antivirus engine for detecting trojans, viruses, malware & other malicious threats.

In this blogpost I will show a proof of concept using a Docker image and Azure Functions to create a simple automated virusscanner for Azure Blob storage.

Setting up the Docker image

First of all some prerequisites. In this demo I’m running Docker for Windows on my Desktop, and coding in Visual Studio 2019 with local Azure Functions. I’ve already setup a Azure Storage account that I can use as a trigger in my Functions.

First, let’s find a Docker image with ClamAV installed.

There are several to be found on DockerHub, I’ve pulled mkodockx/docker-clamav and it works seamlessly in my demo. To run this, simply execute the following command:

docker run -d -p 127.0.0.1:3310:3310 mk0x/docker-clamav:alpine

It should be running and listening on the default port on localhost.

Creating the Azure Function

The second step is to create a project for our Azure Function:

createproject

We’re using the blob triggered function, because we want to scan all new blobs in the location ‘upload’.

blobtrigger

Now, for scanning, the following NuGet package for nClam should be installed:

Install-Package nClam -Version 4.0.1

The actual code for scanning is pretty simple. Shown below is the code that grabs the file, uploads it to the Docker container and retrieves the status of the scan:

using System.IO;
using System.Linq;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using nClam;

namespace VirusScanFunction
{
    public static class ScanBlobs
    {
        static readonly string serverName = "localhost";
        static readonly int serverPort = 3310;

        [FunctionName("ScanBlobs")]
        public static void Run([BlobTrigger("upload/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob, string name, ILogger log)
        {
            // Create client
            var clam = new ClamClient(serverName, serverPort);
            
            // Scanning for viruses...
            var scanResult = clam.SendAndScanFileAsync(myBlob).Result;

            switch (scanResult.Result)
            {
                case ClamScanResults.Clean:
                    log.LogInformation("The file is clean!");
                    break;
                case ClamScanResults.VirusDetected:
                    log.LogInformation("Virus Found!");
                    log.LogInformation("Virus name: {0}", scanResult.InfectedFiles.First().VirusName);
                    break;
                case ClamScanResults.Error:
                    log.LogInformation("Error scanning file: {0}", scanResult.RawResult);
                    break;
            }
        }
    }
}

That is basically it! You just created your own local virusscanner for your blob storage!

Recap and considerations

Obviously this is a PoC and runs fine ‘on my machine container’. For enterprise environments you should care about what container image to use, how to handle viruses found, and what to do to mitigate problems. You obviously want to warn, and block, the person who uploaded the virus in the first place.

Conclusion

Serverless and containers allow you to setup really cool concepts, and make you think outside the box. Years ago we had to install ClamAV on a VM, where now we can use containers, spin them up, scale them, and dispose when we are done. Think of the possibilities!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s