Create a Containerized Kali Linux in Docker
— Tutorial, Kali, Linux, Headless, Docker, Containerization — 9 min read
I'm Brett Fullam, a creative technologist turned networking and cybersecurity specialist passionate about security automation. In this blog post, I'm going to show you how create "containerized" Kali Linux in Docker that can be up and running in seconds to give you "extremely quick and easy access to Kali's toolset without the overhead of an isolated virtual machine" - Kali.org .
Why Docker and not a VM?
In the past, I would spin up a dedicated virtual machine to work with Kali Linux using VMware or VirtualBox. However, there are instances where you may not have to work with a VM, and Docker is the perfect alternative solution.
First, you'll need to decide what it is you'll be using Kali for:
Do you need access to the GUI, or will you be working with tools directly in the command-line?
Do you need the environment Kali is running on to be 'more' secure, or do you just need quick access to the tools available in Kali?
Depending on your answers to these questions you can determine which environment will be a better fit for specific needs on a case by case basis.
If you need access to the GUI, and the additional security a VM provides ... then a VM running Kali Linux is your best choice.
However, if you're only working with tools in the command-line, and security is less of a concern ... then Kali Linux running inside of a Docker container is the perfect choice.
VMs ... A love-hate relationship
VM's are notoriously slow to spin up, and switching back and forth between the VM and your local system is cumbersome. Even sharing files isn't necessarily streamlined by design to uphold a higher security profile. It can be a tedious experience depending on the task you are trying to perform.
If security isn't a concern and I don't need GUI access, then a VM is my last choice.
Containerization Baby
It's true, a VM is certainly more secure than a Docker container (for now, at least). However, spinning up a Docker image is ridiculously fast. Like, "up in seconds" fast, and directly accessible right inside of the host operating system. Did I mention there's even a performance boost?
Docker Containers and Persistance
Every time you spin up your Docker image of Kali any documents created or packages installed will not be saved. By default, Docker containers do not include persistance and any changes you make in the running Docker image will be lost.
However, there are two options available to us to overcome this.
Update the running Docker image by committing the changes in it's current state, or ...
Creating a shared directory with the local system so you can use your local IDE of choice (in my case VScode) to interact with it, and to share files freely with the host operating system.
Getting Started
Docker
For those of you unfamiliar with Docker, this is an excellent project to get you started. We'll only be using a few basic Docker commands, and installing Docker is a snap.
Installation
If you don't already have Docker installed, I recommend you go to Docker.com, and follow their recommended installation documentation for your operating system.
Once Docker is installed, open up a terminal, and let's confirm that it's been installed and running.
docker --version
If it's running, you should see the version details in the terminal. At the time this blog post was written, the most current Docker version was:
Docker version 20.10.11, build dea9396
If not, find and launch Docker Desktop on your host environment. While you can launch Docker from the terminal, it's quite complicated and not recommended.
Grab a copy of the Official Docker Image
Let's grab a copy of the Official Docker Image "kalilinux/kali-rolling". To do this, make sure Docker is running, open a terminal and enter the following command:
docker pull kalilinux/kali-rolling
You should see the following output:
Using default tag: latestlatest: Pulling from kalilinux/kali-rollingcd520bb53672: Pull complete Digest: sha256:a2414437408f0a042db7957451a961b67b37bf5c2297967952dedb080a923a0dStatus: Downloaded newer image for kalilinux/kali-rolling:latestdocker.io/kalilinux/kali-rolling:latest
Create a custom Docker Image for Kali Linux
Once the kali linux image has been downloaded, let's use the following command to confirm it's in our local Docker image library:
docker images -a
You should see a list of Docker images in the output, specifically our Kali image:
REPOSITORY TAG IMAGE ID CREATED SIZEkalilinux/kali-rolling latest 9d14852dfffb 2 days ago 126MB
Create a Docker container
Let's create a Docker container using the kalilinux/kali-rolling image we just downloaded:
docker run -t -i kalilinux/kali-rolling /bin/bash
You should immediately see the following in your terminal:
┌──(root💀bed5e36a21ca)-[/]└─#
This command creates a container and immediately opens a Linux root bash. BOOM. That took what ... seconds to come up?
If you didn't notice, our Kali instance was up and running in our container immediately ... no waiting for loading, and yes, it’s really a full fledged linux machine running Kali Linux!
PLEASE NOTE ... If you exit this prompt you will be back in your local operating system, and you will have to repeat these steps to get your system up and running again.
Let's have a look at the file system and list the directories by using the "ls" command:
ls
You should see the following output:
┌──(root💀bed5e36a21ca)-[/]└─# lsbin dev home lib32 libx32 mnt proc run srv tmp varboot etc lib lib64 media opt root sbin sys usr
Now let's confirm the version of our system
cat /etc/os-release
You should see the following details about the container in the output returned:
┌──(root💀bed5e36a21ca)-[/]└─# cat /etc/os-releasePRETTY_NAME="Kali GNU/Linux Rolling"NAME="Kali GNU/Linux"ID=kaliVERSION="2021.4"VERSION_ID="2021.4"VERSION_CODENAME="kali-rolling"ID_LIKE=debianANSI_COLOR="1;31"HOME_URL="https://www.kali.org/"SUPPORT_URL="https://forums.kali.org/"BUG_REPORT_URL="https://bugs.kali.org/"
If you haven't already noticed, the Kali Linux toolset, known as the default "metapackage", has not been installed. We'll be installing the toolset and customizing our image in the following section.
Installing the "Metapackage"
At this point, and with our Kali container still running, we'll install the default "metapackage" and save these changes by creating a new Docker image.
First, let's install Kali's toolset referred to as the the default "metapackage", with the following command:
apt update && apt -y install kali-linux-headless
For those of you who don't know, the "-y" option keeps the installation from failing whenever a "yes/no" question appears typically requiring user input. This is particularly useful when building Docker containers from a Dockerfile.
When the installation is finished, you can install any additional tools that you would like to include in our custom Docker image.
PLEASE NOTE ... If you exit this prompt you will be back in your local operating system, and you will have to repeat these steps to get your system up and running again up to this point.
Create the shared folder on our Docker container
Now all that's left is to create a directory on our running Docker container that will be shared with the host operating system.
Let's navigate to the /home directory and create a new directory called "shared" with the following commands:
cd /homemkdir shared
Create a new Docker image from the running containers
When you're finished installing Kali's toolset and created the "shared" folder in the /home directory, it's time to save the current state of our running container as a new Docker image.
Leave the Docker container running Kali open, and open a separate terminal. The Kali container needs to be running in order to save it as a Docker image. DO NOT exit out of the Kali container, or you will have to redo all of the steps and installation up to this point.
In the separate terminal, not the kali command prompt, use the following command to "commit" the changes to our running Kali Docker container, and save it as a new custom Docker image:
Before we can commit any of our changes, we'll need some information associated with our running Ubuntu container.
In order to do this, we'll need to open a SEPARATE terminal window on you local host. All of the commands that follow happen in this new-separate terminal, and not in our running container's terminal.
The container's terminal needs to stay open and running, so do not exit out of that prompt.
First, in the new terminal window on our local host, we need to see the information about our running container by using the docker ps -a command:
docker ps -a
You should see something similar to this in the output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESbed5e36a21ca kalilinux/kali-rolling "/bin/bash" 5 hours ago Up 5 hours priceless_roentgen
We'll need the "container ID" from the terminal output, and we'll need to create a "tag" name for our modified image. Here's how the docker commit command is structured:
docker commit <running container id> <tag name of our new image>
Let's fill it in with our container ID, add a tag name "kali_base" and run the following command.
docker commit bed5e36a21ca kali_base
While the docker commit command is running, the Kali Linux terminal will be unresponsive. It's currently "paused" until the Docker image is finished being created.
Once the docker commit command is finished you should be presented with a sha256 sum of the new image which also serves as it's "image ID" number.
sha256:5ccd28331992a43c527dc3a044d1ce0316eb095d37ffd95ec44e68428b689ce9
Let's confirm that the custom image has been saved by using the docker images -a command
docker images -a
You should see the new "kali_base" Docker image we just created in the output.
REPOSITORY TAG IMAGE ID CREATED SIZEkali_base latest 5ccd28331992 About a minute ago 6.89GB
Notice that it is named "kali_base" in the "REPOSITORY" column. If you notice the "image ID" column only shows a part of the sha256 value we were presented with when the image was saved.
We're all set! All of the changes we made to the running Kali Docker image up to this point have been saved to our new docker image "kali_base", and you now can exit out of the running Kali container's prompt.
Using our kali_base Docker image
Finally, we're at a point where we're ready to fire up our new container from our kali_base Docker image.
Docker clean up
First things first. We'll need to do a little clean up, by removing the container we used to create our custom image. Run the docker ps -a command to see all running (and stopped) containers.
docker ps -a
You should see something similar to this output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESbed5e36a21ca kalilinux/kali-rolling "/bin/bash" 5 hours ago Exited (127) 6 minutes ago priceless_roentgen
Leave this output up, and look for the "NAME" column on the far right side. We'll need that to be able to remove this exited container from the list using the docker rm -f command:
docker rm -f <container "NAME"> docker rm -f priceless_roentgen
If done correctly, it will no longer appear in the list when you run the docker ps -a command to view the running-stopped containers:
docker ps -a
Create a container using our new Docker image
Now we're ready to create a container based on our new modified kali_base Docker image, and we're going to add a directory on the host operating system to be linked to our shared volume on the Kali container we'll be creating.
First, create a directory on your host operating system where you can share files between the container and the host.
After you create the directory make sure you take note of the full path to it. We'll be adding that into the commands that follow.
Next we're going to use the following docker command to perform the following actions:
- name the new container
- set the environment variable for the HOST_IP address
- mount the volume using the file path to the shared directory on the local host and where it maps to in the container's file system
- tell it which image to use
- have it return a command prompt on the container
On Mac:
IMPORTANT ... you will need to update "user" with your actual username listed in the file path.
Tip: You can use the "pwd" command from inside of the folder you create on the local host to get this information.
docker run \ --name kali_linux \ -e HOST_IP=$(ifconfig en0 | awk '/ *inet /{print $2}') \ -v /Users/user/Documents/PROJECTS/Docker/Docker-kali:/home/shared \ -t -i \ kali_base /bin/bash
The "--name" is what we want to call the container that gets created. Further down in the command you'll see "kali_base" followed by "/bin/bash". This indicates which image we want to use to create our image, and that we want to return a command prompt.
On PC:
Windows OS (from docker CLI powershell)
Tip: You'll need to manually change your IP address to match your local dev machine.
docker run ` --name golangDev ` -e HOST_IP=192.168.1.166 ` -v //c/Users/user/Workspaces/Docker-kali:/home/shared ` -t -i ` ubuntu /bin/bash
The "--name" is what we want to call the container that gets created. Further down in the command you'll see "kali_base" followed by "/bin/bash". This indicates which image we want to use to create our image, and that we want to return a command prompt.
Once you edit the details to match your local system, copy and paste the entire command into the terminal.
Upon successful completion you should be presented with a Linux root bash like this:
┌──(root💀33b224f6c0c2)-[/]└─#
BOOM! Did you see how fast that came up!
Confirm our Kali Docker container is good to go
Using the terminal in our new Kali Docker container, navigate to the /home directory and confirm that the "shared" folder is present.
cd /home
ls
Persistence and the Shared directory
Everything is good to go, but we have one last important item to go over. The shared directory.
On the local host, go to the directory you indicated to be shared with the container.
On the local host, using any IDE of your choice create a document called hello.txt inside of the shared directory.
Paste the following into the hello.txt document, and make sure it's saved into the shared directory on the host.
Hello Kali Docker container!
- Go back to the terminal with your running Kali Docker container and navigate to the /home/shared directory and list it's contents
cd /shared
ls
You should see the hello.go document we created in our local IDE! Use the cat command to read the content of hello.txt.
cat hello.txt
Hello Kali Docker container!
Now we can edit and share files between the host operating system and the new Kali Docker container.
Kali Docker container complete!
That's it! We now have a "containerized" Kali Linux Docker container that we can launch in seconds, easily share files between the host and the container, and have any files persist thanks to our shared directory.
PLEASE NOTE ... Any files stored outside of the /shared directory will not persist, and will be destroyed when you exit the container.
Once it's up and running, you can install any packages, experiment, and break things all without damaging your host system. What's even better is that the Kali Docker container is reset every time you run a new container with our kali_base image.
I hope you've enjoyed this tutorial and good luck!