Convert Exchange to a Terraform module

This commit is contained in:
Chris Long
2021-05-08 15:13:05 -07:00
parent 8c8c7f760c
commit bb41499a27
28 changed files with 112 additions and 85 deletions

5
.gitignore vendored
View File

@@ -8,9 +8,10 @@ Boxes/*
*.tfstate *.tfstate
*.tfstate.* *.tfstate.*
*.tfvars *.tfvars
inventory.yml ESXi/Ansible/inventory.yml
Azure/Ansible/inventory.yml
inventory.yml.bak inventory.yml.bak
**/inventory.yml inventory.yml
*.box *.box
manifest.xml manifest.xml
HyperV/.vagrant/* HyperV/.vagrant/*

View File

@@ -1,3 +0,0 @@
[defaults]
inventory = inventory.yml
host_key_checking = False

View File

@@ -1,6 +0,0 @@
---
- hosts: exchange
roles:
- exchange
- common
tags: exchange

View File

@@ -1 +0,0 @@
../../../../Azure/Ansible/group_vars/all.yml

View File

@@ -1 +0,0 @@
../../../../../Azure/Ansible/roles/common

View File

@@ -1,2 +0,0 @@
[defaults]
inventory = inventory.yml

View File

@@ -1,6 +0,0 @@
---
- hosts: exchange
roles:
- exchange
- common
tags: exchange

View File

@@ -1 +0,0 @@
../../../../../ESXi/Ansible/group_vars/all.yml

View File

@@ -1 +0,0 @@
../../../../../ESXi/Ansible/roles/common

View File

@@ -1,40 +0,0 @@
#########################################
# ESXI Provider host/login details
#########################################
#
# Use of variables here to hide/move the variables to a separate file
#
provider "esxi" {
esxi_hostname = var.esxi_hostname
esxi_hostport = var.esxi_hostport
esxi_username = var.esxi_username
esxi_password = var.esxi_password
}
resource "esxi_guest" "exchange" {
guest_name = "exchange"
disk_store = var.esxi_datastore
guestos = "windows9srv-64"
boot_disk_type = "thin"
memsize = "8192"
numvcpus = "4"
resource_pool_name = "/"
power = "on"
clone_from_vm = "WindowsServer2016"
# This is the network that bridges your host machine with the ESXi VM
network_interfaces {
virtual_network = var.vm_network
mac_address = "00:50:56:a1:b2:c5"
nic_type = "e1000"
}
# This is the local network that will be used for 192.168.38.x addressing
network_interfaces {
virtual_network = var.hostonly_network
mac_address = "00:50:56:a1:b4:c5"
nic_type = "e1000"
}
guest_startup_timeout = 45
guest_shutdown_timeout = 30
}

View File

@@ -1 +0,0 @@
../../../../ESXi/variables.tf

View File

@@ -1 +0,0 @@
../../../Vagrant/resources

View File

@@ -1 +0,0 @@
../../../Vagrant/scripts

View File

@@ -11,3 +11,7 @@ wef:
win10: win10:
hosts: hosts:
z.z.z.z: z.z.z.z:
exchange:
hosts:
# v.v.v.v:

View File

@@ -0,0 +1,10 @@
## Remove the block comment to enable the creation of the Exchange server
/*
module "exchange" {
source = "./modules/exchange"
resource_group_name = azurerm_resource_group.detectionlab.name
region = var.region
subnet_id = azurerm_subnet.detectionlab-subnet.id
}
*/

View File

@@ -1,8 +1,13 @@
# https://github.com/terraform-providers/terraform-provider-azurerm/blob/1940d84dba45e41b2f1f868a22d7f7af1adea8a0/examples/virtual-machines/virtual_machine/vm-joined-to-active-directory/modules/active-directory/2-virtual-machine.tf
locals {
custom_data_content = file("${path.module}/../../files/winrm.ps1")
}
resource "azurerm_virtual_machine" "exchange" { resource "azurerm_virtual_machine" "exchange" {
name = "exchange.windomain.local" name = "exchange.windomain.local"
location = var.region location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name resource_group_name = var.resource_group_name
network_interface_ids = [azurerm_network_interface.exchange-nic[count.index].id] network_interface_ids = [azurerm_network_interface.exchange-nic.id]
vm_size = "Standard_D3_v2" vm_size = "Standard_D3_v2"
delete_os_disk_on_termination = true delete_os_disk_on_termination = true
@@ -39,7 +44,7 @@ resource "azurerm_virtual_machine" "exchange" {
pass = "oobeSystem" pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup" component = "Microsoft-Windows-Shell-Setup"
setting_name = "FirstLogonCommands" setting_name = "FirstLogonCommands"
content = file("${path.module}/files/FirstLogonCommands.xml") content = file("${path.module}/../../files/FirstLogonCommands.xml")
} }
} }
@@ -58,21 +63,21 @@ resource "azurerm_virtual_machine" "exchange" {
resource "azurerm_network_interface" "exchange-nic" { resource "azurerm_network_interface" "exchange-nic" {
name = "exchange-nic" name = "exchange-nic"
location = var.region location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name resource_group_name = var.resource_group_name
ip_configuration { ip_configuration {
name = "myNicConfiguration" name = "myNicConfiguration"
subnet_id = azurerm_subnet.detectionlab-subnet.id subnet_id = var.subnet_id
private_ip_address_allocation = "Static" private_ip_address_allocation = "Static"
private_ip_address = "192.168.38.106" private_ip_address = "192.168.38.106"
public_ip_address_id = azurerm_public_ip.exchange-publicip[count.index].id public_ip_address_id = azurerm_public_ip.exchange-publicip.id
} }
} }
resource "azurerm_public_ip" "exchange-publicip" { resource "azurerm_public_ip" "exchange-publicip" {
name = "exchange-public-ip" name = "exchange-public-ip"
location = var.region location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name resource_group_name = var.resource_group_name
allocation_method = "Static" allocation_method = "Static"
tags = { tags = {

View File

@@ -0,0 +1,11 @@
variable "resource_group_name" {
type = string
}
variable "region" {
type = string
}
variable "subnet_id" {
type = string
}

View File

@@ -24,6 +24,7 @@ TF_OUTPUT=$(terraform output)
DC_IP=$(echo "$TF_OUTPUT" | grep -E -o "dc_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ') DC_IP=$(echo "$TF_OUTPUT" | grep -E -o "dc_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ')
WEF_IP=$(echo "$TF_OUTPUT" | grep -E -o "wef_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ') WEF_IP=$(echo "$TF_OUTPUT" | grep -E -o "wef_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ')
WIN10_IP=$(echo "$TF_OUTPUT" | grep -E -o "win10_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ') WIN10_IP=$(echo "$TF_OUTPUT" | grep -E -o "win10_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ')
EXCHANGE_IP=$(echo "$TF_OUTPUT" | grep -E -o "exchange_public_ip = ([0-9]{1,3}[\.]){3}[0-9]{1,3}" | cut -d '=' -f 2 | tr -d ' ')
# Don't update unless there's default values in inventory.yml # Don't update unless there's default values in inventory.yml
GREP_COUNT=$(grep -E -c 'x\.x\.x\.x|y\.y\.y\.y|z\.z\.z\.z' ../Ansible/inventory.yml) GREP_COUNT=$(grep -E -c 'x\.x\.x\.x|y\.y\.y\.y|z\.z\.z\.z' ../Ansible/inventory.yml)
@@ -37,5 +38,10 @@ fi
echo "Replacing the default values in DetectionLab/Azure/Ansible/inventory.yml..." echo "Replacing the default values in DetectionLab/Azure/Ansible/inventory.yml..."
sed -i.bak "s/x.x.x.x/$DC_IP/g; s/y.y.y.y/$WEF_IP/g; s/z.z.z.z/$WIN10_IP/g" ../Ansible/inventory.yml sed -i.bak "s/x.x.x.x/$DC_IP/g; s/y.y.y.y/$WEF_IP/g; s/z.z.z.z/$WIN10_IP/g" ../Ansible/inventory.yml
if [ ! -e "$EXCHANGE_IP" ]; then
echo "Exchange server found! Adding the IP to the Ansible inventory..."
sed -i.bak "s/# v.v.v.v/$EXCHANGE_IP/g" ../Ansible/inventory.yml
fi
echo "Displaying the updated inventory.yml below!" echo "Displaying the updated inventory.yml below!"
cat ../Ansible/inventory.yml cat ../Ansible/inventory.yml

View File

@@ -16,6 +16,12 @@
- common - common
tags: wef tags: wef
- hosts: exchange
roles:
- exchange
- common
tags: exchange
- hosts: win10 - hosts: win10
roles: roles:
- win10 - win10

9
ESXi/exchange.tf Normal file
View File

@@ -0,0 +1,9 @@
## Remove the block comment to enable the creation of the Exchange server
/*
module "exchange" {
source = "./modules/exchange"
disk_store = var.esxi_datastore
vm_network = var.vm_network
hostonly_network = var.hostonly_network
}
*/

View File

@@ -7,3 +7,31 @@ terraform {
} }
} }
} }
resource "esxi_guest" "exchange" {
guest_name = "exchange"
disk_store = var.disk_store
guestos = "windows9srv-64"
boot_disk_type = "thin"
memsize = "8192"
numvcpus = "4"
resource_pool_name = "/"
power = "on"
clone_from_vm = "WindowsServer2016"
# This is the network that bridges your host machine with the ESXi VM
network_interfaces {
virtual_network = var.vm_network
mac_address = "00:50:56:a1:b2:c5"
nic_type = "e1000"
}
# This is the local network that will be used for 192.168.38.x addressing
network_interfaces {
virtual_network = var.hostonly_network
mac_address = "00:50:56:a1:b4:c5"
nic_type = "e1000"
}
guest_startup_timeout = 45
guest_shutdown_timeout = 30
}

View File

@@ -0,0 +1,11 @@
variable "vm_network" {
default = "VM Network"
}
variable "hostonly_network" {
default = "HostOnly Network"
}
variable "disk_store" {
type = string
}

View File

@@ -8,20 +8,20 @@
cfg.winrm.retry_limit = 20 cfg.winrm.retry_limit = 20
cfg.vm.network :private_network, ip: "192.168.38.106", gateway: "192.168.38.1", dns: "192.168.38.102" cfg.vm.network :private_network, ip: "192.168.38.106", gateway: "192.168.38.1", dns: "192.168.38.102"
cfg.vm.provision "shell", path: "scripts/fix-second-network.ps1", privileged: true, args: "-ip 192.168.38.106 -dns 8.8.8.8 -gateway 192.168.38.1" cfg.vm.provision "shell", path: "../scripts/fix-second-network.ps1", privileged: true, args: "-ip 192.168.38.106 -dns 8.8.8.8 -gateway 192.168.38.1"
cfg.vm.provision "shell", path: "scripts/provision.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/provision.ps1", privileged: false
cfg.vm.provision "reload" cfg.vm.provision "reload"
cfg.vm.provision "shell", path: "scripts/provision.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/provision.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/download_palantir_wef.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/download_palantir_wef.ps1", privileged: false
cfg.vm.provision "shell", inline: 'wevtutil el | Select-String -notmatch "Microsoft-Windows-LiveId" | Foreach-Object {wevtutil cl "$_"}', privileged: false cfg.vm.provision "shell", inline: 'wevtutil el | Select-String -notmatch "Microsoft-Windows-LiveId" | Foreach-Object {wevtutil cl "$_"}', privileged: false
cfg.vm.provision "shell", path: "scripts/install-splunkuf.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-splunkuf.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-windows_ta.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-windows_ta.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-utilities.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-utilities.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-redteam.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-redteam.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-choco-extras.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-choco-extras.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-osquery.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-osquery.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-sysinternals.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-sysinternals.ps1", privileged: false
cfg.vm.provision "shell", path: "scripts/install-velociraptor.ps1", privileged: false cfg.vm.provision "shell", path: "../scripts/install-velociraptor.ps1", privileged: false
cfg.vm.provision "shell", inline: "Set-SmbServerConfiguration -AuditSmb1Access $true -Force", privileged: false cfg.vm.provision "shell", inline: "Set-SmbServerConfiguration -AuditSmb1Access $true -Force", privileged: false
cfg.vm.provision "shell", inline: 'cscript c:\windows\system32\slmgr.vbs /dlv', privileged: false cfg.vm.provision "shell", inline: 'cscript c:\windows\system32\slmgr.vbs /dlv', privileged: false