Terraform + Azure + Pipelines (Azure Devops): Provisioning on Windows 11 with Bastion configured in Virtual network

Marcelo Gonçalves
3 min readOct 24, 2023

--

Terraform + Azure + Pipelines (Azure Devops) : Provisionando no Windows 11 com Bastion configurado no Virtual network

This article aims to demonstrate the provisioning code for a Windows 11 VM with the bastion configured in the Virtual Network. With this model you can change the information in the source_image_reference field and enter the type of VM you want.

Esse artigo tem como objetivo demonstrar o código de provisionamento de uma vm Windows 11 com o bastion configurado no Virtual Network.

Com esse modelo você pode trocar as informações do campo source_image_reference e informar o tipo de VM que você deseja.

Crie os arquivos abaixo:

Create files below:

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.location
}

variables.tf

variable "my_virtual_machine_password" {
default = "your_password"
description = "Password of the Virtual Machine"
}

variable "my_virtual_machine_size" {
default = "Standard_D2_v4"
description = "Size of the Virtual Machine"
}

variable "location" {

default = "eastus"
description = "Location of the resource group."
}


variable "name" {

default = "Jordan"
description = "Name of the resource."
}





variable "nameresourcegroup" {

default = "labs"
description = "Name of RG"
}

vnet.tf

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

resource "azurerm_subnet" "subnet" {
name = "subnet-1"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
}

bastion.tf

resource "azurerm_subnet" "mybastionsubnet" {
name = "AzureBastionSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.10.0/27"]
}

resource "azurerm_public_ip" "mypipbastion" {
name = "Bastionpip"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
}

resource "azurerm_bastion_host" "myhost" {
name = "Mybastion"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name

ip_configuration {
name = "configuration_ip_bastion"
subnet_id = azurerm_subnet.mybastionsubnet.id
public_ip_address_id = azurerm_public_ip.mypipbastion.id
}
}

vm_win10.tf

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

tags = {
environment = "Testing"
}
}

resource "azurerm_network_interface" "mynetworkinterface" {
name = "network-interface-${var.name}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name

ip_configuration {
name = "internal-${var.name}"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"

public_ip_address_id = azurerm_public_ip.my-public-ip.id
}
}

# Windows 11 Virtual Machine
resource "azurerm_windows_virtual_machine" "myvirtualmachine" {
name = "win11-${var.name}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = var.my_virtual_machine_size
admin_username = "chicano"
admin_password = var.my_virtual_machine_password
network_interface_ids = [
azurerm_network_interface.mynetworkinterface.id,
]

os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}

source_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "windows-10"
sku = "win10-22h2-pro"
version = "latest"
}
}


# Security Group - allowing RDP Connection
resource "azurerm_network_security_group" "sg-rdp-connection" {
name = "allowrdpconnection-${var.name}"
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
}

Pipelines

azure-pipelines_apply.yml

trigger:
- your_branch

pool:
vmImage: ubuntu-latest

variables:
bkresourcegroups: 'name_resource_group'
bkstorageaccount: 'name_storage_account'
bkcontainer: 'name_container'
bkkey: 'key_storage_account'

stages:
- stage:
jobs:
- job: validate
continueOnError: false
steps:

- task: TerraformInstaller@1
displayName: Instalar o Terraform
inputs:
terraformVersion: 'latest'

- task: TerraformTaskV4@4
displayName: Iniciar o Terraform
inputs:
provider: 'azurerm'
command: 'init'
backendServiceArm: 'TerraFormDevConnection'
backendAzureRmResourceGroupName: '$(bkresourcegroups)'
backendAzureRmStorageAccountName: '$(bkstorageaccount)'
backendAzureRmContainerName: '$(bkcontainer)'
backendAzureRmKey: '$(bkkey)'

- task: TerraformTaskV4@4
displayName: Planejar a codificação no Terraform
inputs:
provider: 'azurerm'
command: 'plan'
environmentServiceNameAzureRM: 'TerraFormDevConnection'

- task: TerraformTaskV4@4
displayName: Applicar a codificação no Terraform
inputs:
provider: 'azurerm'
command: 'apply'
commandOptions: '-auto-approve'
environmentServiceNameAzureRM: 'TerraFormDevConnection'

--

--

Marcelo Gonçalves
Marcelo Gonçalves

Written by Marcelo Gonçalves

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

No responses yet