diff --git a/.gitignore b/.gitignore index 676663f..a744ddf 100755 --- a/.gitignore +++ b/.gitignore @@ -4,17 +4,7 @@ Packer/packer_cache/* Packer/packer_build.log Boxes/* .DS_Store -Terraform/*/*.tfstate -Terraform/*/.terraform -Terraform/*/*.tfvars -Terraform/*/*.lock.info -Terraform/*/*.backup -Terraform/*.tfstate -Terraform/*.terraform -Terraform/*.tfvars -Terraform/*.lock.info -Terraform/*.backup -ESXi/.terraform/* -ESXi/*.tfstate -ESXi/*.backup -ESXi/*.tfvars +**/.terraform/* +*.tfstate +*.tfstate.* +*.tfvars diff --git a/Terraform/Pre-Built_AMIs.md b/AWS/Terraform/Pre-Built_AMIs.md similarity index 100% rename from Terraform/Pre-Built_AMIs.md rename to AWS/Terraform/Pre-Built_AMIs.md diff --git a/Terraform/README.md b/AWS/Terraform/README.md similarity index 100% rename from Terraform/README.md rename to AWS/Terraform/README.md diff --git a/Terraform/VM_to_AMIs.md b/AWS/Terraform/VM_to_AMIs.md similarity index 100% rename from Terraform/VM_to_AMIs.md rename to AWS/Terraform/VM_to_AMIs.md diff --git a/Terraform/locals.tf b/AWS/Terraform/locals.tf similarity index 100% rename from Terraform/locals.tf rename to AWS/Terraform/locals.tf diff --git a/Terraform/main.tf b/AWS/Terraform/main.tf similarity index 100% rename from Terraform/main.tf rename to AWS/Terraform/main.tf diff --git a/Terraform/outputs.tf b/AWS/Terraform/outputs.tf similarity index 100% rename from Terraform/outputs.tf rename to AWS/Terraform/outputs.tf diff --git a/Terraform/terraform.tfvars.example b/AWS/Terraform/terraform.tfvars.example similarity index 100% rename from Terraform/terraform.tfvars.example rename to AWS/Terraform/terraform.tfvars.example diff --git a/Terraform/variables.tf b/AWS/Terraform/variables.tf similarity index 100% rename from Terraform/variables.tf rename to AWS/Terraform/variables.tf diff --git a/Terraform/versions.tf b/AWS/Terraform/versions.tf similarity index 100% rename from Terraform/versions.tf rename to AWS/Terraform/versions.tf diff --git a/Terraform/vm_import/dc.json b/AWS/Terraform/vm_import/dc.json similarity index 100% rename from Terraform/vm_import/dc.json rename to AWS/Terraform/vm_import/dc.json diff --git a/Terraform/vm_import/role-policy.json b/AWS/Terraform/vm_import/role-policy.json similarity index 100% rename from Terraform/vm_import/role-policy.json rename to AWS/Terraform/vm_import/role-policy.json diff --git a/Terraform/vm_import/trust-policy.json b/AWS/Terraform/vm_import/trust-policy.json similarity index 100% rename from Terraform/vm_import/trust-policy.json rename to AWS/Terraform/vm_import/trust-policy.json diff --git a/Terraform/vm_import/wef.json b/AWS/Terraform/vm_import/wef.json similarity index 100% rename from Terraform/vm_import/wef.json rename to AWS/Terraform/vm_import/wef.json diff --git a/Terraform/vm_import/win10.json b/AWS/Terraform/vm_import/win10.json similarity index 100% rename from Terraform/vm_import/win10.json rename to AWS/Terraform/vm_import/win10.json diff --git a/Azure/Ansible/ansible.cfg b/Azure/Ansible/ansible.cfg new file mode 100644 index 0000000..bcbfb98 --- /dev/null +++ b/Azure/Ansible/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +inventory = inventory.yml +host_key_checking = False diff --git a/Azure/Ansible/detectionlab.yml b/Azure/Ansible/detectionlab.yml new file mode 100644 index 0000000..c6ee0d4 --- /dev/null +++ b/Azure/Ansible/detectionlab.yml @@ -0,0 +1,18 @@ +--- +- hosts: dc + roles: + - dc + - common + tags: dc + +- hosts: wef + roles: + - wef + - common + tags: wef + +- hosts: win10 + roles: + - win10 + - common + tags: win10 diff --git a/Azure/Ansible/group_vars/all.yml b/Azure/Ansible/group_vars/all.yml new file mode 100644 index 0000000..8a021b0 --- /dev/null +++ b/Azure/Ansible/group_vars/all.yml @@ -0,0 +1,6 @@ +ansible_user: vagrant +ansible_password: Vagrant123 +ansible_port: 5985 +ansible_connection: winrm +ansible_winrm_transport: basic +ansible_winrm_server_cert_validation: ignore diff --git a/Azure/Ansible/group_vars/linux.yml b/Azure/Ansible/group_vars/linux.yml new file mode 100644 index 0000000..57418b3 --- /dev/null +++ b/Azure/Ansible/group_vars/linux.yml @@ -0,0 +1,4 @@ +ansible_user: vagrant +ansible_password: vagrant +ansible_port: 22 +ansible_connection: ssh diff --git a/Azure/Ansible/inventory.yml b/Azure/Ansible/inventory.yml new file mode 100644 index 0000000..e63c81f --- /dev/null +++ b/Azure/Ansible/inventory.yml @@ -0,0 +1,14 @@ +--- +# Replace the x's with the IP addresses from "terrafrom output" +dc: + hosts: + x.x.x.x: + +wef: + hosts: + x.x.x.x: + +win10: + hosts: + x.x.x.x: + diff --git a/Azure/Ansible/roles/common/tasks/main.yml b/Azure/Ansible/roles/common/tasks/main.yml new file mode 100644 index 0000000..ca2d650 --- /dev/null +++ b/Azure/Ansible/roles/common/tasks/main.yml @@ -0,0 +1,76 @@ +--- + +- name: Downloading the Palantir WEF Configuration + win_shell: ".\\download_palantir_wef.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: palantir_wef + failed_when: "'Exception' in palantir_wef.stdout" + +- debug: msg="{{ palantir_wef.stdout_lines }}" + +- name: Downloading the Palantir osquery Configuration + win_shell: ".\\download_palantir_osquery.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: palantir_osquery + failed_when: "'Exception' in palantir_osquery.stdout" + +- debug: msg="{{ palantir_osquery.stdout_lines }}" + +- name: Installing osquery + win_shell: ".\\install-osquery.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: install_osquery + failed_when: "'Exception' in install_osquery.stdout" + +- debug: msg="{{ install_osquery.stdout_lines }}" + +- name: Installing SysInternals Tools + win_shell: ".\\install-sysinternals.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: sysinternals + failed_when: "'Exception' in sysinternals.stdout" + +- debug: msg="{{ sysinternals.stdout_lines }}" + +- name: Installing AutorunsToWineventlog + win_shell: ".\\install-autorunstowineventlog.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: autorunstowineventlog + failed_when: "'Exception' in autorunstowineventlog.stdout" + +- debug: msg="{{ autorunstowineventlog.stdout_lines }}" + +- name: Installing Red Team Tooling + win_shell: ".\\install-redteam.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: redteam + failed_when: "'Exception' in redteam.stdout" + +- debug: msg="{{ redteam.stdout_lines }}" + +- name: Install Utilities + win_chocolatey: + name: + - NotepadPlusPlus + - GoogleChrome + - WinRar + - wireshark + - winpcap + state: present + +- name: Install classic-shell with chocolatey + win_chocolatey: + name: + - classic-shell + state: present + install_args: "ADDLOCAL=ClassicStartMenu" + + + + diff --git a/Azure/Ansible/roles/dc/tasks/main.yml b/Azure/Ansible/roles/dc/tasks/main.yml new file mode 100644 index 0000000..d752629 --- /dev/null +++ b/Azure/Ansible/roles/dc/tasks/main.yml @@ -0,0 +1,144 @@ +--- + +- name: Set DNS Address + win_shell: "Set-DnsClientServerAddress -InterfaceAlias Ethernet -ServerAddresses 127.0.0.1,8.8.8.8" + +- name: Install git + win_chocolatey: + name: git + state: present + +- name: Check if existing DetectionLab directory + win_stat: + path: 'c:\DetectionLab' + register: dir + +- name: Git clone Detectionlab + win_shell: git clone https://github.com/clong/DetectionLab.git + args: + chdir: 'c:\' + when: not dir.stat.exists + +- name: Copy scripts to c:\vagrant + win_shell: Copy-Item -Recurse c:\DetectionLab\Vagrant c:\vagrant + +- name: Create an Administrator user + win_user: + name: Administrator + password: Vagrant123 + state: present + groups: + - Users,Administrators + password_never_expires: yes + +- name: Create the Domain + win_shell: .\\provision.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: domain_creation + changed_when: "'Status : Success' in domain_creation.stdout" + +- name: Reboot Afer Domain Creation + win_reboot: + msg: "Installing AD. Rebooting..." + pre_reboot_delay: 15 + reboot_timeout: 600 + post_reboot_delay: 60 + +- name: Configure OU + win_shell: .\\configure-ou.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: ou_creation + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in ou_creation.stderr" + +- debug: msg="{{ ou_creation.stdout_lines }}" + +- name: Configure WEF GPO + win_shell: .\\configure-wef-gpo.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: wef_gpo + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in wef_gpo.stderr" + +- debug: msg="{{ wef_gpo.stdout_lines }}" + +- name: Configure Powershell Logging GPO + win_shell: .\\configure-powershelllogging.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: powershell_gpo + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in powershell_gpo.stderr" + +- debug: msg="{{ powershell_gpo.stdout_lines }}" + +- name: Configure Auditing Policy GPO + win_shell: .\\configure-AuditingPolicyGPOs.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: audit_policy + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in audit_policy.stderr" + +- debug: msg="{{ audit_policy.stdout_lines }}" + +- name: Disable Windows Defender GPO + win_shell: .\\configure-disable-windows-defender-gpo.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: disable_win_def + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in disable_win_def.stderr" + +- debug: msg="{{ disable_win_def.stdout_lines }}" + +- name: Configure RDP Permissions GPO + win_shell: .\\configure-rdp-user-gpo.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: rdp_gpo + vars: + ansible_become: yes + ansible_become_method: runas + ansible_become_user: windomain.local\vagrant + ansible_become_password: vagrant + ansible_become_flags: logon_type=new_credentials logon_flags=netcredentials_only + failed_when: "'Exception' in rdp_gpo.stderr" + +- debug: msg="{{ rdp_gpo.stdout_lines }}" + +- name: Configure DC with raw Commands + win_shell: "{{ item }}" + with_items: + - "wevtutil el | Select-String -notmatch \"Microsoft-Windows-LiveId\" | Foreach-Object {wevtutil cl \"$_\"}" + - "Set-SmbServerConfiguration -AuditSmb1Access $true -Force" + + diff --git a/Azure/Ansible/roles/wef/tasks/main.yml b/Azure/Ansible/roles/wef/tasks/main.yml new file mode 100644 index 0000000..f078252 --- /dev/null +++ b/Azure/Ansible/roles/wef/tasks/main.yml @@ -0,0 +1,136 @@ +--- + +# This needs to be made idempodent +- name: Set HostOnly DNS Address + win_shell: "Set-DnsClientServerAddress -InterfaceAlias Ethernet -ServerAddresses 192.168.38.102,8.8.8.8" + +- name: Install git + win_chocolatey: + name: git + state: present + +- name: Check if existing DetectionLab directory + win_stat: + path: 'c:\DetectionLab' + register: dir + +- name: Git clone Detectionlab + win_shell: git clone https://github.com/clong/DetectionLab.git + args: + chdir: 'c:\' + when: not dir.stat.exists + +- name: Copy scripts to c:\vagrant + win_shell: Copy-Item -Recurse c:\DetectionLab\Vagrant c:\vagrant + +- name: Join the Domain + win_shell: .\\provision.ps1 + args: + chdir: 'c:\vagrant\scripts' + register: wef_join_domain + changed_when: "'HasSucceeded : True' in wef_join_domain.stdout" + +- debug: msg="{{ wef_join_domain.stdout_lines }}" + +- name: Reboot After Joining the Domain + win_reboot: + msg: "Joining the domain. Rebooting..." + pre_reboot_delay: 15 + reboot_timeout: 600 + post_reboot_delay: 60 + +- name: Download Microsoft ATA + win_get_url: + url: http://download.microsoft.com/download/4/9/1/491394D1-3F28-4261-ABC6-C836A301290E/ATA1.9.iso + dest: "C:\\Users\\vagrant\\AppData\\Local\\Temp\\Microsoft ATA 1.9.iso" + timeout: 3600 + +- name: Clear Event Logs + win_shell: "wevtutil el | Select-String -notmatch \"Microsoft-Windows-LiveId\" | Foreach-Object {wevtutil cl \"$_\"}" + +- name: Downloading the Palantir WEF Configuration + win_shell: ".\\download_palantir_wef.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: palantir_wef + failed_when: "'Exception' in palantir_wef.stdout" + +- debug: msg="{{ palantir_wef.stdout_lines }}" + +- name: Installing WEF Subscriptions + win_shell: ".\\install-wefsubscriptions.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: wef_subscriptions + failed_when: "'Exception' in wef_subscriptions.stdout" + +- debug: msg="{{ wef_subscriptions.stdout_lines }}" + +- name: Installing the Splunk Universal Forwarder + win_shell: ".\\install-splunkuf.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: splunkuf + failed_when: "'Exception' in splunkuf.stdout" + +- debug: msg="{{ splunkuf.stdout_lines }}" + +- name: Install Splunk Windows TA + win_shell: ".\\install-windows_ta.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: windowsta + failed_when: "'Exception' in windowsta.stdout" + +- debug: msg="{{ windowsta.stdout_lines }}" + +- name: Installing the Powershell Log Transcription Share + win_shell: ".\\configure-pslogstranscriptsshare.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: pstranscriptshare + failed_when: "'Exception' in pstranscriptshare.stdout" + +- debug: msg="{{ pstranscriptshare.stdout_lines }}" + +- name: Installing Microsoft Advanced Threat Analytics + win_shell: ".\\install-microsoft-ata.ps1" + args: + chdir: 'c:\vagrant\scripts' + register: windowsata + failed_when: "'Exception' in windowsata.stdout" + +- debug: msg="{{ windowsata.stdout_lines }}" + +- name: Configure WEF with raw Commands + win_shell: "{{ item }}" + with_items: + - "wevtutil el | Select-String -notmatch \"Microsoft-Windows-LiveId\" | Foreach-Object {wevtutil cl \"$_\"}" + - "Set-SmbServerConfiguration -AuditSmb1Access $true -Force" + +- name: Disable password complexity policy + win_shell: | + secedit /export /cfg C:\secpol.cfg + (gc C:\secpol.cfg).replace("PasswordComplexity = 1", "PasswordComplexity = 0") | Out-File C:\secpol.cfg + secedit /configure /db C:\Windows\security\local.sdb /cfg C:\secpol.cfg /areas SECURITYPOLICY + rm -force C:\secpol.cfg -confirm:$false + become: yes + become_method: enable + +- name: Add Ansible user + win_user: + name: ansible + password: Ansible123 + groups: + - Administrators + +- name: Switch to Ansible user + set_fact: + ansible_user: ansible + ansible_password: Ansible123 + +- name: Change password for vagrant account back to vagrant + win_user: + name: vagrant + password: vagrant + diff --git a/Azure/Ansible/roles/win10/tasks/main.yml b/Azure/Ansible/roles/win10/tasks/main.yml new file mode 100644 index 0000000..f58931b --- /dev/null +++ b/Azure/Ansible/roles/win10/tasks/main.yml @@ -0,0 +1,80 @@ +--- +- name: Set HostOnly DNS Address + win_shell: "Set-DnsClientServerAddress -InterfaceAlias Ethernet -ServerAddresses 192.168.38.102,8.8.8.8" + +- name: Install git + win_chocolatey: + name: git + state: present + +- name: Check if existing DetectionLab directory + win_stat: + path: 'c:\DetectionLab' + register: dir + +- name: Git clone Detectionlab + win_shell: git clone https://github.com/clong/DetectionLab.git + args: + chdir: 'c:\' + when: not dir.stat.exists + +- name: Copy scripts to c:\vagrant + win_shell: Copy-Item -Recurse c:\DetectionLab\Vagrant c:\vagrant + +- name: Making Windows10 Great Again + win_shell: .\\MakeWindows10GreatAgain.ps1 + args: + chdir: 'c:\vagrant\scripts' + +- name: Join the Domain + win_shell: .\\provision.ps1 + args: + chdir: 'c:\vagrant\scripts' + +- name: Update group policy + win_shell: "gpupdate /force" + +- name: Reboot Server + win_reboot: + msg: "Joined the domain. Rebooting..." + pre_reboot_delay: 15 + reboot_timeout: 600 + post_reboot_delay: 60 + +- name: Clear Event Logs + win_shell: "wevtutil el | Select-String -notmatch \"Microsoft-Windows-LiveId\" | Foreach-Object {wevtutil cl \"$_\"}" + +- name: DetectionLab Menu + win_shell: | + "\"C:\\Program Files\\Classic Shell\\ClassicStartMenu.exe -xml c:\\vagrant\\resources\\windows\\MenuSettings.xml\"" + regedit /s c:\vagrant\resources\windows\MenuStyle_Default_Win7.reg + +- name: Disable password complexity policy + win_shell: | + secedit /export /cfg C:\secpol.cfg + (gc C:\secpol.cfg).replace("PasswordComplexity = 1", "PasswordComplexity = 0") | Out-File C:\secpol.cfg + secedit /configure /db C:\Windows\security\local.sdb /cfg C:\secpol.cfg /areas SECURITYPOLICY + rm -force C:\secpol.cfg -confirm:$false + become: yes + become_method: enable + +- name: Add Ansible user + win_user: + name: ansible + password: Ansible123 + groups: + - Administrators + +- name: Switch to Ansible user + set_fact: + ansible_user: ansible + ansible_password: Ansible123 + +- name: Change password for vagrant account back to vagrant + win_user: + name: vagrant + password: vagrant + + + + diff --git a/Azure/README.md b/Azure/README.md new file mode 100644 index 0000000..8ae2140 --- /dev/null +++ b/Azure/README.md @@ -0,0 +1,100 @@ +# Building DetectionLab on Azure + +NOTE: This is an early release and it's possible that certain features may not work perfectly for everyone yet + +## Prereqs (~30-60 minutes) +0. Have an active [Azure account](https://azure.microsoft.com/en-us/free/). If you don't have one yet, they give you $200 worth of credit to use within the first 30 days! +1. [Install Terraform](https://www.terraform.io/downloads.html) and move it to a directory included in your system's PATH. +2. [Install Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html). This will be used to provision the instances. Some users may prefer to install Ansible inside of a virtual environment; that's fine too. +3. [Install the Azure command line client](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and make sure it's included in your system's PATH. +4. Either create or re-use an existing SSH keypair that you'll use to authenticate to the logger host +5. Make sure you've pulled down the most recent changes from the DetectionLab git repo +6. Please note that the default credentials before provisioning are `vagrant:Vagrant123` due to the windows SKU/AMI password complexity requirements! + +## Steps +### Terraform +1. **(5 Minutes)** - Configure the `terraform.tfvars` file + 1. Copy the file at `/DetectionLab/Azure/Terraform/terraform.tfvars.example` to `/DetectionLab/Azure/Terraform/terraform.tfvars` + 2. In the newly copied terraform.tfvars, provide a value for each variable. + +2. **(5 Minutes)** - Authenticate to Azure using `az` + 1. Run `az login`. This should bring up a browser that asks you to sign into your Azure account. + 2. Sign in and the window should say "You have logged into Microsoft Azure!" + +3. **(3-20 Minutes)** - Bring up the VM's using Terraform + 1. `cd` to `Azure/Terraform` and run `terraform init` to initialize the working directory + 2. Make sure you followed the pre-reqs and have a `terraform.tfvars` file present with your public IP address whitelisted + 3. Run `terraform apply` to check the Terraform plan or `terraform apply --auto-approve` to bypass the check + 4. It will take ~20 minutes for logger to come online and finish provisioning, but **you can move onto the next step once you see that DC, WEF, and WIN10 have fininshed creation** (usually around 2 minutes): + ``` + azurerm_virtual_machine.dc: Creation complete after 1m55s + azurerm_virtual_machine.wef: Creation complete after 1m54s + azurerm_virtual_machine.win10: Creation complete after 1m55s + ``` + +At this point in time, we're at this state: +* Logger VM has been brought up and is provisioning +* DC VM has been brought up but is unprovisioned +* DC VM has been brought up but is unprovisioned +* DC VM has been brought up but is unprovisioned + +At this point in time, you should be able to open a new terminal window, navigate to `DetectionLab/Azure/Terraform` and run `terraform output`. You should see something like the following: +``` +ata_url = https://52.191.136.x +dc_public_ip = 52.183.119.x +fleet_url = https://52.191.170.x:8412 +guacamole_url = https://52.191.136.x:8080/guacamole +logger_public_ip = 52.191.170.x +region = West US 2 +splunk_url = https://52.191.170.x:8000 +wef_public_ip = 52.191.136.x +win10_public_ip = 52.229.34.x +``` + +We're going to use this output in the next step. + +--- +### Ansible +We're going to use Ansible to fininsh provisioning the rest of the Windows hosts. + +1. **(5 Minutes)** - Configure the `inventory.yml` file + 1. Navigate to `Azure/Ansible` and open `inventory.yml` for editing. + 2. Take the `public_ip` values from `terraform output` and replace the `x.x.x.x` values with the public IP of each host + +Now that Ansible is configured for provisioning, there are two ways to go about this: + +* Provision each host one at a time (e.g. DC, then WEF, then WIN10). This is slower, but requires less steps. +* Provision the DC, then provision WEF and WIN10 simultaneously. This is faster, but you'll have to open multiple terminals and do a bit of manual work. + +For the provisioning to be successful, the DC has to spin up Active Directory before provisioning of the WEF and WIN10 hosts can begin, otherwise they will fail to join the domain and provisioning will fail. + +If you'd like to take the slower but easier route, ensure you're in `DetectionLab/Azure/Ansible` and run `ansible-playbook -v detectionlab.yml`. This will provision the hosts one at a time (DC, WEF, then WIN10). However, if you'd like to go the faster route, follow the directions below. + +If you'd like to take the faster route, I recommend opening 3 terminal windows to `DetectionLab/Azure/Ansible` and following the following steps: +1. In the first window, run `ansible-playbook -v detectionlab.yml --tags "dc"` +2. Once the DC has passed the `Reboot Afer Domain Creation` Ansible step, you can begin provisioning WEF and WIN10 +3. In the second window, run `ansible-playbook -v detectionlab.yml --tags "wef"` +4. In the third window, run `ansible-playbook -v detectionlab.yml --tags "win10"` + +. If all goes well, you should see the following and your lab is complete! +![Ansible](https://github.com/clong/DetectionLab/blob/master/img/esxi_ansible.png?raw=true) + +If you run into any issues along the way, please open an issue on Github and I'll do my best to find a solution. + +## Debugging / Troubleshooting / Known Issues +* If an Ansible playbook fails (and they often do), you can pick up where it left off with `ansible-playbook -vvv detectionlab.yml --tags="hostname-goes-here" --start-at-task="taskname"` +* The "Configure OU" Ansible step often fails because the cmdlet can't find AD. Re-running it often fixes the issue (for unknown reasons): `ansible-playbook -vvv detectionlab.yml --tags="dc" --start-at-task="Configure OU"` +* "Installing Red Team Tooling" hangs if AV isn't disabled successfully +* It seems like sometimes the logger provisioning "errors" somewhere and causes the box to become tained, despite the provision being successful. Work around this by untainting it: `terraform untaint azurerm_virtual_machine.dc` + +## Future work required +* It probably makes sense to abstract all of the logic in `bootstrap.sh` into individual Ansible tasks +* I imagine there's a streamlined way to get the results of `terraform output` into the `inventory.yml` for Ansible. +* I'm guessing there's a way to parallelize some of this execution or make some of it asynchronous: https://medium.com/developer-space/parallel-playbook-execution-in-ansible-30799ccda4e0 and https://docs.ansible.com/ansible/latest/user_guide/playbooks_async.html + +## Credits +As usual, this work is based off the heavy lifting that others have done. My primary sources for this work were: +* [The DetectionLab work that juju4 has been doing on Azure and Ansible.](https://github.com/juju4/DetectionLab/tree/devel-azureansible/Ansible) At least 90% of this code was borrowed from their work. +* [Automate Windows VM Creation and Configuration in vSphere Using Packer, Terraform and Ansible - Dmitry Teslya](https://dteslya.engineer/automation/2019-02-19-configuring_vms_with_ansible/#setting-up-ansible) + +Thank you to all of the sponsors who made this possible! diff --git a/Azure/Terraform/files/FirstLogonCommands.xml b/Azure/Terraform/files/FirstLogonCommands.xml new file mode 100644 index 0000000..9fdd00a --- /dev/null +++ b/Azure/Terraform/files/FirstLogonCommands.xml @@ -0,0 +1,17 @@ + + + cmd /c "mkdir C:\terraform" + Create the Terraform working directory + 11 + + + cmd /c "copy C:\AzureData\CustomData.bin C:\terraform\winrm.ps1" + Move the CustomData file to the working directory + 12 + + + powershell.exe -sta -ExecutionPolicy Unrestricted -file C:\terraform\winrm.ps1 + Move the CustomData file to the working directory + 13 + + \ No newline at end of file diff --git a/Azure/Terraform/files/winrm.ps1 b/Azure/Terraform/files/winrm.ps1 new file mode 100644 index 0000000..cb7413a --- /dev/null +++ b/Azure/Terraform/files/winrm.ps1 @@ -0,0 +1,16 @@ +powershell.exe -c "Set-NetConnectionProfile -InterfaceAlias Ethernet -NetworkCategory Private" +Enable-PSRemoting -Force +winrm quickconfig -q +winrm quickconfig -transport:http +powershell.exe -c "winrm set winrm/config '@{MaxTimeoutms=\`"1800000\`"}'" +powershell.exe -c "winrm set winrm/config/winrs '@{MaxMemoryPerShellMB=\`"800\`"}'" +powershell.exe -c "winrm set winrm/config/service '@{AllowUnencrypted=\`"true\`"}'" +powershell.exe -c "winrm set winrm/config/service/auth '@{Basic=\`"true\`"}'" +powershell.exe -c "winrm set winrm/config/client/auth '@{Basic=\`"true\`"}'" +powershell.exe -c "winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port=\`"5985\`"}'" +netsh advfirewall firewall set rule group="Windows Remote Administration" new enable=yes +netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=allow remoteip=any +reg add HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce /v StartWinRM /t REG_SZ /f /d "cmd.exe /c 'sc config winrm start= auto & sc start winrm'" +Restart-Service winrm +netsh advfirewall firewall add rule name="Port 5985" dir=in action=allow protocol=TCP localport=5985 + diff --git a/Azure/Terraform/locals.tf b/Azure/Terraform/locals.tf new file mode 100644 index 0000000..8e3cc92 --- /dev/null +++ b/Azure/Terraform/locals.tf @@ -0,0 +1,6 @@ +locals { + fleet_url = "https://${azurerm_public_ip.logger-publicip.ip_address}:8412" + splunk_url = "https://${azurerm_public_ip.logger-publicip.ip_address}:8000" + ata_url = "https://${azurerm_public_ip.wef-publicip.ip_address}" + guacamole_url = "https://${azurerm_public_ip.wef-publicip.ip_address}:8080/guacamole" +} \ No newline at end of file diff --git a/Azure/Terraform/main.tf b/Azure/Terraform/main.tf new file mode 100644 index 0000000..79d1244 --- /dev/null +++ b/Azure/Terraform/main.tf @@ -0,0 +1,522 @@ +# 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 = "West US 2" +} + +resource "azurerm_virtual_network" "detectionlab-network" { + name = "DetectionLab-vnet" + address_space = ["192.168.0.0/16"] + location = "West US 2" + 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 = "West US 2" + 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 = "*" + } +} + +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 = "West US 2" + resource_group_name = azurerm_resource_group.detectionlab.name + allocation_method = "Static" + + tags = { + role = "logger" + } +} + +resource "azurerm_network_interface" "logger-nic" { + name = "logger-nic" + location = "West US 2" + 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 = "West US 2" + 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 = "West US 2" + 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", + "echo 'logger' | sudo tee /etc/hostname && sudo hostnamectl set-hostname logger", + "sudo adduser --disabled-password --gecos \"\" vagrant && 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/bootstrap.sh", + "sudo sed -i 's/ETH1/ETH0/g' /opt/DetectionLab/Vagrant/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/bootstrap.sh", + "sudo sed -i 's#/vagrant/resources#/opt/DetectionLab/Vagrant/resources#g' /opt/DetectionLab/Vagrant/bootstrap.sh", + "sudo chmod +x /opt/DetectionLab/Vagrant/bootstrap.sh", + "sudo apt-get -qq update", + "sudo /opt/DetectionLab/Vagrant/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 = "West US 2" + 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 = "West US 2" + resource_group_name = azurerm_resource_group.detectionlab.name + allocation_method = "Static" + + tags = { + role = "dc" + } +} + +resource "azurerm_network_interface" "wef-nic" { + name = "wef-nic" + location = "West US 2" + 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 = "West US 2" + resource_group_name = azurerm_resource_group.detectionlab.name + allocation_method = "Static" + + tags = { + role = "wef" + } +} + +resource "azurerm_network_interface" "win10-nic" { + name = "win10-nic" + location = "West US 2" + 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 = "West US 2" + resource_group_name = azurerm_resource_group.detectionlab.name + allocation_method = "Static" + + tags = { + role = "win10" + } +} + +resource "azurerm_virtual_machine" "dc" { + name = "dc.windomain.local" + location = "West US 2" + 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 = "Vagrant123true1vagrant" + } + + # 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("./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 = "West US 2" + 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 = "Vagrant123true1vagrant" + } + + # 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("./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 = "West US 2" + 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 = "Vagrant123true1vagrant" + } + + # 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("./files/FirstLogonCommands.xml") + } + } + + storage_os_disk { + name = "OsDiskWin10" + caching = "ReadWrite" + create_option = "FromImage" + managed_disk_type = "Standard_LRS" + } + + tags = { + role = "win10" + } +} \ No newline at end of file diff --git a/Azure/Terraform/outputs.tf b/Azure/Terraform/outputs.tf new file mode 100644 index 0000000..693d8df --- /dev/null +++ b/Azure/Terraform/outputs.tf @@ -0,0 +1,35 @@ +output "region" { + value = var.region +} + +output "logger_public_ip" { + value = azurerm_public_ip.logger-publicip.ip_address +} + +output "dc_public_ip" { + value = azurerm_public_ip.dc-publicip.ip_address +} + +output "wef_public_ip" { + value = azurerm_public_ip.wef-publicip.ip_address +} + +output "win10_public_ip" { + value = azurerm_public_ip.win10-publicip.ip_address +} + +output "ata_url" { + value = local.ata_url +} + +output "fleet_url" { + value = local.fleet_url +} + +output "splunk_url" { + value = local.splunk_url +} + +output "guacamole_url" { + value = local.guacamole_url +} \ No newline at end of file diff --git a/Azure/Terraform/terraform.tfvars.example b/Azure/Terraform/terraform.tfvars.example new file mode 100644 index 0000000..8555a73 --- /dev/null +++ b/Azure/Terraform/terraform.tfvars.example @@ -0,0 +1,10 @@ +# https://azure.microsoft.com/en-us/global-infrastructure/locations/ +region = "US WEST 2" +public_key_name = "id_logger" # This can be changed to whatever you want +# These values must point to a valid keypair. +# You'll log into the logger host via: ssh -i /home/user/.ssh/id_logger vagrant@ +public_key_path = "/home/user/.ssh/id_logger.pub" +private_key_path = "/home/user/.ssh/id_logger" +# Replace the IP address below with the IP address(es) you'll be using +# to connect to DetectionLab +ip_whitelist = ["1.2.3.4/32"] diff --git a/Azure/Terraform/variables.tf b/Azure/Terraform/variables.tf new file mode 100644 index 0000000..9cdfe4d --- /dev/null +++ b/Azure/Terraform/variables.tf @@ -0,0 +1,42 @@ +variable "region" { + default = "West US 2" +} + +variable "profile" { + default = "terraform" +} + +variable "availability_zone" { + description = "https://docs.microsoft.com/en-us/azure/availability-zones/az-overview" + default = "" +} + +variable "public_key_name" { + description = "A name for SSH Keypair to use to auth to logger. Can be anything you specify." + default = "id_logger" +} + +variable "public_key_path" { + description = "Path to the public key to be loaded into the logger authorized_keys file" + type = string + default = "/home/user/.ssh/id_logger.pub" +} + +# Note: must use ssh key without passphrase. not supported by Terraform. +variable "private_key_path" { + description = "Path to the private key to use to authenticate to logger." + type = string + default = "/home/user/.ssh/id_logger" +} + +variable "ip_whitelist" { + description = "A list of CIDRs that will be allowed to access the instances" + type = list(string) + default = [""] +} + +variable "external_dns_servers" { + description = "Configure lab to allow external DNS resolution" + type = list(string) + default = ["8.8.8.8"] +} \ No newline at end of file diff --git a/ESXi/README.md b/ESXi/README.md index 69c0989..2fe6151 100644 --- a/ESXi/README.md +++ b/ESXi/README.md @@ -36,11 +36,11 @@ These commands can be run in parallel from three separate terminal sessions. ![Ansible](https://github.com/clong/DetectionLab/blob/master/img/esxi_console.png?raw=true) 4. **(5 Minutes)** Edit the variables in `ESXi/variables.tf` to match your local ESXi configuration or [create a terraform.tfvars file](https://www.terraform.io/docs/configuration/variables.html#variable-definitions-tfvars-files) (RECOMMENDED) to override them. 5. **(25 Minutes)** From `DetectionLab/ESXi`, run `terraform init && terraform apply` -6. Once Terraform has finished bringing the hosts online, change your directory to `DetectionLab/ESXi/ansible` -7. **(1 Minute)** Edit `DetectionLab/ESXi/ansible/inventory.yml` and replace the IP Addresses with the respective IP Addresses of your ESXi VMs. **These IP addresses much be reachable from your host machine!** +6. Once Terraform has finished bringing the hosts online, change your directory to `DetectionLab/ESXi/Ansible` +7. **(1 Minute)** Edit `DetectionLab/ESXi/Ansible/inventory.yml` and replace the IP Addresses with the respective IP Addresses of your ESXi VMs. **These IP addresses much be reachable from your host machine!** 8. **(3 Minute)s** Edit `DetectionLab/ESXi/resources/01-netcfg.yaml`. These are the IP addresses that will be applied to the logger network interfaces. These should be be able to be found in your ESXi console or from the Terraform outputs. 9. **(3 Minute)** Before running any Ansible playbooks, I highly recommend taking snapshots of all your VMs! If anything goes wrong with provisioning, you can simply restore the snapshot and easily debug the issue. -10. Change your directory to `DetectionLab/ESXi/ansible` +10. Change your directory to `DetectionLab/ESXi/Ansible` 11. **(30 Minutes)** Run `ansible-playbook -vvv detectionlab.yml` 12. If all goes well, you should see the following and your lab is complete! ![Ansible](https://github.com/clong/DetectionLab/blob/master/img/esxi_ansible.png?raw=true) diff --git a/img/azure_ansible1.png b/img/azure_ansible1.png new file mode 100644 index 0000000..c86ecb9 Binary files /dev/null and b/img/azure_ansible1.png differ diff --git a/img/azure_terraform1.png b/img/azure_terraform1.png new file mode 100644 index 0000000..33c133b Binary files /dev/null and b/img/azure_terraform1.png differ