How to run the Nessus (v7) security scanner in a Docker container
Introduction
I've been looking into automated vulnerability testing quite recently, and decided to give Tenable's Nessus scanner a go. I haven't been using the product anywhere near long enough to write a meaningful review, but I thought that a quick tutorial on how to spin it up in a Docker container might help people that want to try it out for themselves.
There are quite a few ready made Nessus containers on Docker Hub, but the ones I tried seemed either to contain older versions of Nessus, or else were difficult to get set up. Your mileage may vary if you're better with Docker than I am.
Goals
By the end of this article, you should be able to:
- locate and download Nessus Home
- create and apply the correct license key
- create a Docker image that can be used to run the latest version of Nessus Home (7.0.2 at the time of writing)
Prerequisites
- OSX (High Sierra) as a development platform
- a Docker installation
- a working knowledge of the Docker command line
Get Nessus
You'll need to sign up for a free Nessus account, and you can get that sorted out on Tenable's site.
When registration is complete, Tenable will send you an activation code via email.
docker pull fizzymatt/nessus-7-ubuntu
If you're content to take the long way round, however....
Creating the Docker image
As soon as you receive the email containing your activation code, you have everything you need to start writing a Docker file.
- nessus
-- Dockerfile
-- Nessus-7.0.2-ubuntu1110_amd64.deb
FROM ubuntu:16.04
ADD Nessus-7.0.2-ubuntu1110_amd64.deb /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb
RUN apt-get update -y \
&& apt-get install -y apt-utils tzdata \
&& dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \
&& rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb
EXPOSE 8834
CMD service nessusd start && tail -f /dev/null
So what's going on in the Dockerfile?
This first line tells Docker that we want to use Ubuntu as a base image. When we create a container from the image later on, you'll see that Docker pulls in the Ubuntu image automatically.
FROM ubuntu:16.04
Next, we pull the Nessus package that we stored locally into the Docker image, using Docker's ADD command.
ADD Nessus-7.0.2-ubuntu1110_amd64.deb /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb
In order to keep the Docker image as small as possible, the next few lines actually run a few different commands in succession.
RUN apt-get update -y \
&& apt-get install -y apt-utils tzdata \
&& dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \
&& rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb
What are all those ampersands for?
The double ampersands cause one command to be run after another, so we don't need to use RUN as many times.
Every time an instruction is used in a Dockerfile, Docker will add an extra layer to the resulting image, which will cause it to increase in size. For this reason, it's a good idea to take care when adding instructions.
Let's break those commands down a bit:
First of all, we update the package lists for our Ubuntu base.
RUN apt-get update -y \
Next we install "tzdata", which is a package required to process time zone and daylight-saving time data.
&& apt-get install -y apt-utils tzdata \
We then install the Nessus package using Ubuntu's dpkg tool.
&& dpkg -i /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb \
And then, remove the Nessus package that we pulled in from our local environment. Nessus is installed, so there's no point in having a redundant package hanging around just taking up valuable space.
&& rm -r /tmp/Nessus-7.0.2-ubuntu1110_amd64.deb
The Nessus scanner listens for requests on port 8834, so we tell Docker to expose it on our image
EXPOSE 8834
Finally, we run the commands that will start the Nessus process when a container, based on our image, is run.
CMD service nessusd start && tail -f /dev/null
The first command starts the nessusd service....
CMD service nessusd start ....
....and the second command is actually a workaround to prevent the container from exiting after the nessusd process starts.
The nessusd process runs in the background, which causes Docker to think that the application process has stopped, so we need to create a foreground process to persist our container. The tail command is an example of a process that runs in the foreground, and in our Dockerfile we tell it to write to the /dev/null directory.
/dev/null is a special directory by default on Unix systems, and writing to it has no effect (reading from /dev/null should return 0 bytes). There are no logs being filled up or anything like that, and so we can use it to keep our container up and running without any impact on the main nessusd process.
.... tail -f /dev/null
Building the Docker image
docker build -t fizzymatt/nessus-7-ubuntu .
The argument allows us to provide a tag that we can use to reference the image. It's best to read the Docker documentation for recommendations about creating tags, but I'll be using "fizzymatt/nessus-7-ubuntu" for the purposes of this article.
The last argument "." tells Docker to search for the Dockerfile in the location where the command is run, so if you're running the command in a different location, be sure to provide the path.
docker images
You should see the "fizzymatt/nessus-7-ubuntu" image (or however you decided to tag it) listed in the output.
Running the Docker container
Now it's time to run a container (an instance of an image) based upon the image that we built.
docker run -d --name nessus-7-ubuntu -p 8834:8834 fizzymatt/nessus-7-ubuntu
The (detached) argument tells Docker that we want to run the container without attaching a terminal.
The is just a handy way to reference your container.
The argument allows us to publish a specific port to the host. Here we've published port 8834 (the port that our containerised Nessus instance listens on) to port 8834 on the host (which in my case is my laptop).
The final argument (fizzymatt/nessus-7-ubuntu) is a reference to the image that we're using to create the container.
docker ps -a
This command tells Docker to list all containers, regardless of their state.
If all's well, you should see the name of your container in the output. Beneath the PORTS heading you'll see "0.0.0.0:8834->8834/tcp", and the STATUS will be "Up".
Accessing Nessus
Now that the container is spinning, you should be able to access the Nessus instance.
There will then follow a great deal of downloading and installing, which took a few minutes over my modest internet connection.
When all this has finished, you'll be presented with a screen similar to the following:
If you click on "Create a new scan", you should be able to see all the installed templates.
Summary
By this stage you should have a running Docker container that you can use to get a feel for how Nessus works.
You're on your own from here, as I've not had time to give Nessus a decent test run, but hopefully this has been enough to get you off the starting blocks.
Remember that data will only be persisted inside the container given our current setup, so if you want your settings to stick around after you've stopped or rebuilt the container then you'll probably need to look into using a data volume.
That's beyond the scope of this article, but I might create a "Part 2" if and when I have more experience with the product.
Happy scanning :)
If you liked that article, then why not try:
Symfony 4: setting up a new project
How to set up a Symfony 4 project from scratch using the Composer dependency manager.