Skip to main content

Cave

cave is a Python-based automation toolkit for automated provisioning virtual infrastructure.
Define your virtual infrastructure using code, cave handles the rest.
Can be especially useful for more complex red-teaming training environments.

Cave is still a prototype, use with caution.
It is heavily worked on right now, stuff will change.

Features

  • Supports both Linux and Windows
  • Automated provisioning of virtual machines
  • Automated provisioning of networks
  • Automated configuration of network interfaces
  • Automated installation of ssh
  • Removal of provisioning artifacts like management interfaces for increased realism
  • Python API

Cave handles the creation of virtual machines and networks. It automates OS setup for Linux and Windows. It handles the setup of OpenSSH on the machines.

So after the provisioning, you are left with a virtual infrastructure consisting of networks and machines you defined, ready to be connected to. An obvious next step is to further configure the machines using IaC tools like Ansible or Chef.


Use Cases

  • use in conjunction with Ansible to build a full-fledged cyber range
  • quick and easy setup for testing environments
  • use for automated creation of virtual machines to test your code in

Example topology

example topology image


Getting Started

You will need a Linux machine as your Libvirt virtualisation host and a machine (can be the same host) on which the client is executed. You can use whatever distro you like, cave was tested and will be tested using Debian.

Installing the client

pip install cave-infra
from cave import Range, Interface

Install libvirt

  • Install Libvirt (Debian) apt install --no-install-recommends qemu-system libvirt-clients libvirt-daemon-system
  • Install qemu-img apt install qemu-utils
  • Install dnsmasq apt install dnsmasq
  • install software tpm and ovmf for windows 11/UEFI apt install swtpm stpm-tools ovmf

In case you face SElLnux issues, a quick-fix might be disabling apparmor/SELinux for Libvirt by setting "security_driver" to ["none"] in /etc/libvirt/qemu.conf. Then systemctl restart libvirtd

  • Setup routes to your cave host
    In order to allow traffic for communicating with the virtual infrastructure, you will need to setup routes. Take an ipv4 range that you will later use to make the machines within your deployment accessible to your network. The virtualisation host will act as a router/next hop for the virtual networks and machines.
    For an example, see example topology
  • Create ssh key for root user
  • Download images
    Download ISOs of the windows versions you will need, tested are: Windows 10, Windows 11, Windows-Server 16 and newer
    For the language only English-US is supported.
    If you need to use Windows 11/Any windows with UEFI, you need to make a small change to the iso to make it boot without user interaction https://serverfault.com/questions/353826/windows-boot-iso-file-without-press-any-key.
    Download cloud-init images of the Linux distributions you will use. Ubuntu https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img is tested.

Usage

See example for an example.

Setup

CON_URI = f"qemu+ssh://root@{HOST}/system"

conn = libvirt.open(CON_URI)
range = Range(conn, SSH_URI, TMP_CLOUD_INIT_DIR, SSH_PUB, USERNAME, PASSWORD)
range.nuke_libvirt()
range.add_pool(POOL_NAME,REMOTE_POOL_DIR)

Networks and Interfaces

mngt = range.add_management_network(name="mngmt", 
                         ipv4="10.10.0.1", # ipv4 the libvirt host gets inside the network, it then acts as gateway
                         ipv4_subnet="255.255.255.0") # subnet mask

n1 = range.add_network(name="network1", 
                       ipv4="", 
                       ipv4_subnet="", 
                       mode="") # mode, "open" if the libvirt host should route to and from the network

i1 = Interface(mac="", # leave empty 
               network=n1, # what network the interface is attached to
               ipv4="10.10.1.2", # ipv4 address of the interface
               prefix_length=24, # subnet mask network bist
               is_mngmt=False) # wether or not this is a management interface e.g. is connected to a management network, mngmt interfaces will be detatched in the cleanup phase

im = Interface(mac="", 
               network=mngt, 
               ipv4="10.10.0.2", 
               prefix_length=24, 
               is_mngmt=True) 

Virtual Machines

ubuntu_img = f"{REMOTE_IMAGES_DIR}/{os.path.basename(UBUNTU_IMAGE)}"
ld = range.add_linux_domain(name="linux01", # internal name
                            hostname="lin01", 
                            base_image_path=ubuntu_img, # absolute path to the cloud-init base image on the libvirt host
                            interfaces=[i1, im], # list of interfaces
                            graphics_passwd="pw", # vnc password
                            disk_volume_size_gb=8, # size of the main disk in GB
                            memory=1024, # ram
                            vcpus=2, # virtual vpu cores
                            graphics_port="6000", # port on which the vnc server listens
                            graphics_auto_port="no", # choose port automatically, no if graphics_port is set
                            graphics_address="0.0.0.0", # on which ip/interface the vnc server should listen
                            default_gateway="10.10.1.1", # the range-internal default gateway
                            dns_server="1.1.1.1", # the range internal dns server
                            management_default_gateway="10.10.0.1") # the default gateway for the management interface

Cleanup

# removes management interfaces from machines and removes management network
range.cleanup()

Metadata

Release files for cave-infra 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cave-infra 0.1.6
File Size Uploaded
cave_infra-0.1.6.tar.gz 37.9 kB Details

Release files / cave_infra-0.1.6.tar.gz

Download URL cave_infra-0.1.6.tar.gz
Size 37.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9b549cd7e86b1d8fa1ec9f24820a1c793693682c8bc2e7919df0ced97b725158
BLAKE2b-256 checksum
How to use checksums
00b388f13aae8e34b94f9a7ee6f42295cfc5d4499a853751780ed0a89ada7cd4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.1.6 This release

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page