
Kali Linux VM images build script
This is the build script to create the Kali Linux Virtual Machine (VM) images.
Currently there are two build methods are possible:
build.sh - build straight from your machinebuild-in-container.sh - build from within a container (Docker or Podman)Either way, the build actually happens from within a virtual machine that is created on-the-fly by the build tool debos. Debos uses fakemachine under the hood, which in turn relies on QEMU/KVM.
Make sure that the git repository is cloned locally:
$ sudo apt install -y git
$ git clone https://gitlab.com/kalilinux/build-scripts/kali-vm.git
$ cd kali-vm/
Due to the requirements of QEMU/KVM, you must be part of the kvm group.
You can check by doing:
$ # Not apart of the group
$ grep kvm /etc/group
kvm:x:104:
$
$ # In the group
$ grep kvm /etc/group
kvm:x:104:kali
If your username does not appear in the line returned, it means that you are not in the group, and you must add yourself to the kvm group:
$ sudo adduser $USER kvm
Then log out and log back in for the change to take effect.
If building straight from your machine, using build.sh, you will need to install debos:
$ sudo apt install -y 7zip debos dosfstools qemu-utils zerofree
Then use the script build.sh to build an VM image directly on your machine.
If you prefer to build from within a container, you will need to install and configure either docker or podman on your machine.
Then use the script build-in-container.sh to build a image.
build-in-container.sh is simply a wrapper on top of build.sh.
It will detect which OCI-compliant container engine to use, takes care of creating the container image if missing, and then finally it starts the container to perform the build from within.
docker requires the user to be added to the Docker group, just like the above with KVM, or using the root account (e.g. $ sudo ./build-in-container.sh).
podman has been tested with both as rootful (e.g. $ sudo ./build-in-container.sh) and rootless (e.g. $ ./build-in-container.sh).
Use either build.sh or build-in-container.sh, at your preference.
From this point we will use build.sh for brevity.
The best starting point, as always, is the usage message:
$ ./build.sh -h
Usage: build.sh <options> [-- <debos options>]
Build a Kali Linux VM image
Build options:
-a ARCH Build an image for this architecture, default: amd64
Supported values: amd64
-b BRANCH Kali branch used to build the image, default: kali-rolling
Supported values: kali-dev kali-last-snapshot kali-rolling
-f FORMAT Format to export the image to, default depends on the VARIANT
Supported values: hyperv ova ovf qemu raw vagrant virtualbox vmware
-k Keep raw disk image and other intermediary build artifacts
-m MIRROR Mirror used to build the image, default: http://http.kali.org/kali
-r ROOTFS rootfs to use to build the image, default: none
-s SIZE Size of the disk image in GB, default: 86
-v VARIANT Variant of image to build (see below for details), default: generic
Supported values: generic hyperv qemu rootfs virtualbox vmware
-x VERSION What to name the image release as, default: rolling
-z Zip images and metadata files after the build
Customization options:
-D DESKTOP Desktop environment installed in the image, default: xfce
Supported values: e17 gnome i3 kde lxde mate xfce none
-H HOSTNAME Set system host name, default: kali
-K KEYBOARD Set keyboard layout, default: us
Refer to the README.md for more details
-L LOCALE Set locale, default: en_US.UTF-8
-P PACKAGES Install extra packages (comma/space separated list)
-T TOOLSET The selection of tools to include in the image, default: default
Supported values: default everything headless large none
-U USERPASS Username and password, separated by a colon, default: kali:kali
-Z TIMEZONE Set timezone, default: America/New_York
The different variants of images are:
generic Image with all virtualization support pre-installed, default format: raw
hyperv Image pre-configured for Hyper-V "Enhanced Session Mode", default format: hyperv
qemu Image with QEMU and SPICE guest agents pre-installed, default format: qemu
rootfs Not an image, a root filesystem (no bootloader/kernel), packed in a .tar.gz
virtualbox Image with VirtualBox guest utilities pre-installed, default format: virtualbox
vmware Image with Open VM Tools pre-installed, default format: vmware
The different formats are:
hyperv VHDX disk image, powershell install scripts
ova streamOptimized VMDK disk image, OVF metadata file, packed in a OVA archive
ovf monolithicSparse VMDK disk image, OVF metadata file
qemu QCOW2 disk image, no metadata
raw sparse disk image, no metadata
virtualbox VDI disk image, .vbox metadata file
vmware 2GbMaxExtentSparse VMDK disk image, VMX metadata file
Supported environment variables:
http_proxy HTTP proxy URL, refer to the README.md for more details
Most useful debos options:
--artifactdir DIR Set artifact directory, default: images
--memory, -m SIZE Limit amount of memory to build VM in GB, default: 4G
--scratchsize SIZE Limit amount of HDD to build VM in GB, default: 45G
--debug-shell Get a shell on the VM
--help, -h See the complete list of options for debos
Refer to the README.md for examples
The default options will build a Kali rolling image, default desktop and default toolset for AMD64 architecture.
This is a raw disk image, i.e. a plain binary image of the disk (which can be started with QEMU).
Example:
$ ./build.sh
To build a Kali Linux image tailored for VMware. It means that it comes with the Open VM Tools pre-installed, and the image produced is ready to be imported "as is" in VMware.
Also, we are going to build it from the last stable release of Kali, and we will using GNOME as the desktop environment, rather than the usual default Xfce:
./build.sh -v vmware -b kali-last-snapshot -D gnome
To build a Kali Linux image designed for VirtualBox. It comes with the VirtualBox guest utilities pre-installed, and the image can be imported "as is" in VirtualBox.
Moreover, we want a 150 GB virtual disk, and we will install the "everything" tool selection:
./build.sh -v virtualbox -s 150 -S everything
To build a lightweight Kali image, which has no desktop environment and no default toolset. This is a generic image, it comes with support for most VM engines out there. We will export it to the OVA format, suitable for both VMware and VirtualBox.
You can install additional packages with the -P option.
Either use the option several times (e.g. -P pkg1 -P pkg2 ...), or give a comma/space separated value (e.g. -P "pkg1,pkg2, pkg3 pkg4"), or a mix of both.
Let's also install the package metasploit-framework:
./build.sh -v generic -f ova -D headless -P metasploit-framework
When building a series of images, it might be more convenient (and faster) to split the build in two parts: first, build a rootfs, and then build the images by re-using this rootfs as a starting point.
In the example below, we built a kali-rolling rootfs first, and then we build a series of Vagrant images:
./build.sh -b kali-rolling -v rootfs
./build.sh -r images/rootfs-rolling-amd64.tar.gz -f vagrant -v hyperv
./build.sh -r images/rootfs-rolling-amd64.tar.gz -f vagrant -v qemu
./build.sh -r images/rootfs-rolling-amd64.tar.gz -f vagrant -v virtualbox
./build.sh -r images/rootfs-rolling-amd64.tar.gz -f vagrant -v vmware
To set the keyboard settings, use the option -K.
The setting is of the form <layouts>/<models>/<variants>/<options>. Each setting can be omitted (in that case the default is used), or can have multiple values separated by commas. In the most simple case, you might just want to change the keyboard layout, so you'd set us for a US keyboard layout, de for a German keyboard layout, and so on. Longer explanations and examples can be found in the keyboard(5) manual page.
For the list of supported values, you can refer to the file /usr/share/X11/xkb/rules/xorg.lst (provided by the package xkb-data on Debian and Debian-like systems). This file has different sections (! layout, ! model, !variant and !option) that list the possible values for each setting.
You can also check what's configured on your system with .
There is also a shortcut of to match the host system (ie. what's set in the file ).
To set the locale, use the option -L.
Pick a value in the 1st column of /usr/share/i18n/SUPPORTED, or check what's configured on your system with grep -v ^# /etc/locale.gen, or simply echo $LANG.
There is also a shortcut of -L same to match the host system.
To set the timezone, use the option -Z.
Look into /usr/share/zoneinfo and pick a directory and a sub-directory.
In doubt, run tzselect to guide you, or look at what's configured on your system with realpath /etc/localtime.
There is also a shortcut of -Z same to match the host system.
To set the name and password for the unprivileged user, use the option -U.
The value is a single string and the : is used to separate the username from the password.
Here we will build a Kali image, and configure it to mimic the host system: same locale and same timezone and same username (with the password of password):
./build.sh -K same -L same -Z same -U $USER:password
Different variants of image can be built, depending on what VM engine you want to run the Kali image in. The VARIANT mostly defines what extra package gets installed into the image, to add support for a particular VM engine. Then the FORMAT defines what format for the virtual disk, and what additional metadata files to produce.
If unset, the format (option -f) is automatically set according to the variant (option -v).
Not every combination of variant and format make sense, so the table below tries to summarize the most common combinations.
The generic images come with virtualization support packages pre-installed for QEMU, VirtualBox and VMware, hence the name "generic".
While other images, that target a specific VM engine, only come with support for this particular virtualization engine.
Only the format ova defines a container: the result of the build is a .ova file, which is simply a tar archive.
For other formats, the build produce separate files.
They can be bundled together in a 7z archive with the option -z.
There is also a rootfs type: this is not an image.
It's simply a Kali Linux root filesystem tree, without the kernel and the bootloader, and packed in a .tar.gz archive.
The main use-case is to reuse it as input to build an OS image, and it's not meant to be used outside of the build system.
When building OS images, it is useful to have a caching mechanism in place, to avoid downloading all the packages from the Internet, again and again.
To this effect, the build script attempts to detect known caching proxies that would be running on the local host. If first refers to the local APT configuration Acquire::http::Proxy. If not set, it then tries to detect apt-cacher-ng and squid-deb-proxy by checking if a service is listening on their default port. This mechanism doesn't work for approx (a well-known APT caching proxy), as it's auto-started on demand.
To override this detection, you can export the environment variable http_proxy yourself.
However, you should remember that the build happens within a QEMU Virtual Machine, therefore localhost in the build environment refers to the VM, not to the host.
If you want to reach the host from the VM, you probably want to use http://10.0.2.2.
For example, if you want to use a proxy that is running on your machine on the port 9876, use: export http_proxy=http://10.0.2.2:9876.
If you want to make sure that no proxy is used, use: export http_proxy=.
Also refer to https://github.com/go-debos/debos#environment-variables for more details.
Alternatively, you can setup a local mirror.
It's possible to break the build in two steps.
You can first build a rootfs with ./build.sh -v rootfs, and then build an image based on this rootfs with ./build.sh -r ROOTFS_NAME.tar.gz.
It makes sense if you plan to build several image types, for example.
When the scratch area gets full (i.e. the --scratchsize value is too low), the build might fail with this kind of error messages:
[...]: failed to write (No space left on device)
[...]: Cannot write: No space left on device
Solution: bump the value of --scratchsize.
You can pass arguments to debos after the special character --, so if you need for example 50G, you can do ./build.sh [...] -- --scratchsize=50G.
When debugging build failures, it's convenient to be dropped in a shell within the VM where the build takes place.
This is possible by giving the option --debug-shell to debos: ./build.sh [...] -- --debug-shell.
This is a known issue, refer to https://gitlab.com/kalilinux/build-scripts/kali-vm/-/work_items/25#note_1301070132 for a workaround.
cat /etc/default/keyboard-K same/etc/default/keyboard| variant | format | disk format | metadata | pack |
|---|
| generic | raw | raw (sparse file) | none | |
| generic | ova | streamOptimized VMDK | OVF | OVA |
| generic | ovf | monolithicSparse VMDK | OVF | |
| qemu | qemu | QCOW2 | none | |
| virtualbox | virtualbox | VDI | VBOX | |
| vmware | vmware | 2GbMaxExtentSparse VMDK | VMX |