diff --git a/ec2-test-instance/.gitignore b/ec2-test-instance/.gitignore
new file mode 100644
index 0000000..bcc7663
--- /dev/null
+++ b/ec2-test-instance/.gitignore
@@ -0,0 +1 @@
+setup/*-keypair
diff --git a/ec2-test-instance/.terraform-docs.yml b/ec2-test-instance/.terraform-docs.yml
new file mode 100644
index 0000000..8391b9d
--- /dev/null
+++ b/ec2-test-instance/.terraform-docs.yml
@@ -0,0 +1,44 @@
+formatter: markdown table
+
+header-from: main.tf
+footer-from: ""
+
+sections:
+## hide: []
+ show:
+ - data-sources
+ - header
+ - footer
+ - inputs
+ - modules
+ - outputs
+ - providers
+ - requirements
+ - resources
+
+output:
+ file: README.md
+ mode: inject
+ template: |-
+
+ {{ .Content }}
+
+
+## output-values:
+## enabled: false
+## from: ""
+##
+## sort:
+## enabled: true
+## by: name
+##
+## settings:
+## anchor: true
+## color: true
+## default: true
+## description: false
+## escape: true
+## indent: 2
+## required: true
+## sensitive: true
+## type: true
diff --git a/ec2-test-instance/README.md b/ec2-test-instance/README.md
new file mode 100644
index 0000000..1876f18
--- /dev/null
+++ b/ec2-test-instance/README.md
@@ -0,0 +1,65 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.13 |
+| [aws](#requirement\_aws) | >= 3.0 |
+| [ldap](#requirement\_ldap) | >= 0.5.4 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 3.0 |
+| [local](#provider\_local) | n/a |
+| [null](#provider\_null) | n/a |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [role](#module\_role) | git@github.e.it.census.gov:terraform-modules/aws-iam-role.git | tf-upgrade |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_instance.test](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
+| [aws_key_pair.keypair](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair) | resource |
+| [local_file.test_addresses](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
+| [null_resource.generate_keypair](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
+| [aws_ami.test_arm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
+| [aws_ami.test_x86](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
+| [aws_iam_policy.ssm_policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source |
+| [aws_security_groups.test](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/security_groups) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [account\_alias](#input\_account\_alias) | AWS Account Alias (default: will pull from current account\_alias) | `string` | `""` | no |
+| [account\_id](#input\_account\_id) | AWS Account ID (default: will pull from current user) | `string` | `""` | no |
+| [availability\_zones](#input\_availability\_zones) | AWS Availability Zones to use (by default will use all available) | `list(string)` | `[]` | no |
+| [bootstrap\_commands](#input\_bootstrap\_commands) | List of commands to pass to the instance over SSH | `list(string)` | `[]` | no |
+| [enable\_bootstrap](#input\_enable\_bootstrap) | Flag to enable or disable bootstrap (yum and awscli setup) | `bool` | `true` | no |
+| [enable\_instances](#input\_enable\_instances) | Flag to enable or disable creation of EC2 key and instances | `bool` | `true` | no |
+| [instance\_count](#input\_instance\_count) | Number to indicate how many instances (up to subnet-count x az-count) | `number` | `null` | no |
+| [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component. This should be used primarily for common infrastructure things | `map(string)` | `{}` | no |
+| [private\_subnets\_ids](#input\_private\_subnets\_ids) | List of private subnet objects including: subnet, label, availability\_zone, id |
list(object({
subnet = string
label = string
availability_zone = string
id = string
})) | `[]` | no |
+| [public\_subnets\_ids](#input\_public\_subnets\_ids) | List of public subnet objects including: subnet, label, availability\_zone, id | list(object({
subnet = string
label = string
availability_zone = string
id = string
})) | `[]` | no |
+| [tags](#input\_tags) | AWS Tags to apply to appropriate resources (S3, KMS). Do not include safeguard tags here, use the data\_safeguard field for such things. | `map(string)` | `{}` | no |
+| [vpc\_environment](#input\_vpc\_environment) | VPC environment purpose (infrastructure, common, shared, dev, stage, ite, prod) | `string` | `null` | no |
+| [vpc\_full\_name](#input\_vpc\_full\_name) | VPC full name component (vpc{index}-{vpc\_name}) | `string` | `null` | no |
+| [vpc\_id](#input\_vpc\_id) | VPC ID | `string` | n/a | yes |
+| [vpc\_index](#input\_vpc\_index) | VPC index number (integer starting at 1) | `number` | `null` | no |
+| [vpc\_name](#input\_vpc\_name) | VPC name component used through the VPC descrbing its purpose (ex: dice-dev) | `string` | `null` | no |
+| [vpc\_short\_name](#input\_vpc\_short\_name) | VPC short name component (vpc{index}) | `string` | `null` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [keypair](#output\_keypair) | EC2 keypair for test instances |
+| [test\_instances](#output\_test\_instances) | Details about test instances |
+
\ No newline at end of file
diff --git a/ec2-test-instance/bin/do-iperf.sh b/ec2-test-instance/bin/do-iperf.sh
new file mode 100755
index 0000000..f9aae6d
--- /dev/null
+++ b/ec2-test-instance/bin/do-iperf.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+for f in $(awk '{print $2}' ips.txt); do echo "# from $(hostname) to $(grep $f ips.txt)"; iperf3 -c $f -t 60 -T "$(hostname -s)->$f"; done | tee iperf.$(date +%s).log
diff --git a/ec2-test-instance/bin/do-ping.sh b/ec2-test-instance/bin/do-ping.sh
new file mode 100755
index 0000000..c68919e
--- /dev/null
+++ b/ec2-test-instance/bin/do-ping.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+for f in $(awk '{print $2}' ips.txt); do echo "# from $(hostname) to $(grep $f ips.txt)"; ping -c 10 $f; echo ""; done |& tee pings.$(date +%s).log
diff --git a/ec2-test-instance/bin/install-ssm.sh b/ec2-test-instance/bin/install-ssm.sh
new file mode 100755
index 0000000..3717088
--- /dev/null
+++ b/ec2-test-instance/bin/install-ssm.sh
@@ -0,0 +1,85 @@
+#!/bin/bash -x
+
+VERSION="1.3.0"
+
+echo "# starring install-ssm.sh v$VERSION at $(date)"
+
+echo "# disabling root password"
+passwd -d root
+
+echo "# installing packages"
+sudo yum install -y iperf3 bind-utils curl nc awscli jq lsof policycoreutils-python
+
+echo "# configuring AWS CLI"
+REGION=$(curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)
+aws configure --profile default set region $REGION
+aws configure --profile default set output json
+sudo aws configure --profile default set region $REGION
+sudo aws configure --profile default set output json
+
+echo "# setup ssm"
+
+sudo yum install -y https://s3.$REGION.amazonaws.com/amazon-ssm-$REGION/latest/linux_amd64/amazon-ssm-agent.rpm
+sudo systemctl enable amazon-ssm-agent
+sudo systemctl start amazon-ssm-agent
+sudo systemctl status amazon-ssm-agent
+
+echo "# setp iperf3 service"
+sudo adduser iperf3 -s /sbin/nologin
+
+cat > /tmp/iperf3.service < /tmp/iperf3@.service < iperf3.$f.${TRY}_5001.log 2>&1 &
+ iperf3 -p 5002 -t 60 -c $f > iperf3.$f.${TRY}_5002.log 2>&1 &
+ iperf3 -p 5003 -t 60 -c $f > iperf3.$f.${TRY}_5003.log 2>&1 &
+done
diff --git a/ec2-test-instance/bin/show-tunnel-status.sh b/ec2-test-instance/bin/show-tunnel-status.sh
new file mode 100755
index 0000000..f67e02d
--- /dev/null
+++ b/ec2-test-instance/bin/show-tunnel-status.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+PROFILE=$1
+if [ -z $PROFILE ]
+then
+ echo "* missing profile"
+ exit 1
+fi
+
+REGION=$2
+if [ -z $REGION ]
+then
+ echo "* missing region"
+ exit 1
+fi
+
+VPC=$3
+if [ -z "$VPC" ]
+then
+ VPC="*vpc3*"
+fi
+
+echo "* using profile $PROFILE region $REGION for VPC filter $VPC"
+
+if [ -z "$FULL" ]
+then
+ echo "## VPN"
+ aws --profile $PROFILE --region $REGION ec2 describe-vpn-connections --filters Name=tag:Name,Values="$VPC" --output text|grep -iE "VGW|TAG.*Name|customer.*cgw-"
+ echo "## Routes"
+ aws --profile $PROFILE --region $REGION ec2 describe-route-tables --filters Name=tag:Name,Values="${VPC}private*" --output text|grep -iE "^TAGS.*Name|vgw"
+elif [ "$FULL" == "json" ]
+then
+ echo "## VPN.json"
+ aws --profile $PROFILE --region $REGION ec2 describe-vpn-connections --filters Name=tag:Name,Values="$VPC" --output json
+ echo "## Routes.json"
+ aws --profile $PROFILE --region $REGION ec2 describe-route-tables --filters Name=tag:Name,Values="${VPC}private*" --output json
+else
+ echo "## VPN.full"
+ aws --profile $PROFILE --region $REGION ec2 describe-vpn-connections --filters Name=tag:Name,Values="$VPC" --output text
+ echo "## Routes.full"
+ aws --profile $PROFILE --region $REGION ec2 describe-route-tables --filters Name=tag:Name,Values="${VPC}private*" --output text
+fi
diff --git a/ec2-test-instance/bin/test-ping.sh b/ec2-test-instance/bin/test-ping.sh
new file mode 100755
index 0000000..53b8273
--- /dev/null
+++ b/ec2-test-instance/bin/test-ping.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+DURATION=$1
+if [ -z $DURATION ]
+then
+ DURATION=15
+fi
+COUNT=$(( $DURATION * 60 ))
+if [ $COUNT == 0 ]
+then
+ COUNT=60
+fi
+
+STAMP=$(date "+%Y%m%d.%s")
+start=$(date +%s)
+
+echo "* running ping with count=$COUNT at $(date) start=$start"
+
+TIMEOUT=$(( $COUNT * 2 ))
+
+for f in $(cat test-ips.txt)
+do
+ echo " * host $f"
+ ping -c $COUNT -w $TIMEOUT $f > ping.$f.$STAMP.log 2>&1 &
+done
+
+end=$(date +%s)
+elapsed=$(( $end - $start ))
+
+echo "* done running ping with count=$COUNT at $(date) start=$start end=$end elapsed=$elapsed"
diff --git a/ec2-test-instance/bin/test-ssh.sh b/ec2-test-instance/bin/test-ssh.sh
new file mode 100755
index 0000000..a8a85e8
--- /dev/null
+++ b/ec2-test-instance/bin/test-ssh.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+DURATION=$1
+if [ -z $DURATION ]
+then
+ DURATION=5
+fi
+
+STAMP=$(date "+%Y%m%d.%s")
+start=$(date +%s)
+
+TIMEOUT=$DURATION
+
+KEYPAIR=$(ls setup/*-keypair)
+echo "* running ssh timeout=$TIMEOUT with keypair=$KEYPAIR at $(date) start=$start"
+
+count=1
+ecount=0
+for f in $(cat test-ips.txt)
+do
+ echo " * $count host $f"
+ SSH_AUTH_SOCK="" timeout $TIMEOUT ssh $SSH_OPTIONS -o StrictHostKeyChecking=false -o IdentityFile=$KEYPAIR ec2-user@$f "hostname -f; date +%s"
+ status=$?
+ if [ $status != 0 ]
+ then
+ ecount=$(( $ecount + 1 ))
+ fi
+ count=$(( $count + 1 ))
+done
+
+end=$(date +%s)
+elapsed=$(( $end - $start ))
+
+echo "* done running ssh at $(date) count=$count error_count=$ecount start=$start end=$end elapsed=$elapsed"
diff --git a/ec2-test-instance/data.tf b/ec2-test-instance/data.tf
new file mode 100644
index 0000000..d804ded
--- /dev/null
+++ b/ec2-test-instance/data.tf
@@ -0,0 +1,55 @@
+data "aws_ami" "test_x86" {
+ most_recent = true
+ owners = ["self", "amazon", "aws-marketplace"]
+
+ filter {
+ name = "description"
+ values = ["Amazon Linux 2*"]
+ }
+ filter {
+ name = "root-device-type"
+ values = ["ebs"]
+ }
+ filter {
+ name = "virtualization-type"
+ values = ["hvm"]
+ }
+ filter {
+ name = "architecture"
+ values = ["x86_64"]
+ }
+}
+
+data "aws_ami" "test_arm" {
+ most_recent = true
+ owners = ["self", "amazon", "aws-marketplace"]
+
+ filter {
+ name = "description"
+ values = ["Amazon Linux 2*"]
+ }
+ filter {
+ name = "root-device-type"
+ values = ["ebs"]
+ }
+ filter {
+ name = "virtualization-type"
+ values = ["hvm"]
+ }
+ filter {
+ name = "architecture"
+ values = ["arm64"]
+ }
+}
+
+data "aws_security_groups" "test" {
+ filter {
+ name = "vpc-id"
+ values = [local.vpc_id]
+ }
+ filter {
+ name = "group-name"
+ values = ["*linux*"]
+ }
+}
+
diff --git a/ec2-test-instance/ec2-keypair.tf b/ec2-test-instance/ec2-keypair.tf
new file mode 100644
index 0000000..6e760e7
--- /dev/null
+++ b/ec2-test-instance/ec2-keypair.tf
@@ -0,0 +1,49 @@
+#---
+# ec2 keypairs
+#---
+locals {
+ keypair_name = format("%v-test-ec2-keypair", local.vpc_short_name)
+}
+
+# two-step process to create
+# terraform apply -target=null_resource.generate_keypair
+# terraform apply
+# when done, add to git
+# cd setup
+# echo *-keypair >> .gitignore
+# git-secret add *-ec2-keypair
+# git-secret hide
+# git add *-ec2-keypair.{pub,secret}
+# git commit -m'add ec2-keypair: *-ec2-keypair' *-ec2-keypair.{pub,secret} .gitignore
+
+resource "null_resource" "generate_keypair" {
+ triggers = {
+ keypair_name = local.keypair_name
+ }
+
+ count = var.enable_instances ? 1 : 0
+ provisioner "local-exec" {
+ command = "test -d setup || mkdir setup"
+ }
+ provisioner "local-exec" {
+ working_dir = "./setup"
+ command = "ssh-keygen -f ${local.keypair_name} -N '' -t rsa -b 2048 -C '${local.keypair_name}@${var.vpc_domain_name}'"
+ }
+ # provisioner "local-exec" {
+ # when = destroy
+ # working_dir = "./setup"
+ # command = format("rm %v %v.pub",self.triggers.keypair_name,self.triggers.keypair_name)
+ # }
+}
+
+resource "aws_key_pair" "keypair" {
+ count = var.enable_instances ? 1 : 0
+ key_name = local.keypair_name
+ public_key = file("setup/${local.keypair_name}.pub")
+ depends_on = [null_resource.generate_keypair]
+}
+
+output "keypair" {
+ description = "EC2 keypair for test instances"
+ value = var.enable_instances ? aws_key_pair.keypair[0].key_name : ""
+}
diff --git a/ec2-test-instance/ec2-role.tf b/ec2-test-instance/ec2-role.tf
new file mode 100644
index 0000000..f51d483
--- /dev/null
+++ b/ec2-test-instance/ec2-role.tf
@@ -0,0 +1,22 @@
+locals {
+ ssm_policies = [
+ "AmazonSSMManagedInstanceCore",
+ "AmazonEC2RoleforSSM",
+ ]
+}
+
+data "aws_iam_policy" "ssm_policies" {
+ for_each = toset(local.ssm_policies)
+ name = each.key
+}
+
+module "role" {
+ source = "git@github.e.it.census.gov:terraform-modules/aws-iam-role.git?ref=tf-upgrade"
+
+ role_name = local.ec2_role_name
+ create = var.enable_instances
+ attached_policies = [for k, v in data.aws_iam_policy.ssm_policies : v.arn]
+ enable_instance_profile = true
+ assume_policy_document = data.terraform_remote_state.common.outputs.custom_policy_documents["ec2_assume"].policy
+}
+
diff --git a/ec2-test-instance/ec2.tf b/ec2-test-instance/ec2.tf
new file mode 100644
index 0000000..780d5c0
--- /dev/null
+++ b/ec2-test-instance/ec2.tf
@@ -0,0 +1,61 @@
+# https://cloudanddevopstech.com/2020/11/01/terraform-aws-ec2-with-ssm-agent-installed/
+
+resource "aws_instance" "test" {
+ for_each = var.enable_instances ? { for k, v in local.private_subnets_id_list : k => local.private_subnets_id_map[v.label] } : {}
+
+ ami = local.ami
+ instance_type = local.instance_type
+ availability_zone = each.value.availability_zone
+ key_name = local.key_name
+ subnet_id = each.value.id
+ vpc_security_group_ids = local.security_groups
+ iam_instance_profile = module.role.instance_profile_name
+
+ root_block_device {
+ encrypted = true
+ volume_type = "gp2"
+ volume_size = local.root_volume_size > 0 ? local.root_volume_size : 30
+ delete_on_termination = true
+ }
+
+ provisioner "remote-exec" {
+ inline = var.enable_bootstrap && length(var.bootstrap_commands) > 0 ? var.bootstrap_commands : []
+ on_failure = continue
+
+ connection {
+ type = "ssh"
+ user = "ec2-user"
+ host = self.private_ip
+ agent = false
+ private_key = file("${path.root}/setup/${local.key_name}")
+ timeout = var.enable_bootstrap && length(var.bootstrap_commands) > 0 ? "5m" : "5s"
+ }
+ }
+
+ user_data = file("${path.module}/bin/install-ssm.sh")
+
+ volume_tags = merge(
+ local.common_tags,
+ tomap({ "Name" = format("v-ebs-%v-test-%v:%v", local.vpc_short_name, each.key, "/") }),
+ )
+
+ tags = merge(
+ local.common_tags,
+ tomap({ "Name" = format("%v-test-%v.%v", local.vpc_short_name, each.key, var.vpc_domain_name) }),
+ )
+}
+
+output "test_instances" {
+ description = "Details about test instances"
+ value = { for k, v in aws_instance.test : k => {
+ name = k
+ id = v.id
+ ip_address = v.private_ip
+ subnet_id = v.subnet_id
+ } }
+}
+
+resource "local_file" "test_addresses" {
+ content = templatefile("${path.root}/templates/test-ips.txt.tpl", { instances = aws_instance.test })
+ filename = "${path.root}/test-ips.txt"
+}
diff --git a/ec2-test-instance/locals.tf b/ec2-test-instance/locals.tf
new file mode 100644
index 0000000..0ef3672
--- /dev/null
+++ b/ec2-test-instance/locals.tf
@@ -0,0 +1,3 @@
+locals {
+ vpc_outputs = data.terraform_remote_state.vpc_west_vpc1.outputs
+}
diff --git a/ec2-test-instance/region.tf b/ec2-test-instance/region.tf
new file mode 100644
index 0000000..b7b1696
--- /dev/null
+++ b/ec2-test-instance/region.tf
@@ -0,0 +1,4 @@
+locals {
+ region = var.region
+}
+
diff --git a/ec2-test-instance/settings.auto.tfvars.example b/ec2-test-instance/settings.auto.tfvars.example
new file mode 100644
index 0000000..eba232f
--- /dev/null
+++ b/ec2-test-instance/settings.auto.tfvars.example
@@ -0,0 +1,4 @@
+# vpc_domain_name = "tgw-test-domain"
+enable_instances = true
+enable_bootstrap = false
+instance_count = 1
diff --git a/ec2-test-instance/settings.tf b/ec2-test-instance/settings.tf
new file mode 100644
index 0000000..d18313e
--- /dev/null
+++ b/ec2-test-instance/settings.tf
@@ -0,0 +1,19 @@
+locals {
+ vpc_short_name = local.vpc_outputs.vpc_info["vpc_short_name"]
+
+ private_subnets_ids = local.vpc_outputs.private_subnets_ids
+ private_subnets_id_map = { for v in local.vpc_outputs.private_subnets_ids : v.label => v if length(regexall("endpoints|attachment", v.label)) == 0 }
+ instance_count = var.instance_count == "" || var.instance_count == null ? length(local.private_subnets_id_map) : var.instance_count
+ # private_subnets_id_list = slice(keys(local.private_subnets_id_map), 0, min(local.instance_count, length(local.private_subnets_id_map)))
+ _private_subnets_id_list = [for c in range(1, local.instance_count + 1) : [c, element(keys(local.private_subnets_id_map), c)]]
+ private_subnets_id_list = { for pair in local._private_subnets_id_list : format("%v-%v", pair[1], pair[0]) => { index = pair[0], label = pair[1] } }
+
+ vpc_id = local.vpc_outputs.vpc_id
+ security_groups = tolist(data.aws_security_groups.test.ids)
+
+ ami = data.aws_ami.test_x86.id
+ instance_type = "t3.small"
+ key_name = local.keypair_name
+ root_volume_size = 50
+ ec2_role_name = format("%v-test-ec2-role-%v", local.vpc_short_name, local.region)
+}
diff --git a/ec2-test-instance/systemd/iperf3.service b/ec2-test-instance/systemd/iperf3.service
new file mode 100644
index 0000000..92add00
--- /dev/null
+++ b/ec2-test-instance/systemd/iperf3.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=iperf3 Service
+After=network.target
+
+[Service]
+#Type=simple
+Type=forking
+User=iperf3
+ExecStart=/usr/bin/iperf3 -s -D
+ExecStop=/usr/bin/killall -9 iperf3
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ec2-test-instance/systemd/iperf3@.service b/ec2-test-instance/systemd/iperf3@.service
new file mode 100644
index 0000000..9e53def
--- /dev/null
+++ b/ec2-test-instance/systemd/iperf3@.service
@@ -0,0 +1,20 @@
+[Unit]
+Description=iperf3 Service on port %i
+After=network.target
+
+[Service]
+#Type=simple
+Type=forking
+# User=iperf3
+# PermissionsStartOnly=true
+# ExecStartPre=-/usr/bin/mkdir -p /var/run/iperf3
+E# xecStartPre=/usr/bin/chown iperf3 /var/run/iperf3
+# this -I only works on a newer version of iperf3 (amazon linux2)
+# ExecStart=/usr/bin/iperf3 -s -D -p %i -I /var/run/iperf3/iperf3.%i.pid
+ExecStart=/usr/bin/iperf3 -s -D -p %i
+ExecStop=/usr/bin/kill -KILL $MAINPID
+# PIDFile=/var/run/iperf3/iperf3.%i.pid
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ec2-test-instance/templates/ip-addresses.txt.tpl b/ec2-test-instance/templates/ip-addresses.txt.tpl
new file mode 100644
index 0000000..5ca5edb
--- /dev/null
+++ b/ec2-test-instance/templates/ip-addresses.txt.tpl
@@ -0,0 +1,3 @@
+%{ for k,v in instances ~}
+${v.private_ip}
+%{ endfor ~}
diff --git a/ec2-test-instance/templates/test-ips.txt.tpl b/ec2-test-instance/templates/test-ips.txt.tpl
new file mode 100644
index 0000000..5ca5edb
--- /dev/null
+++ b/ec2-test-instance/templates/test-ips.txt.tpl
@@ -0,0 +1,3 @@
+%{ for k,v in instances ~}
+${v.private_ip}
+%{ endfor ~}
diff --git a/ec2-test-instance/tf-run.data b/ec2-test-instance/tf-run.data
new file mode 100644
index 0000000..3d26174
--- /dev/null
+++ b/ec2-test-instance/tf-run.data
@@ -0,0 +1,23 @@
+VERSION 1.1.3
+REMOTE-STATE
+COMMAND tf-directory-setup.py -l none -f
+COMMAND setup-new-directory.sh
+COMMAND tf-init -upgrade
+null_resource.generate_keypair
+COMMAND tf-directory-setup.py -l s3
+
+COMMAND ln -sf ../variables.vpc.auto.tfvars .
+COMMAND ln -sf ../variables.vpc.tf .
+LINKTOP provider_configs.d/provider.ldap_new.auto.tfvars
+LINKTOP provider_configs.d/provider.ldap_new.tf
+LINKTOP provider_configs.d/provider.ldap_new.variables.tf
+
+ALL
+
+COMMENT echo *-keypair >> .gitignore
+COMMENT git-secret add *-ec2-keypair
+COMMENT git-secret hide
+COMMENT git add *-ec2-keypair.{pub,secret}
+COMMENT git commit -m'add ec2-keypair: *-ec2-keypair' *-ec2-keypair.{pub,secret} .gitignore
+
+
diff --git a/ec2-test-instance/variables.common.availability_zones.tf b/ec2-test-instance/variables.common.availability_zones.tf
new file mode 120000
index 0000000..dca20a3
--- /dev/null
+++ b/ec2-test-instance/variables.common.availability_zones.tf
@@ -0,0 +1 @@
+../common/variables.common.availability_zones.tf
\ No newline at end of file
diff --git a/ec2-test-instance/variables.common.subnet_ids.tf b/ec2-test-instance/variables.common.subnet_ids.tf
new file mode 120000
index 0000000..3d70185
--- /dev/null
+++ b/ec2-test-instance/variables.common.subnet_ids.tf
@@ -0,0 +1 @@
+../common/variables.common.subnet_ids.tf
\ No newline at end of file
diff --git a/ec2-test-instance/variables.common.tf b/ec2-test-instance/variables.common.tf
new file mode 120000
index 0000000..7439ed8
--- /dev/null
+++ b/ec2-test-instance/variables.common.tf
@@ -0,0 +1 @@
+../common/variables.common.tf
\ No newline at end of file
diff --git a/ec2-test-instance/variables.common.vpc.tf b/ec2-test-instance/variables.common.vpc.tf
new file mode 120000
index 0000000..5e77d37
--- /dev/null
+++ b/ec2-test-instance/variables.common.vpc.tf
@@ -0,0 +1 @@
+../common/variables.common.vpc.tf
\ No newline at end of file
diff --git a/ec2-test-instance/variables.common.vpc_id.tf b/ec2-test-instance/variables.common.vpc_id.tf
new file mode 120000
index 0000000..bc2e061
--- /dev/null
+++ b/ec2-test-instance/variables.common.vpc_id.tf
@@ -0,0 +1 @@
+../common/variables.common.vpc_id.tf
\ No newline at end of file
diff --git a/ec2-test-instance/variables.tf b/ec2-test-instance/variables.tf
new file mode 100644
index 0000000..208ce61
--- /dev/null
+++ b/ec2-test-instance/variables.tf
@@ -0,0 +1,24 @@
+variable "enable_instances" {
+ description = "Flag to enable or disable creation of EC2 key and instances"
+ type = bool
+ default = true
+}
+
+variable "enable_bootstrap" {
+ description = "Flag to enable or disable bootstrap (yum and awscli setup)"
+ type = bool
+ default = true
+}
+
+variable "bootstrap_commands" {
+ description = "List of commands to pass to the instance over SSH"
+ type = list(string)
+ default = []
+}
+
+variable "instance_count" {
+ description = "Number to indicate how many instances (up to subnet-count x az-count)"
+ type = number
+ default = null
+}
+
diff --git a/ec2-test-instance/versions.tf b/ec2-test-instance/versions.tf
new file mode 100644
index 0000000..1fe34ba
--- /dev/null
+++ b/ec2-test-instance/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 3.0"
+ }
+ ldap = {
+ source = "trevex/ldap"
+ version = ">= 0.5.4"
+ }
+ }
+ required_version = ">= 0.13"
+}