Skip to content

Commit

Permalink
Automate vm image creation
Browse files Browse the repository at this point in the history
  • Loading branch information
PMaynard committed Sep 5, 2018
1 parent 3bb357c commit 44add84
Show file tree
Hide file tree
Showing 16 changed files with 306 additions and 108 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ Vagrantfile
*.retry
*.iml
*.idea
vagrant_image/packer_cache/
vagrant_image/vagrant.box
18 changes: 0 additions & 18 deletions DEV.md

This file was deleted.

72 changes: 66 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Clone the repository and install the required dependencies:
Build:

mvn clean package
mvn package -Dmaven.test.skip=true # Skip tests.
mvn package -DskipTests # Skip tests.

Start up a RTU:

Expand All @@ -51,7 +51,7 @@ Start up a HMI:

The default configuration profile will deploy 1 HMI and 4 RTUs. The HMI will integrate the RTUs using the IEC104 and OPC-UA. The RTUs are configured to return random process data.

## Prerequisites
## Prerequisites (Vagrant+VirtualBox)

Use the latest version of Vagrant over the pre-built/distribution packages as these scripts use features from the latest versions of Vagrant. *Should be fine if using Ubuntu 18.04.1 LTS*.

Expand All @@ -61,11 +61,70 @@ Use the latest version of Vagrant over the pre-built/distribution packages as th
bundle --binstubs exec
ln -sf /opt/vagrant/exec/vagrant /usr/local/bin/vagrant

## [OPTIONAL] Create VM Image

This is an optional development step. It builds a virtual machine image, pre-configured to run the testbed nodes. If you don't want to create the latest version, the default option is get a stable image from Vagrant's image repository which stays in step with the master branch.

The packer is used to create an image suitable for VirtualBox and Vagrant:

cd vagrant_image
packer build vagrant-node.json
vagrant box add testbed-node vagrant.box

## Deploy

cp Vagrantfile.default Vagrantfile

**WARNING** You will need at least 4GB of free RAM.

Update the Vagrantfile with any additional information, such as static IP address and RAM usage.

The default IP settings are ```10.50.50.*``` .200 for HMI and 101-105 for RTUs. The default RAM per VM is 512MB.

vagrant up

vagrant ssh hmi
vagrant ssh rtu-1 # 1-5
vagrant halt
vagrant destroy

# Example Dataset

An example dataset was created, using the default deployment configuration. PCAPs can be downloaded from [here](https://dx.doi.org/10.6084/m9.figshare.6133457.v1). The IEC104 MITM was performed using the ettercap plugin located [here](https://github.com/PMaynard/ettercap-104-mitm)

- **\[Host-SCAN 13:45\]**: Basic network reconnaissance using a Nmap
network wide scan. CMD: 'nmap -sn 10.50.50.\*'

- **\[Host-SCAN 13:47\]**: Basic network reconnaissance looking for
accessible [IEC104]{acronym-label="IEC104"
acronym-form="singular+short"} servers. CMD: 'nmap 10.50.50.\* -p
2404'

- **\[Host-SCAN 13:47\]**: Full port scan of identified
[RTUs]{acronym-label="RTU" acronym-form="plural+short"} nodes. CMD:
'nmap 10.50.50.101-105 -A'

- **\[Host-SCAN 13:49\]**: An active [IEC104]{acronym-label="IEC104"
acronym-form="singular+short"} scan which probes the nodes using the
[IEC104]{acronym-label="IEC104" acronym-form="singular+short"}
protocol[^1]. CMD: 'nmap -Pn -n -d --script iec-identify.nse
--script-args='iec-identify.timeout=500' -p 2404 10.50.50.101-105'

- **\[Host-MITM 14:19\]**: Performs a [MITM]{acronym-label="MITM"
acronym-form="singular+short"} on RTU-1 and the HMI. CMD: 'ettercap
-i enp0s8 -T -M arp -P spoof\_104 /10.50.50.101/ /10.50.50.150/'

A numerical break down of the dataset is shown below:

Host IP IEC104 OPC-UA Other **Total**
----------- -------------- -------- -------- -------- -----------
HMI 10.50.50.150 26,158 0 17,688 43,846
Historian 10.50.50.151 0 14,695 14,927 29,622
RTU-1 10.50.50.101 3,592 2,940 5,543 12,075
RTU-2 10.50.50.102 3,665 2,941 5,876 12,482
RTU-3 10.50.50.103 3,668 2,940 5,793 12,404
RTU-4 10.50.50.104 3,690 2,940 5,771 12,404
RTU-5 10.50.50.105 3,576 930 7,933 12,442
MITM 10.50.50.99 2,390 0 3,449 5,839
SCAN 10.50.50.3 15 0 28,351 28,366

# Citation

Please cite this framework using the following format:
Expand All @@ -77,5 +136,6 @@ Please cite this framework using the following format:
year = "2018"
}

An example dataset can be found at: https://dx.doi.org/10.6084/m9.figshare.6133457.v1
The dataset can be cited using DOI: [10.6084/m9.figshare.6133457.v1](https://dx.doi.org/10.6084/m9.figshare.6133457.v1)

The full paper can be found at: <https://petermaynard.co.uk/publication/an-open-framework-for-deploying-experimental-scada-testbed-networks/>
14 changes: 7 additions & 7 deletions Vagrantfile.default → Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
config.vm.box_check_update = false

# TODO: Hack because the packaged vm is messy.
config.vm.box_check_update = true
config.vm.provider "virtualbox" do |vb|
vb.customize [ "modifyvm", :id, "--uartmode1", "disconnected" ]
vb.memory = 512
vb.memory = 3048
end

config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
ansible.compatibility_mode = "2.0"
end

(1..5).each do |i|
config.vm.define "rtu-#{i}" do |node|
node.vm.hostname = "rtu"
node.vm.box = "pmaynard/testbed-node"
node.vm.network "public_network", ip: "10.50.50.10#{i}", bridge: "br0"
# node.vm.box = "testbed-node" # [OPTIONAL] If using a locally created image.
node.vm.network "public_network", ip: "10.50.50.10#{i}"
end
end

config.vm.define "hmi" do |hmi|
hmi.vm.hostname = "hmi"
hmi.vm.box = "pmaynard/testbed-node"
hmi.vm.network "public_network", ip: "10.50.50.200", bridge: "br0"
# hmi.vm.box = "testbed-node" # [OPTIONAL] If using a locally created image.
hmi.vm.network "public_network", ip: "10.50.50.200"
end
end
13 changes: 0 additions & 13 deletions Vagrantfile.build

This file was deleted.

2 changes: 1 addition & 1 deletion node/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
<dependency>
<groupId>org.opcfoundation.ua</groupId>
<artifactId>opc-ua-stack</artifactId>
<version>1.3.344-SNAPSHOT</version>
<version>1.3.345-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
Expand Down
29 changes: 18 additions & 11 deletions playbook.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
---
- hosts: all
become: yes
tasks:
- name: Configure for packaging
include_role:
name: vagrant-box
when: "'buildImage' in ansible_hostname"
tasks:
- name: Install Requirements
apt: name={{ item }} state=present
with_items:
- openjdk-8-jdk
- maven
- tmux
- htop

- name: Setup Environmnet for TestBed
include_role:
name: node
when: "'buildImage' in ansible_hostname"
- name: Compile source code.
command: "mvn package"
args:
creates: "/vagrant/node/target/node-1.0.jar"
chdir: "/vagrant/"
when: "'rtu' in ansible_hostname or 'hmi' in ansible_hostname"

- name: Startup RTU
shell: "tmux new -d cat /vagrant/scripts/rtu.cmd | java -jar /vagrant/node/target/node-1.0.jar"
shell: "tmux new -d java -jar /vagrant/node/target/node-1.0.jar && tmux send script SPACE /vagrant/scripts/rtu.cmd ENTER"
become_user: vagrant
when: "'rtu' in ansible_hostname"

- name: Startup HMI
shell: "tmux new -d java -jar cat /vagrant/scripts/hmi.cmd | java -jar /vagrant/node/target/node-1.0.jar"
shell: "tmux new -d java -jar /vagrant/node/target/node-1.0.jar && tmux send script SPACE /vagrant/scripts/hmi.cmd ENTER"
become_user: vagrant
when: "'hmi' in ansible_hostname"
18 changes: 0 additions & 18 deletions roles/node/tasks/main.yml

This file was deleted.

33 changes: 0 additions & 33 deletions roles/vagrant-box/tasks/main.yml

This file was deleted.

1 change: 0 additions & 1 deletion scripts/hmi.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ hmi-interval 1000
remote-hosts 127.0.0.1
show
run

40 changes: 40 additions & 0 deletions vagrant_image/preseed.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
choose-mirror-bin mirror/http/proxy string
d-i base-installer/kernel/override-image string linux-server
d-i clock-setup/utc boolean true
d-i clock-setup/utc-auto boolean true
d-i finish-install/reboot_in_progress note
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i partman-auto/disk string /dev/sda
d-i partman-auto-lvm/guided_size string max
d-i partman-auto/choose_recipe select atomic
d-i partman-auto/method string lvm
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i pkgsel/include string openssh-server
d-i pkgsel/install-language-support boolean false
d-i pkgsel/update-policy select none
d-i pkgsel/upgrade select full-upgrade
d-i time/zone string UTC
tasksel tasksel/first multiselect standard, ubuntu-server

d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/layoutcode string gb
d-i keyboard-configuration/modelcode string pc105
d-i debian-installer/locale string en_GB

# Create vagrant user account.
d-i passwd/user-fullname string vagrant
d-i passwd/username string vagrant
d-i passwd/user-password password vagrant
d-i passwd/user-password-again password vagrant
d-i user-setup/allow-password-weak boolean true
d-i user-setup/encrypt-home boolean false
d-i passwd/user-default-groups vagrant sudo
d-i passwd/user-uid string 900
5 changes: 5 additions & 0 deletions vagrant_image/scripts/ansible.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -eux

# Install Ansible repository.
apt -y update && apt-get -y upgrade
apt -y install ansible
15 changes: 15 additions & 0 deletions vagrant_image/scripts/cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -eux

# Apt cleanup.
apt autoremove
apt update

# Delete unneeded files.
rm -f /home/vagrant/*.sh

# Zero out the rest of the free space using dd, then delete the written file.
dd if=/dev/zero of=/EMPTY bs=1M
rm -f /EMPTY

# Add `sync` so Packer doesn't quit too early, before the large file is deleted.
sync
8 changes: 8 additions & 0 deletions vagrant_image/scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash -eux

# Add vagrant user to sudoers.
echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers

# Disable daily apt unattended updates.
echo 'APT::Periodic::Enable "0";' >> /etc/apt/apt.conf.d/10periodic
Loading

0 comments on commit 44add84

Please sign in to comment.