No description
Find a file
2026-05-06 16:45:51 -04:00
.devcontainer create devcontainer 2025-11-03 18:50:11 +00:00
ansible-collection@d36e5a0cf3 update repos 2026-02-09 15:14:04 +00:00
documentation@2e0a2680f4 update repos 2026-02-09 15:14:04 +00:00
setup@97651d5424 update heads 2025-11-03 18:49:49 +00:00
terraform-modules update repos 2026-02-09 15:14:04 +00:00
.gitignore update ignores 2025-11-03 18:50:00 +00:00
.gitmodules use https links 2025-11-19 03:49:17 +00:00
README.md added advanced Ansible customization docs and AD user provisioning section 2026-05-06 16:45:51 -04:00

CyberLab Dev

What is CyberLab Dev?

CyberLab Dev is a tool that allows professors and educators to automatically build cybersecurity lab environments for their students. Instead of spending hours manually setting up each lab machine before every class or semester, CyberLab Dev handles the entire process automatically: creating the virtual machines, configuring the network, and installing the lab software. When the semester is over, tearing everything down is equally simple.

CyberLab Dev is able to set up the following lab environments:

  • XSS Flask --- (Cross-Site Scripting attacks against a web application)
  • Command Injection (PHP) --- (Command injection attacks against a PHP web application)
  • Command Injection (.NET) --- (Command injection attacks against a .NET web application)
  • Banking App --- (Attacking a realistic vulnerable banking application)
  • WordPress --- (Web application attacks against a WordPress site)
  • Windows Domain Controller --- (Active Directory and Windows domain environments)
  • DHCP Server --- (Windows networking and DHCP configuration)
  • Certificate Service --- (Windows certificate authority and PKI)
  • Redhill --- (A simulation of the infrastructure of a small fictional town, in progress)

Time

Plan for approximately 23 hours to complete the full setup from scratch for the first time. Once set up, deploying a new lab for students takes under 15 minutes.

Technical comfort level

This guide assumes you are comfortable using a computer but have no prior experience with servers, Linux, or virtualization. Every step is explained in plain language. You will use a terminal (command line) for some steps — this guide will tell you exactly what to type.


The 5 Phases Explained

The setup process happens in five phases, each building on the last:

Phase 1: Install Proxmox

Proxmox is the foundation. It turns your dedicated machine into a server capable of running multiple virtual computers simultaneously. You install it once and largely leave it alone after that.

Phase 2: Create an Isolated Network

Before deploying any lab machines, you create an isolated private network that keeps the vulnerable lab machines completely separated from your real campus or office network.

Phase 3: Create the Windows VM Template

You create a Windows Server "master copy" — a template that gets cloned every time a new lab machine is needed, so you never have to install Windows from scratch again.

Phase 4: Deploy Labs Automatically with Terraform

Terraform is the automation tool. You describe what lab you want in a simple configuration file, run one command, and Terraform handles everything: cloning the template, booting the machine, and installing the lab software automatically.

Phase 5: Manual Deployment with Ansible (Optional)

For users who want more direct control, lab software can also be installed manually on existing machines using Ansible directly. This is an advanced option and most users will not need it.


Phase 1: Installing Proxmox

What is Proxmox?

Proxmox is the foundation that everything else in this guide builds on. You can think of it as software that turns a physical computer into a host that can run many smaller "virtual" computers inside it simultaneously. Each of those virtual machines can be its own isolated lab environment for students, with its own operating system, network, and software, all hosted by that single Proxmox setup.

Before students can use a cybersecurity lab, Proxmox needs to be installed and running on a dedicated machine. This is typically done once, and then left alone.

[ + ] Note: This guide assumes you are installing Proxmox on a dedicated physical machine (a server or desktop). If you do not have a physical machine that can be wiped and dedicated solely to Proxmox and are instead setting up a test environment inside a virtual machine, the steps are the same, but performance will be limited.

What you will need:

  • A computer dedicated to running Proxmox (it will be wiped during installation)
  • The latest Proxmox ISO file, downloaded from https://www.proxmox.com/en/downloads/proxmox-virtual-environment/iso
  • A USB drive (at least 2 GB) to boot the installer
    • OR access to virtualization software instead
  • A place to store credentials (you don't want to forget them!)

Step 1: Boot the installer

Create a bootable USB from the ISO you downloaded (tools like Balena Etcher or Rufus work well for this), then boot your machine from it. You will be presented with a menu — select the first option, "Install Proxmox VE", and press Enter.

Step 2: Accept the license and select your disk

Accept the end user license agreement, then select the disk you want to install Proxmox on.

⚠️ Warning: the selected disk will be completely erased. ⚠️

On a dedicated machine or virtual machine, there is typically only one disk to choose from.

Step 3: Set your password and email

Choose a strong password for the root account. This is the administrator account for your entire Proxmox server — write it down and store it somewhere safe. You will need it every time you log in. Enter an email address as well (this is used for system alerts).

Step 4: Configure the management network

This screen configures how you will reach your Proxmox server over the network. In most cases, the installer will automatically detect the correct values and you can leave them as-is. Here is what each field means:

Field                --- Purpose                                            --- What should you do
----------------------------------------------------------------------------------------------------------------------
Management Interface --- The network card Proxmox will use                  --- Leave as the only available option
Hostname             --- A name for this server                             --- Set to anything (ex: proxmox.lab)
IP Address           --- The address you'll use to reach the web interface  --- Write this down. Leave as auto-detected
Gateway              --- Your network's router address                      --- Leave as auto-detected
DNS Server           --- Used to resolve website names                      --- Leave as auto-detected

Step 5: Confirm and install

Review the summary screen and click Install. The process takes a few minutes. When it finishes, the machine will reboot and display a message in the terminal showing your IP address.

Step 6: Log into the web interface

On any computer on the same network, open a web browser and navigate to:

https://[YOUR-IP-ADDRESS]:8006

For example: https://192.168.122.38:8006

Your browser will show a security warning. This is expected! Proxmox uses a self-signed certificate that browsers don't trust by default. Click Advanced and then Accept the Risk and Continue (the exact wording varies by browser).

Log in with:

  • Username: root
  • Password: the password you set and wrote down

You should now see the Proxmox dashboard. Phase 1 complete!


Phase 2: Creating an Isolated Network

Why does this matter?

This step creates a private, sealed-off network inside Proxmox that your lab virtual machines will live on. Without it, any intentionally vulnerable machine you deploy for students would be connected to your real campus or office network, which is a serious security risk. The isolated network acts like a walled sandbox: machines inside it can reach the internet through a controlled gateway (called NAT), but they are invisible and unreachable from the outside.

⚠️ This step is not optional. Skipping it means your lab machines will be exposed on your real network. Always complete this before creating any virtual machines. ⚠️

Step 1: Create a Zone

A Zone defines the isolated network boundary. There are many different technologies that can be used for separation such as Simple, VLAN, QinQ, VXLAN, or EVPN. This guide will not get into the specifics of each technology. This guide will be using the Simple technology, which is a simple isolated bridge. This will be sufficient for single node deployments. For multi-node deployments, you should contact your cluster admin for further guidance.

  1. Log into the Proxmox web UI and click Datacenter in the left panel.
  2. Expand the SDN section and click Zones.
  3. Click the Add button at the top of the screen and select Simple from the menu.
  4. In the form that appears, fill in the ID field with a name for your network. Any name will do.
  5. Look for the Advanced checkbox in the bottom right of the form and click it to reveal additional options. Verify that Automatic DHCP is unchecked. It should be off by default, but it's worth confirming. This is important because the Windows machines in this lab manage their own IP addresses internally, and conflicts can arise from Proxmox also trying to assign addresses.
  6. Click the blue Add button.

Step 2: Create a VNet

A VNet (Virtual Network) is the actual network that your virtual machines will connect to. They are used to segment zones into different networks. This example will only be creating a zone with a single VNet.

  1. Still under SDN, click the VNets tab.
  2. Click the Create button.
  3. Give it a Name. Anything works.
  4. Under Zone, select the zone you just created in Step 1.
  5. Click the blue Create button.

Step 3: Create a Subnet

Subnets specify what IP ranges are allowed to be used on a virtual network (VNet).

  1. Still in the VNets tab, you will see two panels. On the right side, find the Subnets panel.
  2. Click Create.
  3. Fill in the Subnet option with an IP range in CIDR format.
  4. Select a Gateway that is the first address in your CIDR range.
  5. Check the SNAT checkbox.
  6. Click the blue Create button.

[ + ] Note: If you are unsure of what options to select for the Subnet, here are some sensible defaults that are unlikely to conflict with any existing networks:

Subnet:  172.16.11.0/24
Gateway: 172.16.11.1

Step 4: Apply the Changes

SDN changes in Proxmox are not active until you explicitly apply them.

  1. Click the SDN tab directly (not any of the sub-items beneath it).
  2. Click the Apply button in the top left of the window.

Your isolated network is now active and ready for virtual machines to connect to it. Phase 2 complete!


Phase 3: Setting up the Windows VM Template

What is a VM template and why do we need one?

A template is a blueprint copy of a virtual machine. Instead of installing Windows from scratch every time a new lab machine is needed, Proxmox can clone the template in seconds. You only have to go through the Windows installation process once, and everything after that will be automated.

What you will need before starting:

A Windows Server ISO downloaded from Microsoft's evaluation center. The following versions are supported:

[ + ] Note: These are free evaluation copies valid for 180 days, meaning no license purchase is needed for a lab environment. Do not use a standard Windows 10 or Windows 11 ISO — those versions do not support the server features this project deploys.

[ + ] Note: These drivers are required to allow Windows to communicate effectively with the virtual hardware Proxmox provides.

Step 1: Upload the ISOs to Proxmox

  1. Log into the Proxmox web UI.
  2. In the left panel, click local storage under your node name.
  3. Click the ISO Images tab.
  4. Click Upload and upload your Windows Server ISO.
  5. Repeat and upload your VirtIO ISO.

Both files should now appear in the ISO Images list.

Step 2: Create the VM

  1. Click the blue Create VM button in the top right of the screen.

General tab:

  • Node: Leave as your node name
  • VM ID: A number will be auto-assigned (likely 100). Write this number down — you will need it later
  • Name: Set this to something of your choosing (ex: windows-server-template)
  • Everything else: leave at defaults
  • Click Next

OS tab:

  • ISO Image: Select your Windows Server ISO
  • Guest OS Type: Select Microsoft Windows
  • Version: Leave as the value Proxmox pre-fills — it will show something like 11/2022/2025 which covers modern Windows Server versions
  • Check the Add additional drive for VirtIO drivers checkbox and select your VirtIO ISO in the dropdown that appears
  • Click Next

System tab:

[ + ] Note: When you selected Microsoft Windows on the OS tab, Proxmox automatically pre-filled the recommended settings for Windows on this page. The values may look unfamiliar but they are correct — do not change them to the "Default" options in the dropdowns, as those defaults are intended for Linux.

  • Qemu Agent: Check this box — this lets Proxmox communicate with the VM after it's running, which the automation tools rely on later
  • Add EFI Disk: Check this and select local-lvm as the storage
  • Add TPM: Check this and select local-lvm as the storage
  • Everything else: leave as pre-filled
  • Click Next

Disks tab:

  • Storage: Leave as local-lvm
  • Disk Size: Change to 64 GiB
  • Everything else: leave at defaults
  • Click Next

CPU tab:

  • Cores: Change from 1 to 2
  • Everything else: leave at defaults
  • Click Next

Memory tab:

  • Change from 4096 to 8192 MiB
  • Click Next

Network tab:

  • Bridge: Confirm this is set to your isolated VNet (e.g. cyber). Do not leave it on vmbr0 — that is your real network
  • Everything else: leave at defaults
  • Click Next

Confirmation tab:

  • Review your settings
  • Make sure Start after created is NOT checked
  • Click Finish

Step 3: Boot and Install Windows

  1. Click on your new VM in the left panel.
  2. Click Start in the top right, then click Console to open the VM's screen.
  3. When you see a prompt to press any key to boot from CD, press a key quickly.
  4. If a boot menu appears, select the UEFI QEMU DVD ROM option that corresponds to your Windows ISO. If you're unsure which one, try the first DVD option — if it doesn't work, restart and try the other.
  5. Windows Setup will load. Leave the language and keyboard settings at their defaults and click Next, then Install Now.
  6. When asked which version to install, select Windows Server 2022 Datacenter (Desktop Experience). The Desktop Experience version gives you the standard Windows graphical interface — without it you only get a command line.
  7. Accept the license agreement and select Custom: Install Microsoft Windows only (advanced).

Step 4: Load the VirtIO Storage Driver

On the drive selection screen you will see no drives listed. This is expected — Windows cannot see the virtual disk yet because it needs a driver first.

  1. Click Load Driver, then click Browse.
  2. Find the VirtIO CD drive in the list (it will be labeled something like virtio-win-0.1.xxx).
  3. Navigate to amd64win10. Despite the folder being named win10, these drivers are correct for Windows Server 2022 as well.
  4. Click OK. Windows will scan and find a driver called Red Hat VirtIO SCSI pass-through controller.
  5. Select it and click Next.

Your virtual disk will now appear. Select it and click Next to begin the installation.

Step 5: Complete the Windows Installation

Windows will copy files and reboot automatically one or more times. This takes approximately 510 minutes. When it finishes you will land on a Customize Settings screen asking you to set a password for the Administrator account.

⚠️ Important: Do not fill in the password and click Finish normally. Instead, press Ctrl + Shift + F3 on your keyboard. This enters a special mode called Audit Mode, which prepares the machine to be used as a reusable template.

After pressing Ctrl + Shift + F3, the machine will reboot and land on a Windows desktop automatically logged in as Administrator. You may see a small Sysprep dialog box appear — close it. You are now ready to proceed to Step 6.

Step 6: Run the Setup Script and Convert to a Template

First, install the VirtIO network drivers:

  1. Open File Explorer inside the Windows VM.
  2. Find the VirtIO CD drive in the left panel and open it.
  3. Scroll to the bottom and find the file called virtio-win-gt-x64.msi — double click it and run the installer with default options. Do not run the x86 version.
  4. Once the installer finishes, your network adapter will be active and the VM will have internet access.

Next, run the setup script:

  1. Open PowerShell as Administrator — right-click the Start menu and select Windows PowerShell (Run as Administrator).
  2. Paste the following command and press Enter:
$request = (Invoke-WebRequest -Uri "https://cyberlab.erwine.dev/_static/scripts/WindowsSetup.ps1").Content
$script = [System.Text.Encoding]::UTF8.GetString($request)
Invoke-Expression $script

[ + ] This is what the script does:

  • Installs PowerShell 7
  • Installs and configures OpenSSH
  • Installs Cloudbase-Init
  • Runs Sysprep
  1. The script will run for several minutes. You will see output as each component installs. When you see a Sysprep is working popup appear, the process is nearly complete.
  2. The VM will shut itself down automatically. Do not restart it.
  3. In the Proxmox left panel, right-click your VM, then select Convert to Template and confirm.

The icon next to the VM will change to indicate it is now a template. You will also notice the Start button is no longer available — templates cannot be booted directly.

Phase 3 is now complete. Your Windows Server template is ready to be cloned!

[ + ] Note for nested/test environments only: If you are running Proxmox inside a virtual machine for testing purposes rather than on dedicated hardware, you may find that the isolated network does not have internet access. This is a limitation of nested virtualization and will not affect a real bare metal deployment. As a workaround for testing, you can temporarily switch the VM's network bridge to vmbr0 in the Hardware settings before running the script, then switch it back to your isolated VNet before converting to a template.


Phase 4: Deploying a Lab with Terraform

What is Terraform and what does it do here?

Terraform is the tool that makes lab deployment automatic. Instead of manually creating a virtual machine, configuring its network, and installing software, you describe what you want in a configuration file and Terraform handles everything else. For a professor, this means deploying an entire cybersecurity lab environment takes a single command rather than hours of manual setup.

When you run Terraform in this project, these four things happen automatically in sequence:

  1. The VM is created — Terraform tells Proxmox to clone your Windows Server template and boot a new machine
  2. The VM is configured — Cloudbase-Init runs automatically inside the new VM on first boot, setting the hostname, expanding the disk, and applying network settings
  3. Terraform waits — a built-in 3 minute pause gives Cloudbase-Init time to finish before the next step
  4. The lab software is installed — Ansible connects to the new VM over SSH and installs whatever cybersecurity lab scenario you specified

Available lab scenarios:

This project includes the following ready-to-deploy lab scenarios. Each one installs a different vulnerable application or environment for students to practice on:

Role Name                                       --- Description
---------------------------------------------------------------------------------------------------------------------
mason3263.cyberlab.xss_flask                    --- A web application vulnerable to Cross-Site Scripting (XSS)
mason3263.cyberlab.command_injection_php        --- A web application vulnerable to command injection via PHP
mason3263.cyberlab.command_injection_dotnet_1   --- A web application vulnerable to command injection via .NET
mason3263.cyberlab.banking_app_node             --- A vulnerable banking application built with Node.js
mason3263.cyberlab.wordpress                    --- A WordPress installation
mason3263.cyberlab.apache_install               --- A basic Apache web server
mason3263.cyberlab.nginx_install                --- A basic Nginx web server
mason3263.cyberlab.dhcp_server                  --- A Windows DHCP server
mason3263.cyberlab.domain_controller            --- A Windows Active Directory domain controller
mason3263.cyberlab.redhill                      --- A multi-machine lab simulating the infrastructure of a small
                                                    fictional town (Redhill, Ohio). Note: work in progress.

[ + ] Note for professors: The vulnerable lab scenarios (XSS, command injection, banking app) are intentionally insecure — that is the point. This is why the isolated network from Phase 2 is mandatory. These machines should never be connected to a real network.

Prerequisites

Before running Terraform, make sure the following are in place. These are one-time setup steps.

[ + ] Note: Terraform and Ansible are run from a management machine of your choosing — this can be your everyday laptop/desktop, or a dedicated VM you create inside Proxmox itself. It does not run on the Proxmox server directly. The only requirement is that the machine you choose can reach your Proxmox server over the network.

1. Install Terraform

Check if Terraform is already installed:

terraform --version

If it is not installed, follow the official instructions here.

2. Install Ansible

sudo apt install ansible-core

3. Clone the CyberLab repository

If you have not already done so, clone the cyberlab-dev repository to your machine. This gives you the Terraform modules and Ansible collection needed to run deployments:

git clone https://git.erwine.dev/osu-cyberlab/cyberlab-dev.git

This will create a folder called cyberlab-dev in your current directory. Remember where you put it — you will need the path in the steps that follow.

4. Install the CyberLab Ansible collection

This installs all the lab scenario roles onto your machine:

ansible-galaxy collection install [PATH-TO-REPO]/ansible-collection/

Replace [PATH-TO-REPO] with the path to wherever you cloned the cyberlab-dev repository on your machine. For example, if you cloned it to your home folder:

ansible-galaxy collection install ~/cyberlab-dev/ansible-collection/

5. Generate an SSH key

Terraform uses SSH to connect to newly created VMs. If you don't already have an SSH key, generate one with:

ssh-keygen -t ed25519 -C "cyberlab"

Press Enter at all prompts to accept defaults and leave the passphrase empty. Your public key will be saved at ~/.ssh/id_ed25519.pub. View it with:

cat ~/.ssh/id_ed25519.pub

Copy the entire output — you will need it in your configuration file.

6. Create a Proxmox API token

Terraform needs to authenticate with Proxmox. Rather than using your root password directly, you'll create a dedicated API token:

  1. Log into the Proxmox web UI
  2. Click Datacenter in the left panel
  3. Expand Permissions and click API Tokens
  4. Click Add
  5. Set User to root@pam and give the token any Token ID you like (e.g. terraform)
  6. Uncheck the Privilege Separation checkbox
  7. Click Add

⚠️ Important: The token secret is shown only once. Copy it immediately and store it somewhere safe, as you cannot retrieve it again. ⚠️

Your API token will look like this:

root@pam!terraform=ff3996f7-3a53-4f8f-ae23-24af703b1269

Step 1: Set up your deployment folder

Create a new folder for your lab deployment and navigate into it:

mkdir my-first-lab
cd my-first-lab

Step 2: Create your configuration file

Create a file called main.tf and paste in the following template, filling in your own values where indicated:

terraform {
  required_providers {
    proxmox = {
      source  = "bpg/proxmox"
      version = "0.85.1"
    }
    ansible = {
      source  = "ansible/ansible"
      version = "~> 1.3.0"
    }
  }
}

provider "proxmox" {
  endpoint  = "https://[YOUR-PROXMOX-IP]:8006/"
  api_token = "[YOUR-API-TOKEN]"
  insecure  = true
}

module "xss_lab" {
  source = "[PATH-TO-REPO]/cyberlab-dev/terraform-modules/terraform-proxmox-vm"

  target_node = "[YOUR-NODE-NAME]"
  vm_template = [YOUR-TEMPLATE-VM-ID]
  hostname    = "xss-lab-01"
  os          = "Windows"

  username = "Administrator"
  password = "YourPasswordHere"

  public_ssh_keys = [
    "[YOUR-SSH-PUBLIC-KEY]"
  ]

  network_config = {
    ip   = "172.16.11.10"
    gw   = "172.16.11.1"
    cidr = "24"
  }

  ansible_roles = {
    "mason3263.cyberlab.xss_flask" = ""
  }
}

Here is what each placeholder means and where to find it:

Placeholder              --- What to put here
---------------------------------------------------------------------------------------------------------------------
YOUR-PROXMOX-IP          --- The IP address you use to reach your Proxmox web UI (e.g. 192.168.1.100)
YOUR-API-TOKEN           --- The token you created in Prerequisite 6 (e.g. root@pam!terraform=...)
PATH-TO-REPO             --- The path to the cloned cyberlab-dev repository on your machine
YOUR-NODE-NAME           --- The name of your Proxmox node, visible in the left panel of the web UI
YOUR-TEMPLATE-VM-ID      --- The VM ID number you wrote down when creating the template (e.g. 100)
YOUR-SSH-PUBLIC-KEY      --- The full output of: cat ~/.ssh/id_ed25519.pub

To deploy a different lab scenario, change the ansible_roles value. For example, to deploy the command injection lab instead:

  ansible_roles = {
    "mason3263.cyberlab.command_injection_php" = ""
  }

[ + ] Security note: Your API token and password are sensitive credentials. Never commit this file to a public git repository or share it with others.

Step 3: Initialize Terraform

This downloads all required tools. Only needs to be done once per folder:

terraform init

Step 4: Preview the deployment

This shows you exactly what Terraform will create without actually doing anything. Always run this first:

terraform plan

Review the output and confirm it matches what you expect: the VM name, template ID, IP address, and lab scenario should all be correct.

Step 5: Run the deployment

terraform apply

Type yes when prompted to confirm. The deployment will take several minutes. Here is what you will see:

  • Terraform creates the playbook file immediately
  • The VM creation begins (this takes 115 minutes depending on your hardware)
  • A 3 minute countdown begins while Cloudbase-Init sets up the VM
  • Ansible connects and installs the lab software

When complete you will see:

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Your lab VM is now running and ready for students!

Step 6: Tearing down a lab

When you are done with a lab and want to remove it, run:

terraform destroy

Type yes to confirm. Terraform will delete the VM from Proxmox. This is useful at the end of a semester or when you want to start fresh.

[ + ] Note: This only deletes the cloned lab VM. Your original template is not affected and can be used to deploy new labs at any time.


Phase 5: Manual Deployment with Ansible (Optional)

This may be useful as an alternative to Terraform when:

  • You want to reconfigure a VM that already exists without recreating it
  • You are managing just one or two machines and don't need full automation
  • You want more direct control over exactly what gets installed and when
  • Something in the Terraform setup isn't working in your environment
  • You want to deploy to a different environment (e.g. AWS) for which Terraform scripts are not yet available

[ + ] Note: The Ansible deployment path requires that base virtual machines already exist and are running before Ansible can configure them. This is different from the Terraform path, which creates the VMs automatically as part of the deployment. When using Ansible directly, you must first manually clone your Windows template in Proxmox and boot the machine before running any Ansible scripts against it.

Prerequisites

  • A VM already created in Proxmox and running Windows Server — either cloned from your template manually, or one left over from a previous deployment
  • The VM's IP address
  • SSH access to the VM (the setup script from Phase 3 must have been run on it)
  • Ansible and the CyberLab collection installed (covered in Phase 4 Prerequisites)

How the manual path works

Instead of Terraform, you run Ansible directly using a playbook called deploy.yaml. This playbook knows about every available lab scenario. You tell it which scenarios to deploy and where by writing an inventory file, which is a simple text file that lists your VMs and what role each one should play. If any are defined in this inventory, they are installed. Anything not defined gets skipped entirely.

Step 1: Create your deployment folder

Create a new folder for your deployment and navigate into it:

mkdir my-manual-lab
cd my-manual-lab

Step 2: Create your inventory file

Create a file called inventory.yaml and fill it in based on which lab scenarios you want to deploy. Here is a complete example deploying just the XSS Flask lab:

all:
  hosts:
    xss_flask:
      ansible_host: 172.16.11.10
      ansible_user: Administrator
      ansible_password: YourPasswordHere
      ansible_shell_type: powershell
      ansible_connection: ssh

To deploy multiple scenarios on different machines, add more hosts:

all:
  hosts:
    xss_flask:
      ansible_host: 172.16.11.10
      ansible_user: Administrator
      ansible_password: YourPasswordHere
      ansible_shell_type: powershell
      ansible_connection: ssh

    command_injection_php:
      ansible_host: 172.16.11.11
      ansible_user: Administrator
      ansible_password: YourPasswordHere
      ansible_shell_type: powershell
      ansible_connection: ssh

    domain_controller:
      ansible_host: 172.16.11.12
      ansible_user: Administrator
      ansible_password: YourPasswordHere
      ansible_shell_type: powershell
      ansible_connection: ssh

⚠️ Important: The host names (xss_flask, command_injection_php, domain_controller, etc.) must be spelled exactly as shown. ⚠️

Here is the full list of valid host names:

  • xss_flask
  • command_injection_php
  • command_injection_dotnet_1
  • banking_app_node
  • wordpress
  • redhill
  • domain_controller
  • dhcp_server
  • certificate_service

Step 3: Run the deployment

Run the following command, replacing [PATH-TO-REPO] with the actual location of your cyberlab-dev folder (the same path used in Phase 4):

ansible-playbook \
  -i inventory.yaml \
  [PATH-TO-REPO]/ansible-collection/playbooks/deploy.yaml

Ansible will connect to each VM defined in your inventory and install the corresponding lab software. You will see output for each task as it runs. A successful completion looks like:

PLAY RECAP *********************************************************************
xss_flask    : ok=5    changed=3    unreachable=0    failed=0

If you see unreachable=1 it means Ansible couldn't connect to that VM over SSH. You should check that the VM is running and that the IP address in your inventory is correct.

[Advanced] Customizing Ansible Roles

Each lab scenario comes with sensible defaults that work out of the box. However, most roles expose configuration options that allow you to tailor the lab to your specific needs. Customization is done by passing variables into the role, either through your Terraform main.tf file or your Ansible inventory.yaml file depending on which deployment path you are using. To override a value, you provide it when calling the role. You only need to specify the values you want to change and anything you leave out will use its default.

Customizing via Terraform (Phase 4)

In your main.tf, pass variables through the ansible_roles block like this:

ansible_roles = {
  "mason3263.cyberlab.xss_flask" = <<-EOT
    xss_flask:
      name: "my-xss-lab"
      backend:
        PORT: 8080
        SECRET_KEY: "mysecretkey"
  EOT
}

Customizing via Ansible inventory (Phase 5)

In your inventory.yaml, add a vars block under the relevant host:

all:
  hosts:
    xss_flask:
      ansible_host: 172.16.11.10
      ansible_user: Administrator
      ansible_password: YourPasswordHere
      ansible_shell_type: powershell
      ansible_connection: ssh
      vars:
        xss_flask:
          backend:
            PORT: 8080
            SECRET_KEY: "mysecretkey"

Below are the available customization options by role:


XSS Flask

A cross-site scripting vulnerability lab running on Flask.

Option                                   --- Default          --- Description
------------------------------------------------------------------------------------------
name                                     --- xss-flask        --- The name of the application instance
url                                      --- _                --- The URL the app will be served at
root                                     --- /srv/xss-flask   --- The directory the app is installed in
backend.PORT                             --- 3000             --- The port the app listens on
backend.SECRET_KEY                       --- (random)         --- Secret key for session security (auto-generated)
backend.JWT_ACCESS_TOKEN_EXPIRES_DAYS    --- 1                --- How many days login tokens stay valid
backend.CORS_ORIGIN                      --- *                --- Which origins are allowed to make requests

Banking App

A vulnerable banking application built with Node.js.

Option           --- Default          --- Description
------------------------------------------------------------------------------------------
name             --- banking-app      --- The name of the application instance
root             --- /srv/bank-app    --- The directory the app is installed in
backend.PORT     --- 5000             --- The port the app listens on
backend.DB_PATH  --- ./database.db    --- Path to the SQLite database file

Command Injection (PHP)

A web application vulnerable to command injection via PHP.

Option           --- Default                      --- Description
------------------------------------------------------------------------------------------
name             --- cmd-inj-php                  --- The name of the application instance
url              --- _                            --- The URL the app will be served at
root             --- /srv/command-injection-php   --- The directory the app is installed in
proxy_backend    --- nginx                        --- The web server used to proxy the app

Command Injection (.NET)

A web application vulnerable to command injection via .NET.

Option           --- Default      --- Description
------------------------------------------------------------------------------------------
root             --- /srv/dotnet  --- The directory the app is installed in
backend.port     --- 5000         --- The port the app listens on
backend.location --- /api         --- The API endpoint location

Apache (Install)

Installs the Apache web server.

Option        --- Default  --- Description
------------------------------------------------------------------------------------------
install_php   --- true     --- Whether to install PHP alongside Apache

Apache (Config)

Configures an existing Apache installation.

Option        --- Default                        --- Description
------------------------------------------------------------------------------------------
server_name   --- (server's IP address)          --- The server name Apache responds to
root          --- (none)                         --- The document root directory
port          --- 80                             --- The port Apache listens on
php.enabled   --- false                          --- Whether to enable PHP processing
modules       --- (none)                         --- Additional Apache modules to enable

Nginx (Install)

Installs the Nginx web server. Uses system defaults and does not require additional configuration for basic use.


Nginx (Config)

Configures an existing Nginx installation with virtual host settings.

Option                    --- Default    --- Description
------------------------------------------------------------------------------------------
name                      --- default    --- The name of this virtual host configuration
listeners                 --- [80]       --- List of ports Nginx listens on
server_name               --- _          --- The server name this config responds to
locations.proxy           --- []         --- List of reverse proxy location blocks
locations.static          --- []         --- List of static file location blocks
locations.php             --- []         --- List of PHP location blocks

WordPress

WordPress uses all default configuration and does not currently expose customization options. It will be installed with standard settings automatically.


Domain Controller

A Windows Active Directory domain controller.

Option                        --- Default           --- Description
------------------------------------------------------------------------------------------
cyberlab_ad.domain            --- example.internal  --- The fully qualified domain name (e.g. myschool.internal)
cyberlab_ad.netbios_name      --- Example           --- The short NetBIOS name for the domain (e.g. MYSCHOOL)
cyberlab_ad.username          --- Administrator     --- The domain administrator username
cyberlab_ad.password          --- Password123       --- The domain administrator password
domain_controller.hostname    --- dc1               --- Hostname for the domain controller
domain_controller.ntp_server  --- time.windows.com  --- Time server used to keep the domain in sync

[ + ] Note: For a real classroom deployment you will almost certainly want to change cyberlab_ad.domain and cyberlab_ad.netbios_name from their defaults. Using example.internal is fine for testing but a named domain makes the lab feel more realistic for students.

⚠️ Important: Change cyberlab_ad.password from its default value of Password123 before deploying in any real environment. ⚠️


DHCP Server

A Windows DHCP server. Integrates with the domain controller when one is present.

Option                        --- Default          --- Description
------------------------------------------------------------------------------------------
dhcp_server.dhcp_range.start  --- 172.16.1.1       --- First IP address handed out to clients
dhcp_server.dhcp_range.stop   --- 172.16.1.254     --- Last IP address handed out to clients
dhcp_server.subnet            --- 172.16.0.0/15    --- The network subnet in CIDR format
dhcp_server.router            --- 172.16.0.1       --- The default gateway given to clients
dhcp_server.dns               --- 172.16.0.2       --- The DNS server given to clients (usually the domain controller)

Certificate Service

A Windows certificate authority. Requires an existing domain controller.

Option                                      --- Default          --- Description
------------------------------------------------------------------------------------------
certificate_service.hostname                --- cert-svc         --- Hostname for the certificate server
certificate_service.ca.type                 --- EnterpriseRootCA --- The type of certificate authority to create
certificate_service.ca.generate.common_name --- (hostname)       --- The common name on the root certificate
certificate_service.ca.generate.hash_algo   --- SHA256           --- The hashing algorithm used for certificates
certificate_service.ca.generate.key_len     --- 4096             --- The key length for the root certificate
enrollment_policy_service.enabled           --- true             --- Whether to enable the enrollment policy service
enrollment_service.enabled                  --- true             --- Whether to enable the enrollment service

Windows Setup

Prepares a Windows machine to join an existing Active Directory domain.

Option                     --- Default                      --- Description
------------------------------------------------------------------------------------------
cyberlab_ad.domain         --- example.com                  --- The domain to join
cyberlab_ad.username       --- administrator                --- The domain administrator username
windows_setup.ad.enabled   --- true                         --- Whether to join the machine to the domain
windows_setup.ad.ou_path   --- (default AD path)            --- The Organizational Unit to place the machine in
windows_setup.ad.hostname  --- (current hostname)           --- Override the hostname before joining the domain

Redhill

A multi-machine lab simulating the infrastructure of a small fictional town (Redhill, Ohio). Redhill deploys multiple websites representing different town services.

Option                                --- Default                                     --- Description
----------------------------------------------------------------------------------------------------------------
install_dir                           --- /srv/redhill                                --- The install directory
url                                   --- http://(server IP)                          --- The base URL
archive_urls.redhill                  --- (cyberlab.erwine.dev/Redhill.tar.gz)        --- Main Redhill site archive
archive_urls.redhillschools           --- (cyberlab.erwine.dev/Redhill-Schools.tar.gz)--- Schools website archive
archive_urls.redhillemergencyservices --- (cyberlab.erwine.dev/...)                   --- Emergency services website
archive_urls.redhilllibrary           --- (cyberlab.erwine.dev/Redhill-Library.tar.gz)--- Library website archive
archive_urls.redhillcommunityservices --- (cyberlab.erwine.dev/...)                   --- Community services website

[ + ] Note: Redhill is actively being developed and new services are added over time. The default archive URLs always point to the latest available version.


Node (Generic)

A generic role for deploying Node.js applications from a git repository. Useful for custom lab scenarios.

Option                  --- Default                     --- Description
--------------------------------------------------------------------------------------------------------------
name                    --- Node-App                    --- The name of the application instance
install_dir             --- /srv/node                   --- The directory the app is installed in
git.url                 --- (none)                      --- The git repository URL to clone
git.version             --- HEAD                        --- The branch or tag to check out
git.subdirectory        --- (none)                      --- A subdirectory within the repo to use
env.file                --- .env                        --- The name of the environment file
env.contents            --- (none)                      --- Key-value pairs to write into the environment file
setup_script            --- scripts/setup.bash          --- Script to run once after cloning
run_script              --- scripts/run.bash            --- Script to run the application

Flask (Generic)

A generic role for deploying Python Flask applications from a git repository. Useful for custom lab scenarios.

Option           --- Default                            --- Description
------------------------------------------------------------------------------------------
name             --- flask-app                          --- The name of the application instance
url              --- _                                  --- The URL the app will be served at
proxy_url        --- http://127.0.0.1:3000              --- The internal URL Nginx proxies to
root             --- /srv/flask                         --- The directory the app is installed in
git.url          --- (none)                             --- The git repository URL to clone
git.version      --- HEAD                               --- The branch or tag to check out
git.subdirectory --- (none)                             --- A subdirectory within the repo to use
env.file         --- .env                               --- The name of the environment file
env.contents     --- (none)                             --- Key-value pairs to write into the environment file
setup_command    --- scripts/setup.bash                 --- Script to run once after cloning
run_command      --- scripts/run.bash                   --- Script to run the application

.NET (Generic)

A generic role for deploying .NET applications. Useful for custom lab scenarios.

Option                  --- Default                    --- Description
------------------------------------------------------------------------------------------
root                    --- /srv/dotnet                --- The directory the app is installed in
systemd.name            --- dotnet                     --- The name of the systemd service
systemd.run_command     --- (none)                     --- The command used to start the application
apt.packages            --- aspnetcore-runtime-9.0     --- The .NET runtime package to install
archive.url             --- (none)                     --- URL to download the application archive from
archive.path            --- (none)                     --- Path to extract the archive to
env.name                --- .env                       --- The name of the environment file
env.contents            --- (none)                     --- Key-value pairs to write into the environment file

[Optional] Active Directory User Provisioning

If you have deployed a domain controller using the domain_controller role, you can automatically create Active Directory user accounts from an Excel spreadsheet. This is useful for setting up a realistic AD environment with a population of users for students to interact with or attack.

[ + ] Note: These users are not student accounts; they are the simulated users that exist inside the lab environment. Students will interact with or attempt to compromise these accounts as part of their exercises.

Example scenario: Sensitive data in AD attributes

Active Directory allows administrators to store arbitrary attributes on user accounts. In some real organizations, administrators mistakenly store sensitive information (such as a user's initial password or a password hint) in fields like description or info, assuming these fields are only visible to administrators. In reality, standard users and even guest users can often query these fields via LDAP.

You can simulate this in your lab by adding a description column to your spreadsheet containing a password hint or the user's actual password. Students can then use LDAP enumeration tools to discover these values, which is a realistic attack scenario.

Example scenario: AS-REP Roasting

⚠️ Note: Currently marked as in development. ⚠️

AS-REP Roasting is an attack against Active Directory accounts that have Kerberos pre-authentication disabled. When pre-authentication is disabled on an account, an attacker can request an encrypted ticket for that user without knowing their password, and then attempt to crack the ticket offline. Combined with a weak password, this gives students a realistic path into an AD environment.

To set this up once supported: create a user in your spreadsheet with a weak password and set the dont_require_preauth attribute to true. Students can then use tools such as impacket-GetNPUsers to perform the AS-REP Roasting attack.

⚠️ Note: is this the correct attribute name and format required in the spreadsheet? ⚠️

Step 1: Install the required Python dependencies

From your management machine, run:

ansible-playbook \
  -e "venv_path=" \
  [PATH-TO-REPO]/ansible-collection/playbooks/ansible_setup.yaml

[ + ] Note: This only needs to be done once. It installs the Python libraries required for the Excel conversion script.

Step 2: Create your spreadsheet

Create an Excel file (.xlsx) with the following columns. The column headers must be spelled exactly as shown:

Column      --- Description                                  --- Example
------------------------------------------------------------------------------------------
firstname   --- User's first name                            --- Jane
lastname    --- User's last name                             --- Smith
username    --- User's login username                        --- jsmith
password    --- User's initial password                      --- Test123!
groups      --- AD groups to add them to (comma-separated)   --- Students, Lab Users

You can add additional columns beyond these five; they will be stored as extra attributes on the user account in Active Directory. For example, adding a description column allows you to simulate the scenario described above.

Step 3: Run the conversion and deployment

Run the following command, replacing the placeholders with your values:

ansible-playbook \
  -e "pwd=[PATH-TO-YOUR-SPREADSHEET-FOLDER]" \
  -e "excel_file=[YOUR-SPREADSHEET-FILENAME].xlsx" \
  [PATH-TO-REPO]/ansible-collection/playbooks/dc_setup.yaml

This will generate a users.yaml file in your spreadsheet folder and provision all users into Active Directory on your domain controller.

[ + ] Note: Re-running this command with an updated spreadsheet will update existing users and add new ones.