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:
kali
starts a kali containerparrot
starts a parrot containerstop
stops 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.