diff --git a/.gitignore b/.gitignore index cf7ed26e..5da147d2 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ env/ poetry.lock .venv/ srv/isc-agent/requirements.txt + + diff --git a/README_Terraform.md b/README_Terraform.md new file mode 100644 index 00000000..b0ed4a62 --- /dev/null +++ b/README_Terraform.md @@ -0,0 +1,60 @@ +### For instructions on how to install `terraform`, please consult the following: [HashiCorp Terraform Installation](https://learn.hashicorp.com/tutorials/terraform/install-cli) + +### Install `git` if not part of the default OS packages: +`sudo install git` +(_could be apt, yum, dpkg, etc._) + +### Clone this repository: +`git clone https://github.com/DShield-ISC/dshield` + +### Change into the `cloud provider` automation directory of choice: +- To deploy honeypots using AWS' infrastructure: + - `cd dshield/terraform/aws/` + +- To deploy honeypots using Microsoft Azure's infrastructure: + - `cd dshield/terraform/azure/` + +### Adjust the required and optional variables to reflect the environment: +` variables.tf ` +(_no judgement if the editor isn't `vi`_) + +### Define the following **required** variables: +- **dshield_email** +- **dshield_apikey** +- **dshield_userid** +- **aws_ssh_key_pub** _OR_ **azure_ssh_key_pub** _depending on provider_ +- **aws_ssh_key_priv** _OR_ **azure_ssh_key_priv** _depending on provider_ +- **aws_credentials** _if using **AWS**_ +- **azure_tenant_id** _if using **Azure Service Principal**_ +- **azure_subscription_id** _if using **Azure Service Principal**_ +- **azure_client_id** _if using **Azure Service Principal**_ +- **azure_client_secret** _if using **Azure Service Principal**_ + +### Optional variables: +- **honeypot_nodes** (default: `1` *increase to scale horizontally*) +- **aws_region** (default: `us-east-1`) _if using **AWS**_ +- **aws_ec2_size** (default: `t2.micro`) _if using **AWS**_ +- **azure_region** (default: `East US`) _if using **Azure**_ +- **azure_image_size** (default: `Standard_B1ls`) _if using **Azure**_ +- **honeypot_network** (default: `10.40.0.0/16` for VPC & `10.40.0.0/24` for SG) +- **honeypot_ssh_port** (default: `12222`) +- **dshield_ca_country** (default: `US`) +- **dshield_ca_state** (default: `Florida`) +- **dshield_ca_city** (default: `Jacksonville`) +- **dshield_ca_company** (default: `DShield`) +- **dshield_ca_depart** (default: `Decoy`) + +### General assumptions (**please update to reflect the appropriate locations as denoted above**): +- AWS credentials are contained in the default location: + - `~/.aws/credentials` + +- Azure credentials are successfully validated using `az login` prior to plan/apply + +- SSH credentials are contained in the default location: + - `~/.ssh/id_rsa` + - `~/.ssh/id_rsa.pub` + +### After completing the above items, run the following commands to begin the installation: +```terraform init; terraform plan -out=honeypot; terraform apply "honeypot"``` +**OR** +```terraform init; terraform apply``` and type `yes` when prompted diff --git a/terraform/aws/main.tf b/terraform/aws/main.tf new file mode 100644 index 00000000..c893684f --- /dev/null +++ b/terraform/aws/main.tf @@ -0,0 +1,194 @@ +terraform { + required_providers { + aws = { + version = "~> 3.73.0" + } + http = { + version = ">= 2.1.0" + } + null = { + version = ">= 3.1.0" + } + local = { + version = ">= 2.1.0" + } + template = { + version = ">= 2.2.0" + } + } + + required_version = "~> 1.1.4" +} + +provider "aws" { + shared_credentials_file = var.aws_credentials + region = var.aws_region + # if using separate profiles, otherwise leave at "default" or comment out + profile = var.aws_profile +} + +data "http" "local_ip" { + url = "https://ipv4.icanhazip.com" +} + +data "aws_availability_zones" "available" { + state = "available" +} + +data "aws_ami" "ubuntu_ami" { + owners = [var.aws_ami_owner] + most_recent = true + filter { + name = "name" + values = [ var.aws_ami_name ] + } +} + +# switched from template_file to local_file due to: https://github.com/hashicorp/terraform/issues/24616 +resource "local_file" "enable_logging" { + content = templatefile("${path.module}/../templates/install_honeypot.tpl", {output_logging = var.output_logging}) + filename = "${path.module}/../scripts/install_honeypot.sh" +} + +# upload ssh key to provision / configure ec2 +resource "aws_key_pair" "honeypot_key" { + key_name = "dshield_honeypot" + public_key = file(var.aws_ssh_key_pub) +} + +# Create a VPC to launch our instances into +resource "aws_vpc" "honeypot_vpc" { + cidr_block = "${var.honeypot_network}/16" +} + +# Create an internet gateway to give our subnet access to the outside world +resource "aws_internet_gateway" "honeypot_gw" { + vpc_id = aws_vpc.honeypot_vpc.id +} + +# Grant the VPC internet access on its main route table +resource "aws_route" "honeypot_internet" { + route_table_id = aws_vpc.honeypot_vpc.main_route_table_id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.honeypot_gw.id +} + +# Create a subnet to launch our instances into +resource "aws_subnet" "honeypot_subnet" { + vpc_id = aws_vpc.honeypot_vpc.id + cidr_block = "${var.honeypot_network}/24" + availability_zone = data.aws_availability_zones.available.names[0] + map_public_ip_on_launch = true +} + +resource "aws_security_group" "honeypot_security_group" { + name = "honeypot_security_group" + vpc_id = aws_vpc.honeypot_vpc.id + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "honeypot" { + ami = data.aws_ami.ubuntu_ami.id + instance_type = var.aws_ec2_size + key_name = aws_key_pair.honeypot_key.id + vpc_security_group_ids = [ aws_security_group.honeypot_security_group.id ] + subnet_id = aws_subnet.honeypot_subnet.id + count = var.honeypot_nodes + + tags = { + Name = var.aws_tag + } +} + +resource "null_resource" "upload" { + count = var.honeypot_nodes + triggers = { + ec2_public_ip = element(aws_instance.honeypot.*.public_ip, count.index) + } + + connection { + type = "ssh" + user = var.aws_ami_user + host = element(aws_instance.honeypot.*.public_ip, count.index) + private_key = file(var.aws_ssh_key_priv) + } + + provisioner "file" { + destination = "/tmp/dshield.ini" + content = templatefile("${path.module}/../templates/dshield_ini.tpl", { + dshield_email = var.dshield_email + dshield_userid = var.dshield_userid + dshield_apikey = var.dshield_apikey + public_ip = element(aws_instance.honeypot.*.public_ip, count.index) + public_ssh = var.honeypot_ssh_port + private_ip = join("/", [var.honeypot_network, "24"]) + deploy_ip = chomp(data.http.local_ip.body) + }) + } + + provisioner "file" { + destination = "/tmp/dshield.sslca" + content = templatefile("${path.module}/../templates/dshield_sslca.tpl", { + dshield_ca_country = var.dshield_ca_country + dshield_ca_state = var.dshield_ca_state + dshield_ca_city = var.dshield_ca_city + dshield_ca_company = var.dshield_ca_company + dshield_ca_depart = var.dshield_ca_depart + }) + } + + # upload our provisioning scripts + provisioner "file" { + source = "${path.module}/../scripts/" + destination = "/tmp/" + } + + provisioner "remote-exec" { + inline = [ + "sudo sed -i.bak 's/^[#\\s]*Port 22\\s*$/Port ${var.honeypot_ssh_port}/' /etc/ssh/sshd_config", + "sudo mv /tmp/dshield.ini /etc/", + "sudo mv /tmp/dshield.sslca /etc/" + ] + } + + # install required packages + provisioner "remote-exec" { + script = "${path.module}/../scripts/install_reqs.sh" + } + + depends_on = [ aws_instance.honeypot ] +} + +resource "null_resource" "install" { + count = var.honeypot_nodes + triggers = { + ec2_public_ip = element(aws_instance.honeypot.*.public_ip, count.index) + } + + connection { + type = "ssh" + user = var.aws_ami_user + host = element(aws_instance.honeypot.*.public_ip, count.index) + port = var.honeypot_ssh_port + private_key = file(var.aws_ssh_key_priv) + } + + # install dshield honeypot + provisioner "remote-exec" { + script = "${path.module}/../scripts/install_honeypot.sh" + } + + depends_on = [null_resource.upload] +} diff --git a/terraform/aws/output.tf b/terraform/aws/output.tf new file mode 100644 index 00000000..12d67df4 --- /dev/null +++ b/terraform/aws/output.tf @@ -0,0 +1,16 @@ +output "begin" { + value = < $d/../etc/CA/requests/$hostname.keypin +fi + +if [ ! -f $d/../etc/CA/keys/$hostname-spare.key ]; then + openssl req -sha256 -new -newkey rsa:2048 -keyout $d/../etc/CA/keys/$hostname-spare.key -out $d/../etc/CA/requests/$hostname-spare.csr -nodes -subj "/C=$country/ST=$state/L=$city/O=$company/OU=$department/CN=$hostname" +openssl req -in $d/../etc/CA/requests/$hostname-spare.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64 > $d/../etc/CA/requests/$hostname-spare.keypin +fi + +if [ ! -f $d/../etc/CA/keys/dshieldca.key ] ; then + openssl genrsa -aes256 -out $d/../etc/CA/keys/dshieldca.key -passout pass:raspi 4096 + openssl rsa -in $d/../etc/CA/keys/dshieldca.key -out $d/../etc/CA/keys/dshieldcanp.key -passin pass:raspi + mv $d/../etc/CA/keys/dshieldcanp.key $d/../etc/CA/keys/dshieldca.key +fi +if [ ! -f $d/../etc/CA/certs/dshieldca.crt ]; then + openssl req -new -x509 -days 3652 -key $d/../etc/CA/keys/dshieldca.key -out $d/../etc/CA/certs/dshieldca.crt -subj "/C=$country/ST=$state/L=$city/O=$company/OU=$department/CN=ROOT CA" +fi + +# we will only sign the primary CSR, not the spare one for now. +touch ../etc/CA/index.txt + +sed -r --in-place=.bak "s|^dir\s=.*$|dir = $cadir|" ../etc/openssl.cnf + +openssl ca -batch -config ../etc/openssl.cnf -policy signing_policy -extensions signing_req -out ../etc/CA/certs/$hostname.crt -infiles ../etc/CA/requests/$hostname.csr diff --git a/terraform/templates/dshield_ini.tpl b/terraform/templates/dshield_ini.tpl new file mode 100644 index 00000000..511bc2d9 --- /dev/null +++ b/terraform/templates/dshield_ini.tpl @@ -0,0 +1,21 @@ +[DShield] +interface=eth0 +version=93 +email=${dshield_email} +userid=${dshield_userid} +apikey=${dshield_apikey} +piid= +# the following lines will be used by a new feature of the submit code: +# replace IP with other value and / or anonymize parts of the IP +honeypotip=${public_ip} +replacehoneypotip= +anonymizeip= +anonymizemask= +fwlogfile=/var/log/dshield.log +nofwlogging=${private_ip} ${deploy_ip} +localips=${deploy_ip} +adminports=${public_ssh} +nohoneyips=${deploy_ip} +nohoneyports='2222 2223 8000' +manualupdates=0 +telnet=true diff --git a/terraform/templates/dshield_sslca.tpl b/terraform/templates/dshield_sslca.tpl new file mode 100644 index 00000000..9a8f4fac --- /dev/null +++ b/terraform/templates/dshield_sslca.tpl @@ -0,0 +1,5 @@ +Country="${dshield_ca_country}" +State="${dshield_ca_state}" +City="${dshield_ca_city}" +Company="${dshield_ca_company}" +Depart="${dshield_ca_depart}" diff --git a/terraform/templates/install_honeypot.tpl b/terraform/templates/install_honeypot.tpl new file mode 100644 index 00000000..1c7338fc --- /dev/null +++ b/terraform/templates/install_honeypot.tpl @@ -0,0 +1,14 @@ +#! /bin/bash +cd ~/ +mkdir install +cd install +git clone https://github.com/DShield-ISC/dshield.git +cd dshield/bin +mv /tmp/makecert2.sh makecert.sh +chmod +x makecert.sh +sudo ./install.sh --upgrade +if [ ${output_logging} = true ]; then + chmod +x /tmp/enable_logging.sh + sudo /tmp/enable_logging.sh +fi +sudo reboot