Advanced Red Team Lab Infrastructure on Azure using Terraform
Topology
- Solid red line = Active Directory connection
- Dotted blue line = Endpoint connection for Logs
Virtual Network
Address Space |
---|
10.0.0.0/16 |
Subnets
Subnet Name | IPv4 | Use |
---|---|---|
GatewaySubnet | 10.0.0.0/24 | VPN Gateway |
RTLAB-subnet1 | 10.0.1.0/24 | Active Directory |
RTLAB-subnet2 | 10.0.2.0/24 | Pivoting Lab |
Virtual Network Gateway (VPN)
SKU | VNET Subnet | Public IP | Tunnel Type | Authentication Type | Address Pool (Clients) |
---|---|---|---|---|---|
VpnGw1 | 10.0.0.0/24GatewaySubnet |
RTLAB-public-ip-1 |
OpenVPN (SSL) | Azure Certificate | 192.168.1.0/24 |
Virtual Machines
Host | Size | OS | Image Offer | Image Plan | Role | Subnet | Private IP |
---|---|---|---|---|---|---|---|
RTLAB-winserver | Standard B2ms (2 vCPUs, 8GB RAM) | Windows | WindowsServer | 2019-DataCenter | AD DC | RTLAB-subnet1 |
Dynamic |
RTLAB-win1 | Standard B2s (2 vCPUs, 4GB RAM) | Windows | Windows-10 | win10-22h2-entn-g2 | AD User | RTLAB-subnet1 |
Dynamic |
RTLAB-win2 | Standard B2s (2 vCPUs, 4GB RAM) | Windows | Windows-10 | win10-22h2-entn-g2 | AD User | RTLAB-subnet1 RTLAB-subnet2 |
Dynamic Dynamic |
RTLAB-win3 | Standard B2s (2 vCPUs, 4GB RAM) | Windows | Windows-10 | win10-22h2-entn-g2 | Pivot Machine | RTLAB-subnet2 |
Dynamic |
RTLAB-ubuntu | Standard B2s (2 vCPUs, 4GB RAM) | Linux | 0001-com-ubuntu-server-jammy | 22_04-lts-gen2 | AD User | RTLAB-subnet1 |
Dynamic |
RTLAB-kali | Standard B2s (2 vCPUs, 4GB RAM) | Linux | kali | kali-2023-2 | SOC BOX | RTLAB-subnet1 RTLAB-subnet2 |
Dynamic Dynamic |
Note: All VMs are configured to auto shutdown on 11:00 PST daily
Note: VPN gateway incurs cost even when not used (therefore billed for 720 hours). To save costs, VPN gateway can be destroyed when not needed and re-deployed again when needed, regularly.
- Terraform Language Documentation
- Terraform: azurerm Documentation
- GitHub: hashicorp/terraform-provider-azurerm/examples
- Quickstart: Use Terraform to create a Windows VM
- Quickstart: Use Terraform to create a Linux VM
- Configure Terraform in Azure Cloud Shell with Azure PowerShell
- Modules
- azurerm_resource_group
- random_id
- random_password
- azurerm_virtual_network
- azurerm_subnet
- azurerm_public_ip
- azurerm_network_security_group
- azurerm_network_interface
- azurerm_network_interface_security_group_association
- azapi_resource
- Microsoft.Compute/sshPublicKeys@2022-11-01
- azapi_resource_action
- Microsoft.Compute/sshPublicKeys@2022-11-01
- azurerm_windows_virtual_machine
- azurerm_linux_virtual_machine
- azurerm_marketplace_agreement
- azurerm_dev_test_global_vm_shutdown_schedule
- azurerm_virtual_machine_extension
- azurerm_virtual_network_gateway
Pre-requisite: Active Azure Subscription
- Configure Terraform
- Configure Cloud Shell
- Install/Update Terraform
- Authenticate via a Microsoft account from Cloud Shell (using PowerShell)
- Create a service principal using Azure PowerShell
- Specify service principal credentials in environment variables
- Specify service principal credentials in a Terraform provider block
- Generate VPN certificate
- Deploy Infrastructure
- Configure VPN client
- Put VMs to stopped(de-allocated) state
- View Console Output
- Destroy Resources
1. Open Azure Portal and login
2. Open Azure Cloud Shell and select "PowerShell" as the interpreter environment
3. If this is your first time using the Azure account, when displayed "You have no storage mounted" and prompted to create a file share, select "Show advanced settings"
4. Select Subscription
, Cloud Shell region
, enter names for Resource group
, Storage account
and File share
and press the "Create Storage" button
Note: Storage account must be unique across all Azure subscriptions globally, not just yours. The reason for that is that the name becomes part of the URL, e.g. https://accountname.blob.core.windows.net
1. After getting a Cloud Shell (PS), check if terraform is installed and up to date
#Check terraform version to see if it needs an update
terraform version
If the version is out of date, browse to Terraform Downloads and copy the download link of the latest version for Linux - AMD64
- Note: Azure Shell is based on Azure Linux (linux_amd64), so we need the Linux - AMD64 version
https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_linux_amd64.zip
#Download terraform
curl -O <terraform_download_url>
#Unzip package
unzip <zip_file_downloaded_in_previous_step>
#Create bin directory if not present
mkdir bin
#Move terraform to bin directory
mv terraform bin/
Restart Cloud Shell
Confirm terraform is updated
#Check current subscription
Get-AzSubscription
Save both Subscription ID
and tenantId
for upcoming steps
The most common pattern is to interactively sign in to Azure, create a service principal, test the service principal, and then use that service principal for future authentication (either interactively or from your scripts).
#Create service principal with Contributer role
$sp = New-AzADServicePrincipal -DisplayName <service_principal_name> -Role "Contributor"
#Display the App ID
$sp.AppId
#Display the autogenerated password
$sp.PasswordCredentials.SecretText
Save both AppId
and PasswordCredentials.SecretText
for upcoming steps
Replace the following code with respective values gained from earlier steps and execute code to save values as environment variables
#Save values as environment variables
$env:ARM_SUBSCRIPTION_ID="<azure_subscription_id>"
$env:ARM_TENANT_ID="<azure_subscription_tenant_id>"
$env:ARM_CLIENT_ID="<service_principal_app_id>"
$env:ARM_CLIENT_SECRET="<service_principal_password>"
#Check the environment variables
gci env:ARM_*
1. Clone/Download this GitHub repository on Windows computer
2. Replace fields in rtlab/Terraform/providers.tf
with respective values
provider "azurerm" {
features {}
subscription_id = "<SUBSCRIPTIONID>"
tenant_id = "<TENANTID>"
client_id = "<CLIENTID>"
client_secret = "<CLIENTSECRET>"
}
Pre-requisites:
winget
package manager
1. Execute p2s-vpn-cert-gen.ps1
2. Input private key when prompted with Enter Password to Export Client Cert (with Private Key)
3. Input private key again when prompted to extract private key details via openssl
1. Create zip archive of the rtlab
folder
2. Upload zip archive to Azure using Cloud Shell
3. Extract archive
4. Run rtlab\tf-deploy.ps1
Wait for deployment to finish (takes around ~45-60 minutes)
Output containing credentials and SSH keys are saved to rtlab/Terraform/outputs.txt
{
"password_admin_ubuntu": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_soc": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_win1": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_win2": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_win3": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_winserver": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"password_admin_winserver_safemode": {
"sensitive": true,
"type": "string",
"value": "<REDACTED>"
},
"key_data_kali": {
"sensitive": false,
"type": "string",
"value": "ssh-rsa <REDACTED> generated-by-azure"
},
"key_data_ubuntu": {
"sensitive": false,
"type": "string",
"value": "ssh-rsa <REDACTED> generated-by-azure"
},
"resource_group_name": {
"sensitive": false,
"type": "string",
"value": "RTLAB"
}
}
<REDACTED:VPNClientConfigurationArchiveDownloadURL>
1. After successful deployment, download the VPN client configuration archive from the link in the output
2. Extract archive
3. Copy PRIVATE KEY
data and P2SChildCert
data from rtlab\Terraform\VPNcerts\profileinfo.txt
and put them in vpnclientconfiguration\OpenVPN\vpnconfig.ovpn
using any text editor
VMs on Azure are billed in both running
and stopped
state, as resources remain allocated in the datacenter for these two states. In the stopped (deallocated)
state, VMs don't incur a cost, although OS disks reserved for the VMs will be still billed.
rtlab/tf-deploy.ps1
automatically stops all VMs after deployment to save costs. However, after using lab VMs, please use the rtlab/dealloc-all-vm.ps1
script to deallocate resources and save costs.
On the VM console output for the custom script extension can be found in a JSON file located at : C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\<version>\Status
Azure command execution and script handling logs (i.e logs detailing the downloading and running the script) can be found at : C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension\<version>
Run rtlab/tf-destroy.ps1
to automatically destroy all resources created by the Terraform execution plan earlier