Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Building Labs - A Basic Overview

Building a Lab network

The basics / @JonTheNiceGuy / @g7vri


  • Introduction
  • What is a Lab?
  • A basic lab
  • A note on networking
  • A little bit of config
  • Complicated labs
  • My lab!


  • Network Security Professional for > 10 years
  • Interest in Linux and Open Source

What is A Lab

For the purpose of this presentation

"A lab is an environment in which you can perform the same test twice and get the same results"

A Basic Lab

Virtual Machines

  • Virtual Devices
    • VM Snapshots
    • Clone VMs
    • OVA Files
    • Vagrant
  • Physical Devices
    • Appliances
    • Servers
    • Laptops

Note: VM Snapshot: Very fast, adds files to system per snapshot, can be cumulative Clone VMs: May be difficult to do depending on Hypervisor OVA files: Not platform independant, but can be massaged to work between VMWare, VirtualBox, ESXi, Hyper-V. Vagrant: My go-to system. Simple text files, pre-packaged "Box" files. Basically clones VMs from a known working state, and runs post-install customization.

A Basic Lab


  • Home Made
    • Shell Scripts
    • Powershell
    • Batch Files
  • Tools
    • Puppet
    • Chef
    • Ansible
    • Salt

A note on networking

  • You should learn some basic networking before creating labs.
    • Routing
    • Port Forwarding
  • Understand interface types
    • Bridged interfaces are like physically plugging in to your network.
    • NAT interfaces "Hide" behind your host IP address
    • Private networks are (typically!) inside your host machine

A little bit of config

  • Vagrant
    • -> Linux
    • -> Windows
    • -> Several Machines at once
  • Ansible
    • -> Create users

A little bit of config


mkdir Lab-A
cd Lab-A
vagrant init ubuntu/trusty64
vagrant up

Note: Remember that you need to create your vagrantfile in a new directory. The vagrantfile path is exposed to the VM in /vagrant or c:\vagrant

A little bit of config

Vagrant -> Linux

Vagrant.configure(2) do |config| = "ubuntu/trusty64"
  config.vm.synced_folder "/mnt", "/mnt/host"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
  config.vm.provision "shell", inline: <<-SHELL
    sudo apt-get update && sudo apt-get install -y sendemail
  config.vm.provision "shell", run: "always", inline: <<-SHELL
    /vagrant/RunProcess | /vagrant/sendemail 
    sudo shutdown -h now

Note: Here we define a standard box - This has been created on a public server, it should not be trusted. For confidential builds, build your own and host internally, replace with config.vm.url.

Attention to: synced_folder, vb.memory and provisioning - "run: always" versus "run: once"

A little bit of config

Vagrant -> Windows

Vagrant.configure(2) do |config| = "opentable/win-2012r2-standard-amd64-nocm"
  config.vm.hostname = "server"
  config.vm.provision :shell, path: "shell/InstallChocolatey.cmd"
  config.vm.provision :shell, path: "shell/InstallBoxStarter.bat"
  config.vm.provision :shell, path: "shell/RunBoxstarter.ps1" "public_network", bridge: "eth1.200", 
    ip: ""
  config.vm.provision :shell, run: "always",
    inline: "route delete"
  config.vm.provision :shell, run: "always",
    inline: "route add mask"

Note: Really untrustworthy build - not from a vendor.

Attention to: Define hostname, public_network, note that this is a windows box and is running cmd and bat files (also PS1 files). Routing on public network interfaces is problematic at best!!

A little bit of config

Vagrant -> Several Machines at once

Vagrant.configure(2) do |config| = "opentable/win-2012r2-standard-amd64-nocm"
  config.vm.define :v401a do |v401a|
    v401a.vm.hostname = "v401a" "public_network", bridge: "em2.401", 
      ip: ""
  config.vm.define :v401b do |v401b|
    v401b.vm.hostname = "v401b" = "ubuntu/trusty64" "public_network", bridge: "em2.401", 
      ip: ""

Note: Attention to: Config creates two machines, defines hostnames and separates out box files to use. Note no post config is here. Contrived example drawn from complex personal scripts.

A little bit of config


ssh-copy-id root@linux1

# Windows Machines need
#  ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1

ansible -m setup 

ansible-playbook site.yml

A little bit of config

Ansible -> Starting up

  • hosts
  • group_vars/all/vault
default_password: DreadfullyInsecure
    name: Jon Spriggs
    name: Fred Bloggs

Note: Use ansible-vault encrypt to convert the plaintext vault file to an encrypted one.

A little bit of config

Ansible -> Create Windows Users

  • ad.yml
- hosts: Core_AD
   - ad
  • roles/ad/tasks/main.yml
- name: Create User in AD
  raw: if (dsquery user -samid "{{item.key}}") {"Not Required"} else
    {New-ADUser -SamAccountName "{{item.key}}" -UserPrincipalName 
    "{{item.key}}@labby.mclabface" -Name "{{}}" 
    -DisplayName "{{}}"
    -GivenName "{{" ")[1]}}" 
    -Surname "{{" ")[-1]}}" 
    -ChangePasswordAtLogon $true -Enabled $true 
    -AccountPassword (ConvertTo-SecureString "{{default_password}}" 
    -AsPlainText -Force)}
  with_dict: "{{users}}"
  tags: users 

A little bit of config

Ansible -> Create Linux Users

  • linux.yml
- hosts: Core_Linux
  roles: common_linux
  • roles/common_linux/tasks/main.yml
- include: user.yml
  tags: users
  • roles/common_linux/tasks/user.yml
- name: Create role for Sudo Group
  lineinfile: "dest=/etc/sudoers state=present regexp='^%sudo' 
    line='%sudo ALL=(ALL) NOPASSWD: ALL' validate='visudo -cf %s'"
- name: Creating Admin Users
  user: name="{{item.key}}" uid="{{item.value.uid}}" 
    comment="{{}}" groups=sudo shell=/bin/bash 
    password="{{default_password | password_hash('sha512') }}" 
  with_dict: "{{admin_users}}"

Complicated Labs

  • VLAN Tag your switches
  • Route (or better - Firewall) between VLANs
  • Create disposable network segments (or "Pods")
  • Unified authentication using Radius, Kerberos and Active Directory
  • Ansible for Infrastructure (Linux, Windows, ESXi, but not switches!)

Note: For all Windows' failings, it's very easy to set up MS Active Directory, and even easier to add Radius Authentication to that model. Linux will do Kerberos authentication against Active Directory, as will ESXi.

The network segments should be isolated from each other by a firewall. This means an impacting change on one pod will not impact any other. The firewall will also perform routing and hide NATs where required.

Ansible is not able to reconfigure older Cisco or Juniper switches. It can be coerced into making changes to Checkpoint firewalls, but will not work out-of-the-box.

My lab

  • Back-to-back firewalls from "Live" areas, into "Core" terminal servers
  • Terminal servers have full access to all pods
  • Terminal servers are MS Windows virtualized on Linux systems - which means SSH can be used to bring them back online.
  • Using ser2net to provide telnet access to serial ports over USB
  • NAS for shared storage of Vagrant Boxes, mounted on all VM servers

My lab


  • Physical Topology
{CORP_NET} -> {CORP_FW} -> {LAB_FW} -> {LAB_DSL}
                             / | \
            POD_NET1 <------/  |  \----> POD_NET2
  • Firewall Rules
Permit: CORP_NET -> Core_Net : RDP
Deny  : CORP_NET -> Core_Net : Any
Deny  : Any      -> CORP_NET : Any
Permit: Core_Net -> Any      : Any
Deny  : Any      -> Core_Net : Any
Permit: POD_Nets -> Internet : Any
Deny  : Any      -> Any      : Any

Any questions?



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment