You already got an idea of the use case of Terraform and also about how we can connect to Azure using terraform. If not, please refer to my first two articles:
So far we are able to connect to Azure and now, we will deploy some serious entities inside Azure using terraform. In this article, I thought to proceed with an Azure virtual machine deployment. We are expected to get the below entities inside Azure after this proposed Terraform deployment.
  1. A Windows 2016 server
  2. VNet with a dynamic public IP, Subnet, NSG, NIC etc...
  3. Connection ports open for HTTPS, WinRM and RDP. Able to connect using both RDP and WinRM
  4. VMAgent to run automatically
Terraform configuration(azurevm.tf) for this deployment has been uploaded here and only use that version for your reference. Below, I have explained the sections of interest so that you can refer to the configuration with a better understanding, rather than just following it.
  1. provider "azurerm" {}
  2. variable "location" {
  3. default = "Southeast Asia"
  4. }
  5. variable "username" {
  6. default = "jaishmathews"
  7. }
  8. variable "password" {
  9. default = "jaishmathews$1234"
  10. }
  11. resource "azurerm_resource_group" "resourceGroup" {
  12. name = "MindcrackerResourceGroup"
  13. location = "${var.location}"
  14. }
  1. resource "azurerm_public_ip" "publicip" { //Here defined the public IP
  2. name = "mindcrackpublicip"
  3. location = "${var.location}"
  4. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  5. public_ip_address_allocation = "Dynamic"
  6. idle_timeout_in_minutes = 30
  7. domain_name_label = "mindcrackvm" //Here defined the dns name
  8. tags {
  9. environment = "test"
  10. }
  11. }
  12. resource "azurerm_virtual_network" "vnet" { //Here defined the virtual network
  13. name = "mindcracknetwork"
  14. address_space = ["10.0.0.0/16"]
  15. location = "${var.location}"
  16. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  17. }
  18. resource "azurerm_network_security_group" "nsg" { //Here defined the network secrity group
  19. name = "mindcracknsg"
  20. location = "${var.location}"
  21. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  22. security_rule { //Here opened https port
  23. name = "HTTPS"
  24. priority = 1000
  25. direction = "Inbound"
  26. access = "Allow"
  27. protocol = "Tcp"
  28. source_port_range = "*"
  29. destination_port_range = "443"
  30. source_address_prefix = "*"
  31. destination_address_prefix = "*"
  32. }
  33. security_rule { //Here opened WinRMport
  34. name = "winrm"
  35. priority = 1010
  36. direction = "Inbound"
  37. access = "Allow"
  38. protocol = "Tcp"
  39. source_port_range = "*"
  40. destination_port_range = "5985"
  41. source_address_prefix = "*"
  42. destination_address_prefix = "*"
  43. }
  44. security_rule { //Here opened https port for outbound
  45. name = "winrm-out"
  46. priority = 100
  47. direction = "Outbound"
  48. access = "Allow"
  49. protocol = "*"
  50. source_port_range = "*"
  51. destination_port_range = "5985"
  52. source_address_prefix = "*"
  53. destination_address_prefix = "*"
  54. }
  55. security_rule { //Here opened remote desktop port
  56. name = "RDP"
  57. priority = 110
  58. direction = "Inbound"
  59. access = "Allow"
  60. protocol = "Tcp"
  61. source_port_range = "*"
  62. destination_port_range = "3389"
  63. source_address_prefix = "*"
  64. destination_address_prefix = "*"
  65. }
  66. tags {
  67. environment = "test"
  68. }
  69. }
  70. resource "azurerm_subnet" "subnet" { //Here defined subnet
  71. name = "mindcracksubnet"
  72. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  73. virtual_network_name = "${azurerm_virtual_network.vnet.name}"
  74. address_prefix = "10.0.2.0/24"
  75. }
  76. resource "azurerm_network_interface" "nic" { //Here defined network interface
  77. name = "mindcracknic"
  78. location = "${var.location}"
  79. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  80. network_security_group_id = "${azurerm_network_security_group.nsg.id}"
  81. ip_configuration {
  82. name = "mindcrackconfiguration"
  83. subnet_id = "${azurerm_subnet.subnet.id}"
  84. private_ip_address_allocation = "dynamic"
  85. public_ip_address_id = "${azurerm_public_ip.publicip.id}"
  86. }
  87. }
  88. resource "azurerm_storage_account" "storageacc" { //Here defined a storage account for disk
  89. name = "mindcrackstoacc"
  90. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  91. location = "${var.location}"
  92. account_tier = "Standard"
  93. account_replication_type = "GRS"
  94. }
  95. resource "azurerm_storage_container" "storagecont" { //Here defined a storage account container for disk
  96. name = "mindcrackstoragecont"
  97. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  98. storage_account_name = "${azurerm_storage_account.storageacc.name}"
  99. container_access_type = "private"
  100. }
  101. resource "azurerm_managed_disk" "datadisk" { //Here defined data disk structure
  102. name = "mindcrackdatadisk"
  103. location = "${var.location}"
  104. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  105. storage_account_type = "Standard_LRS"
  106. create_option = "Empty"
  107. disk_size_gb = "1023"
  108. }
  109. resource "azurerm_virtual_machine" "vm" { //Here defined virtual machine
  110. name = "mindcrackvm"
  111. location = "${var.location}"
  112. resource_group_name = "${azurerm_resource_group.resourceGroup.name}"
  113. network_interface_ids = ["${azurerm_network_interface.nic.id}"]
  114. vm_size = "Standard_A2" //Here defined virtual machine size
  115. storage_image_reference { //Here defined virtual machine OS
  116. publisher = "MicrosoftWindowsServer"
  117. offer = "WindowsServer"
  118. sku = "2016-Datacenter"
  119. version = "latest"
  120. }
  121. storage_os_disk { //Here defined OS disk
  122. name = "mindcrackosdisk"
  123. caching = "ReadWrite"
  124. create_option = "FromImage"
  125. managed_disk_type = "Standard_LRS"
  126. }
  127. storage_data_disk { //Here defined actual data disk by referring to above structure
  128. name = "${azurerm_managed_disk.datadisk.name}"
  129. managed_disk_id = "${azurerm_managed_disk.datadisk.id}"
  130. create_option = "Attach"
  131. lun = 1
  132. disk_size_gb = "${azurerm_managed_disk.datadisk.disk_size_gb}"
  133. }
  134. os_profile { //Here defined admin uid/pwd and also comupter name
  135. computer_name = "mindcrackhost"
  136. admin_username = "${var.username}"
  137. admin_password = "${var.password}"
  138. }
  139. os_profile_windows_config { //Here defined autoupdate config and also vm agent config
  140. enable_automatic_upgrades = true
  141. provision_vm_agent = true
  142. winrm = { //Here defined WinRM connectivity config
  143. protocol = "http"
  144. }
  145. }
  146. }
Verification of this deployment includes the below steps. I am not mentioning about how to run a terraform configuration file as it has been mentioned in my previous articles.
  • Successful Deployment
    Please verify that you got something like below on command prompt before anything else.

    terraform
  • Verify Azure Portal
    You should see something like the below image,

    terraform

  • Test RDP
    You should be able to login with uid/pwd inside the configuration file. Below is the screenshot from my side after login using the IP showing in the Azure portal
terraform
terraform
terraform
terraform
That's all there is to show here. Please refer to the attached configuration file. In this series, next, I will show how to run certain bootstrap scripts during this VM deployment as part of Terraform. Until then, cheers.