Files
DetectionLab/Azure/Terraform/main.tf
2021-05-05 21:40:48 -07:00

538 lines
18 KiB
HCL

# terraform init, plan, apply, destroy
# Note: does not support idempotence, don't execute twice with same scope.
# https://www.terraform.io/docs/providers/azurerm/index.html
# latest test: terraform 0.12.18
#
# FIXME!
# * apply: provisioning not working on Windows
# Error: Unsupported argument [...] An argument named "connection" is not expected here.
# apply => Error: timeout - last error: SSH authentication failed (root@:22): ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
# * apply: linux provisioning
# => works but script ends with error code for some reason (post bro install and splunk restart)
# Specify the provider and access details
provider "azurerm" {
version = "=2.12.0"
features {}
}
# 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_resource_group" "detectionlab" {
name = "DetectionLab-terraform"
location = var.region
}
resource "azurerm_virtual_network" "detectionlab-network" {
name = "DetectionLab-vnet"
address_space = ["192.168.0.0/16"]
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
}
# Create a subnet to launch our instances into
resource "azurerm_subnet" "detectionlab-subnet" {
name = "DetectionLab-Subnet"
resource_group_name = azurerm_resource_group.detectionlab.name
virtual_network_name = azurerm_virtual_network.detectionlab-network.name
address_prefixes = ["192.168.38.0/24"]
}
resource "azurerm_network_security_group" "detectionlab-nsg" {
name = "DetectionLab-nsg"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
# SSH access
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
# source_address_prefix = "*"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# Splunk access
security_rule {
name = "Splunk"
priority = 1002
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "8000"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# Fleet access
security_rule {
name = "Fleet"
priority = 1003
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "8412"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# RDP
security_rule {
name = "RDP"
priority = 1004
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# WinRM
security_rule {
name = "WinRM"
priority = 1005
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5985-5986"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# Windows ATA
security_rule {
name = "WindowsATA"
priority = 1006
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# Allow all traffic from the private subnet
security_rule {
name = "PrivateSubnet"
priority = 1007
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "192.168.38.0/24"
destination_address_prefix = "*"
}
# Guacamole access
security_rule {
name = "Guacamole"
priority = 1008
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "8080"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
# Velociraptor access
security_rule {
name = "Velociraptor"
priority = 1009
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "9999"
source_address_prefixes = var.ip_whitelist
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "detectionlab-nsga" {
subnet_id = azurerm_subnet.detectionlab-subnet.id
network_security_group_id = azurerm_network_security_group.detectionlab-nsg.id
}
resource "azurerm_public_ip" "logger-publicip" {
name = "logger-public-ip"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
allocation_method = "Static"
tags = {
role = "logger"
}
}
resource "azurerm_network_interface" "logger-nic" {
name = "logger-nic"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
ip_configuration {
name = "logger-NicConfiguration"
subnet_id = azurerm_subnet.detectionlab-subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "192.168.38.105"
public_ip_address_id = azurerm_public_ip.logger-publicip.id
}
}
# Storage
resource "random_id" "randomId" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group_name = azurerm_resource_group.detectionlab.name
}
byte_length = 8
}
resource "azurerm_storage_account" "detectionlab-storageaccount" {
name = "diag${random_id.randomId.hex}"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
account_replication_type = "LRS"
account_tier = "Standard"
}
# Linux VM
resource "azurerm_virtual_machine" "logger" {
name = "logger"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
network_interface_ids = [azurerm_network_interface.logger-nic.id]
vm_size = "Standard_D1_v2"
delete_os_disk_on_termination = true
storage_os_disk {
name = "OsDiskLogger"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
os_profile {
computer_name = "logger"
admin_username = "vagrant"
admin_password = "vagrant"
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/vagrant/.ssh/authorized_keys"
key_data = file(var.public_key_path)
}
}
boot_diagnostics {
enabled = "true"
storage_uri = azurerm_storage_account.detectionlab-storageaccount.primary_blob_endpoint
}
# Provision
# https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/examples/virtual-machines/provisioners/linux/main.tf
# https://www.terraform.io/docs/provisioners/connection.html
provisioner "remote-exec" {
connection {
host = azurerm_public_ip.logger-publicip.ip_address
user = "vagrant"
private_key = file(var.private_key_path)
}
inline = [
"sudo add-apt-repository universe && sudo apt-get -qq update && sudo apt-get -qq install -y git",
"sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config && sudo service ssh restart",
"echo 'logger' | sudo tee /etc/hostname && sudo hostnamectl set-hostname logger",
"sudo adduser --disabled-password --gecos \"\" vagrant && echo 'vagrant:vagrant' | sudo chpasswd",
"echo 'vagrant:vagrant' | sudo chpasswd",
"sudo mkdir /home/vagrant/.ssh && sudo cp /home/ubuntu/.ssh/authorized_keys /home/vagrant/.ssh/authorized_keys && sudo chown -R vagrant:vagrant /home/vagrant/.ssh",
"echo 'vagrant ALL=(ALL:ALL) NOPASSWD:ALL' | sudo tee -a /etc/sudoers",
"sudo git clone https://github.com/clong/DetectionLab.git /opt/DetectionLab",
"sudo sed -i 's/eth1/eth0/g' /opt/DetectionLab/Vagrant/logger_bootstrap.sh",
"sudo sed -i 's/ETH1/ETH0/g' /opt/DetectionLab/Vagrant/logger_bootstrap.sh",
"sudo sed -i 's#/usr/local/go/bin/go get -u#GOPATH=/root/go /usr/local/go/bin/go get -u#g' /opt/DetectionLab/Vagrant/logger_bootstrap.sh",
"sudo sed -i 's#/vagrant/resources#/opt/DetectionLab/Vagrant/resources#g' /opt/DetectionLab/Vagrant/logger_bootstrap.sh",
"sudo chmod +x /opt/DetectionLab/Vagrant/logger_bootstrap.sh",
"sudo apt-get -qq update",
"sudo /opt/DetectionLab/Vagrant/logger_bootstrap.sh 2>&1 |sudo tee /opt/DetectionLab/Vagrant/bootstrap.log",
]
}
tags = {
role = "logger"
}
}
# https://github.com/terraform-providers/terraform-provider-azurerm/tree/master/examples/virtual-machines/vm-joined-to-active-directory
# Windows VM
resource "azurerm_network_interface" "dc-nic" {
name = "dc-nic"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
ip_configuration {
name = "DC-NicConfiguration"
subnet_id = azurerm_subnet.detectionlab-subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "192.168.38.102"
public_ip_address_id = azurerm_public_ip.dc-publicip.id
}
}
resource "azurerm_public_ip" "dc-publicip" {
name = "dc-public-ip"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
allocation_method = "Static"
tags = {
role = "dc"
}
}
resource "azurerm_network_interface" "wef-nic" {
name = "wef-nic"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
ip_configuration {
name = "WEF-NicConfiguration"
subnet_id = azurerm_subnet.detectionlab-subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "192.168.38.103"
public_ip_address_id = azurerm_public_ip.wef-publicip.id
}
}
resource "azurerm_public_ip" "wef-publicip" {
name = "wef-public-ip"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
allocation_method = "Static"
tags = {
role = "wef"
}
}
resource "azurerm_network_interface" "win10-nic" {
name = "win10-nic"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
ip_configuration {
name = "myNicConfiguration"
subnet_id = azurerm_subnet.detectionlab-subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "192.168.38.104"
public_ip_address_id = azurerm_public_ip.win10-publicip.id
}
}
resource "azurerm_public_ip" "win10-publicip" {
name = "win10-public-ip"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
allocation_method = "Static"
tags = {
role = "win10"
}
}
resource "azurerm_virtual_machine" "dc" {
name = "dc.windomain.local"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
network_interface_ids = [azurerm_network_interface.dc-nic.id]
vm_size = "Standard_D1_v2"
delete_os_disk_on_termination = true
storage_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
os_profile {
computer_name = "dc"
admin_username = "vagrant"
admin_password = "Vagrant123"
custom_data = local.custom_data_content
}
os_profile_windows_config {
provision_vm_agent = true
enable_automatic_upgrades = false
# Auto-Login's required to configure WinRM
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "AutoLogon"
content = "<AutoLogon><Password><Value>Vagrant123</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>vagrant</Username></AutoLogon>"
}
# Unattend config is to enable basic auth in WinRM, required for the provisioner stage.
# https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/examples/virtual-machines/provisioners/windows/files/FirstLogonCommands.xml
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "FirstLogonCommands"
content = file("${path.module}/files/FirstLogonCommands.xml")
}
}
storage_os_disk {
name = "OsDiskDc"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
tags = {
role = "dc"
}
}
resource "azurerm_virtual_machine" "wef" {
name = "wef.windomain.local"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
network_interface_ids = [azurerm_network_interface.wef-nic.id]
vm_size = "Standard_D1_v2"
delete_os_disk_on_termination = true
storage_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
os_profile {
computer_name = "wef"
admin_username = "vagrant"
admin_password = "Vagrant123"
custom_data = local.custom_data_content
}
os_profile_windows_config {
provision_vm_agent = true
enable_automatic_upgrades = false
# Auto-Login's required to configure WinRM
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "AutoLogon"
content = "<AutoLogon><Password><Value>Vagrant123</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>vagrant</Username></AutoLogon>"
}
# Unattend config is to enable basic auth in WinRM, required for the provisioner stage.
# https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/examples/virtual-machines/provisioners/windows/files/FirstLogonCommands.xml
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "FirstLogonCommands"
content = file("${path.module}/files/FirstLogonCommands.xml")
}
}
storage_os_disk {
name = "OsDiskWef"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
tags = {
role = "wef"
}
}
resource "azurerm_virtual_machine" "win10" {
name = "win10.windomain.local"
location = var.region
resource_group_name = azurerm_resource_group.detectionlab.name
network_interface_ids = [azurerm_network_interface.win10-nic.id]
vm_size = "Standard_D1_v2"
delete_os_disk_on_termination = true
storage_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "Windows-10"
sku = "19h1-pron"
version = "latest"
}
os_profile {
computer_name = "win10"
admin_username = "vagrant"
admin_password = "Vagrant123"
custom_data = local.custom_data_content
}
os_profile_windows_config {
provision_vm_agent = true
enable_automatic_upgrades = false
# Auto-Login's required to configure WinRM
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "AutoLogon"
content = "<AutoLogon><Password><Value>Vagrant123</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>vagrant</Username></AutoLogon>"
}
# Unattend config is to enable basic auth in WinRM, required for the provisioner stage.
# https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/examples/virtual-machines/provisioners/windows/files/FirstLogonCommands.xml
additional_unattend_config {
pass = "oobeSystem"
component = "Microsoft-Windows-Shell-Setup"
setting_name = "FirstLogonCommands"
content = file("${path.module}/files/FirstLogonCommands.xml")
}
}
storage_os_disk {
name = "OsDiskWin10"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
tags = {
role = "win10"
}
}