Provisionamento de Active Directory Services com Terraform

Marcelo Gonçalves
4 min readDec 4, 2023

--

Você deve ter passado por algum momento no mundo da computação da nuvem uma necessidade de provisionar um ADDS de maneira rápida, apenas para realizar um laboratório ou para realizar um teste de um sistema. Eu pelo menos já tive várias situações com essa necessidade, por esse motivo vou compartilhar uma codificação que eu elaborei depois de várias pesquisas com todos vocês.

Eu coloquei um método que você responde para o script qual é a senha, usuário, FQDN e Netbios que você tem preferência:

Siga a codificação logo abaixo:

main.tf

terraform {
backend "azurerm" {
resource_group_name = "NAME_RESOURCE_GROUP"
storage_account_name = "NAME_STORAGE_ACCOUNT"
container_name = "NAME_CONTAINER"
key = "KEY_STORAGE_ACCOUNT"
}
}

provider "azurerm" {
# Configuration options
features {
}
}

rg.tf

resource "azurerm_resource_group" "rg" {
name = lower("rg-${var.nameresourcegroup}")
location = var.location1
}

vm_adds.tf

resource "azurerm_public_ip" "my-public-ip" {
name = "Public-ip-${var.name-vm1}"
resource_group_name = azurerm_resource_group.rg.name
location = var.location1
allocation_method = "Static"

tags = {
environment = "Testing"
}
}
resource "azurerm_network_interface" "mynetworkinterface" {
name = "network-interface-${var.name-vm1}"
location = var.location1
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "internal-${var.name-vm1}"
subnet_id = azurerm_subnet.subnet1.id
private_ip_address_allocation = "Static"
private_ip_address = var.ip_dns_adds
public_ip_address_id = azurerm_public_ip.my-public-ip.id
}
}
# Windows 11 Virtual Machine
resource "azurerm_windows_virtual_machine" "myvirtualmachine" {
name = "vm-${var.name-vm1}"
resource_group_name = azurerm_resource_group.rg.name
location = var.location1
size = var.my_virtual_machine_size
admin_username = var.win_username
admin_password = var.win_userpass
network_interface_ids = [
azurerm_network_interface.mynetworkinterface.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-datacenter"
version = "latest"
}

}
# Security Group - allowing RDP Connection
resource "azurerm_network_security_group" "sg-rdp-connection" {
name = "allowrdpconnection-${var.name-vm1}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = "rdpport"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags = {
environment = "Testing"
}
}

# Associate security group with network interface
resource "azurerm_network_interface_security_group_association" "my_association" {
network_interface_id = azurerm_network_interface.mynetworkinterface.id
network_security_group_id = azurerm_network_security_group.sg-rdp-connection.id
}
#Install Active Directory on the DC01 VM
resource "azurerm_virtual_machine_extension" "install_ad" {
name = "install_ad"
# resource_group_name = azurerm_resource_group.main.name
virtual_machine_id = azurerm_windows_virtual_machine.myvirtualmachine.id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
protected_settings = <<SETTINGS
{
"commandToExecute": "powershell -command \"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${base64encode(data.template_file.ADDS.rendered)}')) | Out-File -filepath ADDS.ps1\" && powershell -ExecutionPolicy Unrestricted -File ADDS.ps1 -Domain_DNSName ${data.template_file.ADDS.vars.Domain_DNSName} -Domain_NETBIOSName ${data.template_file.ADDS.vars.Domain_NETBIOSName} -SafeModeAdministratorPassword ${data.template_file.ADDS.vars.SafeModeAdministratorPassword}"
}
SETTINGS
}
#Variable input for the ADDS.ps1 script
data "template_file" "ADDS_install" {
template = file("ADDS.ps1")
vars = {
Domain_DNSName = "${var.Domain_DNSName}"
Domain_NETBIOSName = "${var.netbios_name}"
SafeModeAdministratorPassword = "${var.SafeModeAdministratorPassword}"
}
}

vnet.tf

resource "azurerm_virtual_network" "vnet1" {
name = "vnet-${var.vnet1-name}"
address_space = ["10.10.0.0/16"]
location = var.vnet1-location
resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_subnet" "subnet1" {
name = "sub-${var.vnet1-name}"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = ["10.10.1.0/24"]
}

variables_adds.tf

variable "Domain_DNSName" {
description = "FQDN for the Active Directory Forest Root Domain"
type = string
sensitive = false
}

variable "netbios_name" {
description = "NETBIOS Name for the AD Domain"
type = string
sensitive = false
}
variable "SafeModeAdministratorPassword" {
description = "Password for AD Safe Mode Recovery"
type = string
sensitive = true
}
#Variable input for the ADDS.ps1 script
data "template_file" "ADDS" {
template = file("ADDS.ps1")
vars = {
Domain_DNSName = "${var.Domain_DNSName}"
Domain_NETBIOSName = "${var.netbios_name}"
SafeModeAdministratorPassword = "${var.SafeModeAdministratorPassword}"
}
}

variables.tf

variable "nameresourcegroup" {

default = "lab-adds-server"
description = "Name of RG"
}
variable "location1" {
default = "eastus"
description = "Location of VM1."
}

variable "vnet1-location" {
default = "eastus"
description = "Location of the Vnet1."
}

variable "vnet1-name" {
default = "adds"
}

variable "win_username" {
description = "Windows Username"
type = string
sensitive = false
}
variable "win_userpass" {
description = "Windows Password"
type = string
sensitive = true
}
variable "my_virtual_machine_size" {
#default = "Standard_D2_v4"
default = "Standard_B2ms"
description = "Size of the Virtual Machine"
}

variable "name-vm1" {
type = string
default = "adds"
description = "Name of the resource."
}
variable "ip_dns_adds" {
default = "10.10.1.100"
}

ADDS.ps1

[CmdletBinding()]

param
(
[Parameter(ValuefromPipeline=$true,Mandatory=$true)] [string]$Domain_DNSName,
[Parameter(ValuefromPipeline=$true,Mandatory=$true)] [string]$Domain_NETBIOSName,
[Parameter(ValuefromPipeline=$true,Mandatory=$true)] [String]$SafeModeAdministratorPassword
)
$SMAP = ConvertTo-SecureString -AsPlainText $SafeModeAdministratorPassword -Force
Set-NetFirewallProfile -Profile Public,Private,Domain -Enabled False
Install-windowsfeature -name AD-Domain-Services -IncludeManagementTools
Install-WindowsFeature DNS -IncludeAllSubFeature -IncludeManagementTools
Install-ADDSForest -CreateDnsDelegation:$false -DatabasePath "C:\Windows\NTDS" -DomainMode "WinThreshold" -DomainName $Domain_DNSName -DomainNetbiosName $Domain_NETBIOSName -ForestMode "WinThreshold" -InstallDns:$true -LogPath "C:\Windows\NTDS" -NoRebootOnCompletion:$false -SysvolPath "C:\Windows\SYSVOL" -Force:$true -SkipPreChecks -SafeModeAdministratorPassword $SMAP
Restart-computer

output.tf

output "public_ip_address_vm-adds" {
value = azurerm_windows_virtual_machine.myvirtualmachine.public_ip_address
}

Espero que tenham gostado, e não se esqueça de me seguir no Youtube:

Cloud na Quebrada Channel

--

--

Marcelo Gonçalves
Marcelo Gonçalves

Written by Marcelo Gonçalves

Microsoft Solutions Architect | Teacher | Linux | MCP | MCT | LGPDF™ | OCI | AWS