Cloud Pentesting Lab
How To Create a Kali & Parrot Pentesting Lab in AWS Using Docker and Terraform
In this post, I’ll quickly run through how to set up an AWS EC2 machine and install pre-configured kali and parrot containers, all provisioned automatically with terraform.
Prerequisites
Sign up for a free AWS account. You just need a valid credit card.
Install AWS CLI tool.
Install Terraform CLI tool.
Pull the lab repo from my github that contains everything you need to follow this guide, and cd into it:
git pull https://github.com/tonyarris/lab && cd ./lab
What’s in the repo?
You’ll find a folder for the kali/ and parrot/ docker images. In each, there’s the dockerfile that specifies the docker build. I have added a few tools to the kali machine, whereas the parrot container remains vanilla. You can leave these as-is for the purposes of this guide.
The terraform/ folder contains the deployment manifest, so let’s have a look:
cd terraform/
Terraform is an infrastructure-as-code tool that lets you manage cloud assets extremely quickly and easily. If you inspect the main.tf file, you’ll see it contains all the info needed to deploy an EC2 instance.
For example:
provider "aws" {
profile = "default"
region = "eu-south-1"
}
sets the AWS zone,
resource "aws_instance" "pt_lab" {
ami = "ami-0f8ce9c417115413d"
instance_type = "t3.micro"
associate_public_ip_address = true
key_name = "ssh-key"
count = var.instance_count
tags = {
Name = "PT Lab Instance ${count.index + 1}"
}
Creates a new aws_instance called pt_lab, specifies a t3.micro machine, associates a public IP address, associates an SSH key for access and gives it a count which we will see shortly.
root_block_device {
volume_type = "gp2"
volume_size = 30
}
This block assigns a 30GB hard drive.
The following block runs a script that configures the Docker containers:
user_data = <<-EOF
#!/bin/bash
# clone lab repo and setup filesystem
sudo su
git clone https://github.com/tonyarris/lab /home/ubuntu/lab
cd /home/ubuntu/lab
cp stop.sh kali
cp stop.sh parrot
rm stop.sh
rm -r terraform/
# install docker
apt-get -y update
apt-get -y upgrade
apt-get -y install docker.io
# build containers
cd kali
chmod +x *.sh
./build.sh
cd ../parrot
chmod +x *.sh
./build.sh
# set aliases
cd /home/ubuntu
echo "alias kali=\"sh /home/ubuntu/lab/kali/run.sh\"" >> .bashrc
echo "alias parrot=\"sh /home/ubuntu/lab/parrot/run.sh\"" >> .bashrc
echo "alias stop=\"sh /home/ubuntu/lab/parrot/stop.sh\"" >> .bashrc
EOF
}
There’s one more important that we will see shortly.
Configure AWS CLI
Create a new AWS Access Key.
Run:
aws configure
and follow the prompts to input your AWS Access Key ID and Secret Access Key.
Create an SSH key & add to the manifest
Follow this guide to create an ed25519 SSH key in a location of your choice.
Add your public_key to the main.tf manifest in place of mine in this block:
resource "aws_key_pair" "ssh-key" {
key_name = "ssh-key"
public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl9VKriojo6Q60esciAHQxKh8g6Tb00eYIHdAm8RuqPry5xTFP+gh0GS4ub0hZBnOyvC6sa4B/1MTNjL+Ex4rkUfM0gHH0PSSImJPBzKtQQ+sCxk4TsKTjfqxUHQQeaQgqufpy9uiXLRKdX0mZJLWv/Q2o6Dbcj7XhZqdrSzLKHqm7cCjv5b7AzVCRXlENA7fFSDXuupaNyWwfubn55qVielLQOJOTnNuuS2RQrNKDVWSMqAVds+E0SeFVikRAqhbd0YNWYqs139Z/bu9R9vMhLs1HElRimCwx1itjn+GHCLQ25chJHu1+snJmWakjxuLQz0Y8qoo+xrFluzQXQWo1"
}
This will associate your EC2 instance with your SSH key, granting you remote SSH access.
Save the main.tf file.
Deploy
From within the terraform/ folder, run:
terraform init
to initialise terraform.
Validate the manifest file with:
terraform validate
You should see Success! The configuration is valid. If not, fix any errors.
Then run:
terraform apply
and you should see a confirmation message showing all the changes terraform is about to make. It should look something like this:
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.pt_lab[0] will be created
+ resource "aws_instance" "pt_lab" {
+ ami = "ami-0f8ce9c417115413d"
+ arn = (known after apply)
+ associate_public_ip_address = true
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t3.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = "ssh-key"
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "PT Lab Instance 1"
}
+ tags_all = {
+ "Name" = "PT Lab Instance 1"
}
+ tenancy = (known after apply)
+ user_data = "b6598edad7c973b8fe63d4a74baf28256a6e3541"
+ user_data_base64 = (known after apply)
+ vpc_security_group_ids = (known after apply)
+ capacity_reservation_specification {
+ capacity_reservation_preference = (known after apply)
+ capacity_reservation_target {
+ capacity_reservation_id = (known after apply)
}
}
+ ebs_block_device {
+ delete_on_termination = (known after apply)
+ device_name = (known after apply)
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ snapshot_id = (known after apply)
+ tags = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = (known after apply)
+ volume_type = (known after apply)
}
+ enclave_options {
+ enabled = (known after apply)
}
+ ephemeral_block_device {
+ device_name = (known after apply)
+ no_device = (known after apply)
+ virtual_name = (known after apply)
}
+ metadata_options {
+ http_endpoint = (known after apply)
+ http_put_response_hop_limit = (known after apply)
+ http_tokens = (known after apply)
+ instance_metadata_tags = (known after apply)
}
+ network_interface {
+ delete_on_termination = (known after apply)
+ device_index = (known after apply)
+ network_interface_id = (known after apply)
}
+ root_block_device {
+ delete_on_termination = true
+ device_name = (known after apply)
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = 30
+ volume_type = "gp2"
}
}
# aws_key_pair.ssh-key will be created
+ resource "aws_key_pair" "ssh-key" {
+ arn = (known after apply)
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "ssh-key"
+ key_name_prefix = (known after apply)
+ key_pair_id = (known after apply)
+ public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl9VKriojo6Q60esciAHQxKh8g6Tb00eYIHdAm8RuqPry5xTFP+gh0GS4ub0hZBnOyvC6sa4B/1MTNjL+Ex4rkUfM0gHH0PSSImJPBzKtQQ+sCxk4TsKTjfqxUHQQeaQgqufpy9uiXLRKdX0mZJLWv/Q2o6Dbcj7XhZqdrSzLKHqm7cCjv5b7AzVCRXlENA7fFSDXuupaNyWwfubn55qVielLQOJOTnNuuS2RQrNKDVWSMqAVds+E0SeFVikRAqhbd0YNWYqs139Z/bu9R9vMhLs1HElRimCwx1itjn+GHCLQ25chJHu1+snJmWakjxuLQz0Y8qoo+xrFluzQXQWo1"
+ tags_all = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ instance_ip = [
+ (known after apply),
]
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
Type yes and press enter.
Your cloud pentesting box is being provisioned! Terraform will print out the public IP address and you can access your box with:
ssh -i YOURKEY ubuntu@11.22.33.44
where YOURKEY is your private SSH key and 11.22.33.44 is your EC2’s public IP address.
The EC2 machine will be ready almost instantly, but it will take about 20 minutes for the kali and parrot containers to download and install.
Using the lab
Once connected, there are three commands you need to know:
kalistarts a kali containerparrotstarts a parrot containerstopstops all running containers
To exit a container, just run exit.
Any files that you want to persist from the containers, you can save to /root/client/ in the container which maps to /home/ubuntu/lab/client on the EC2 machine. Remember, any time you stop a container, all its files will be lost.
Customising & destroying the lab
You can make changes to the terraform manifest and run terraform apply again and terraform will automatically make the changes and deploy as needed.
You can alter the dockerfile manifests in the kali/ and parrot/ folders to add your favourite tools.
If you want to destroy the instance, run terraform destroy from within the terraform/ folder of the repo and your instance will be destroyed.
Done
That’s it! I hope you enjoyed setting up the lab. If you had any problems following this guide, drop me a line.