Copy and paste the following into main.tf
and run coder template push
:
1terraform {
2 required_providers {
3 coder = {
4 source = "coder/coder"
5 }
6 azurerm = {
7 source = "hashicorp/azurerm"
8 }
9 }
10}
11
12provider "azurerm" {
13 features {}
14}
15
16provider "coder" {
17}
18
19data "coder_workspace" "me" {}
20
21data "coder_parameter" "location" {
22 description = "What location should your workspace live in?"
23 display_name = "Location"
24 name = "location"
25 default = "eastus"
26 mutable = false
27 option {
28 value = "eastus"
29 name = "East US"
30 }
31 option {
32 value = "centralus"
33 name = "Central US"
34 }
35 option {
36 value = "southcentralus"
37 name = "South Central US"
38 }
39 option {
40 value = "westus2"
41 name = "West US 2"
42 }
43}
44
45data "coder_parameter" "data_disk_size" {
46 description = "Size of your data (F:) drive in GB"
47 display_name = "Data disk size"
48 name = "data_disk_size"
49 default = 20
50 mutable = "false"
51 type = "number"
52 validation {
53 min = 5
54 max = 5000
55 }
56}
57
58resource "coder_agent" "main" {
59 arch = "amd64"
60 auth = "azure-instance-identity"
61 os = "windows"
62}
63
64resource "random_password" "admin_password" {
65 length = 16
66 special = true
67 # https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements#reference
68 # we remove characters that require special handling in XML, as this is how we pass it to the VM
69 # namely: <>&'"
70 override_special = "~!@#$%^*_-+=`|\\(){}[]:;,.?/"
71}
72
73locals {
74 prefix = "coder-win"
75 admin_username = "coder"
76}
77
78resource "azurerm_resource_group" "main" {
79 name = "${local.prefix}-${data.coder_workspace.me.id}"
80 location = data.coder_parameter.location.value
81 tags = {
82 Coder_Provisioned = "true"
83 }
84}
85
86// Uncomment here and in the azurerm_network_interface resource to obtain a public IP
87#resource "azurerm_public_ip" "main" {
88# name = "publicip"
89# resource_group_name = azurerm_resource_group.main.name
90# location = azurerm_resource_group.main.location
91# allocation_method = "Static"
92# tags = {
93# Coder_Provisioned = "true"
94# }
95#}
96resource "azurerm_virtual_network" "main" {
97 name = "network"
98 address_space = ["10.0.0.0/24"]
99 location = azurerm_resource_group.main.location
100 resource_group_name = azurerm_resource_group.main.name
101 tags = {
102 Coder_Provisioned = "true"
103 }
104}
105resource "azurerm_subnet" "internal" {
106 name = "internal"
107 resource_group_name = azurerm_resource_group.main.name
108 virtual_network_name = azurerm_virtual_network.main.name
109 address_prefixes = ["10.0.0.0/29"]
110}
111resource "azurerm_network_interface" "main" {
112 name = "nic"
113 resource_group_name = azurerm_resource_group.main.name
114 location = azurerm_resource_group.main.location
115 ip_configuration {
116 name = "internal"
117 subnet_id = azurerm_subnet.internal.id
118 private_ip_address_allocation = "Dynamic"
119 // Uncomment for public IP address as well as azurerm_public_ip resource above
120 # public_ip_address_id = azurerm_public_ip.main.id
121 }
122 tags = {
123 Coder_Provisioned = "true"
124 }
125}
126# Create storage account for boot diagnostics
127resource "azurerm_storage_account" "my_storage_account" {
128 name = "diag${random_id.storage_id.hex}"
129 location = azurerm_resource_group.main.location
130 resource_group_name = azurerm_resource_group.main.name
131 account_tier = "Standard"
132 account_replication_type = "LRS"
133}
134# Generate random text for a unique storage account name
135resource "random_id" "storage_id" {
136 keepers = {
137 # Generate a new ID only when a new resource group is defined
138 resource_group = azurerm_resource_group.main.name
139 }
140 byte_length = 8
141}
142
143resource "azurerm_managed_disk" "data" {
144 name = "data_disk"
145 location = azurerm_resource_group.main.location
146 resource_group_name = azurerm_resource_group.main.name
147 storage_account_type = "Standard_LRS"
148 create_option = "Empty"
149 disk_size_gb = data.coder_parameter.data_disk_size.value
150}
151
152# Create virtual machine
153resource "azurerm_windows_virtual_machine" "main" {
154 name = "vm"
155 admin_username = local.admin_username
156 admin_password = random_password.admin_password.result
157 location = azurerm_resource_group.main.location
158 resource_group_name = azurerm_resource_group.main.name
159 network_interface_ids = [azurerm_network_interface.main.id]
160 size = "Standard_DS1_v2"
161 custom_data = base64encode(
162 templatefile("${path.module}/Initialize.ps1.tftpl", { init_script = coder_agent.main.init_script })
163 )
164 os_disk {
165 name = "myOsDisk"
166 caching = "ReadWrite"
167 storage_account_type = "Premium_LRS"
168 }
169 source_image_reference {
170 publisher = "MicrosoftWindowsServer"
171 offer = "WindowsServer"
172 sku = "2022-datacenter-azure-edition"
173 version = "latest"
174 }
175 additional_unattend_content {
176 content = "<AutoLogon><Password><Value>${random_password.admin_password.result}</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>${local.admin_username}</Username></AutoLogon>"
177 setting = "AutoLogon"
178 }
179 additional_unattend_content {
180 content = file("${path.module}/FirstLogonCommands.xml")
181 setting = "FirstLogonCommands"
182 }
183 boot_diagnostics {
184 storage_account_uri = azurerm_storage_account.my_storage_account.primary_blob_endpoint
185 }
186 tags = {
187 Coder_Provisioned = "true"
188 }
189}
190
191resource "coder_metadata" "rdp_login" {
192 resource_id = azurerm_windows_virtual_machine.main.id
193 item {
194 key = "Username"
195 value = local.admin_username
196 }
197 item {
198 key = "Password"
199 value = random_password.admin_password.result
200 sensitive = true
201 }
202}
203
204resource "azurerm_virtual_machine_data_disk_attachment" "main_data" {
205 managed_disk_id = azurerm_managed_disk.data.id
206 virtual_machine_id = azurerm_windows_virtual_machine.main.id
207 lun = "10"
208 caching = "ReadWrite"
209}
210
211# Stop the VM
212resource "null_resource" "stop_vm" {
213 count = data.coder_workspace.me.transition == "stop" ? 1 : 0
214 depends_on = [azurerm_windows_virtual_machine.main]
215 provisioner "local-exec" {
216 # Use deallocate so the VM is not charged
217 command = "az vm deallocate --ids ${azurerm_windows_virtual_machine.main.id}"
218 }
219}
220
221# Start the VM
222resource "null_resource" "start" {
223 count = data.coder_workspace.me.transition == "start" ? 1 : 0
224 depends_on = [azurerm_windows_virtual_machine.main]
225 provisioner "local-exec" {
226 command = "az vm start --ids ${azurerm_windows_virtual_machine.main.id}"
227 }
228}
229