I'm trying to deploy a simple infrastructure in Azure through Terraform, the infrastructure is made of an Application Gateway (with Web Application Firewall, so the WAF_v2 version) with two virtual machines in the backend.
At the beginning I have implemented the Application Gateway (Standard_v2) without the WAF, and worked properly, but when I have implemented the WAF, I got the following error after lunching "terraform init" command (see attached screenshot also):
Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/example: provider registry registry.terraform.io does not have a provider named
│ registry.terraform.io/hashicorp/example
│
│ All modules should specify their required_providers so that external consumers will get the correct providers when using a module. To see which modules are currently depending
│ on hashicorp/example, run the following command:
│ terraform providers
So I run the command "terraform providers" as suggested by Terraform and got this:
Providers required by configuration:
.
├── provider[registry.terraform.io/hashicorp/azurerm] >= 2.97.0
├── provider[registry.terraform.io/hashicorp/example]
└── provider[registry.terraform.io/hashicorp/random]
In the following you can see the Terraform code of my infrastructure:
terraform {
required_version = ">=0.12"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=2.97.0"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg1" {
name = "myResourceGroupAG"
location = "francecentral"
}
resource "example_wafpolicy" "exampleWAF" {
name = "example_wafpolicy_name"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
custom_rules {
name = "Rule1"
priority = 1
rule_type = "MatchRule"
match_conditions {
match_variables {
variable_name = "RemoteAddr"
}
operator = "IPMatch"
negation_condition = false
match_values = ["XX.XX.XX.XX"]
}
action = "Block"
}
policy_settings {
enabled = true
mode = "Prevention"
request_body_check = true
file_upload_limit_in_mb = 100
max_request_body_size_in_kb = 128
}
managed_rules {
managed_rule_set {
type = "OWASP"
version = "3.2"
}
}
}
resource "azurerm_virtual_network" "vnet1" {
name = "myVNet"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
address_space = ["10.21.0.0/16"]
}
resource "azurerm_subnet" "frontend" {
name = "myAGSubnet"
resource_group_name = azurerm_resource_group.rg1.name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = ["10.21.0.0/24"]
}
resource "azurerm_subnet" "backend" {
name = "myBackendSubnet"
resource_group_name = azurerm_resource_group.rg1.name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = ["10.21.1.0/24"]
}
resource "azurerm_public_ip" "pip1" {
name = "myAGPublicIPAddress"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_application_gateway" "network" {
name = "myAppGateway"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
sku {
name = "WAF_v2"
tier = "WAF_v2"
capacity = 2
}
gateway_ip_configuration {
name = "my-gateway-ip-configuration"
subnet_id = azurerm_subnet.frontend.id
}
frontend_port {
name = var.frontend_port_name
port = 80
}
frontend_ip_configuration {
name = var.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.pip1.id
}
backend_address_pool {
name = var.backend_address_pool_name
}
backend_http_settings {
name = var.http_setting_name
cookie_based_affinity = "Disabled"
port = 80
protocol = "Http"
request_timeout = 20
}
http_listener {
name = var.listener_name
frontend_ip_configuration_name = var.frontend_ip_configuration_name
frontend_port_name = var.frontend_port_name
protocol = "Http"
firewall_policy_id = example_wafpolicy.exampleWAF.id
}
request_routing_rule {
name = var.request_routing_rule_name
rule_type = "Basic"
priority = 25
http_listener_name = var.listener_name
backend_address_pool_name = var.backend_address_pool_name
backend_http_settings_name = var.http_setting_name
}
firewall_policy_id {
id = example_wafpolicy.exampleWAF.id
}
waf_configuration {
content{
enabled = lookup(waf_configuration.value,"enabled",true)
file_upload_limit_mb = lookup(waf_configuration.value,"file_upload_limit_mb",30)
firewall_mode = lookup(waf_configuration.value,"firewall_mode","Prevention")
max_request_body_size_kb = lookup(waf_configuration.value,"max_request_body_size_kb",128)
request_body_check = lookup(waf_configuration.value,"request_body_check",true)
rule_set_type = lookup(waf_configuration.value,"rule_set_type","OWASP")
rule_set_version = lookup(waf_configuration.value,"rule_set_version", "3.1")
}
}
}
resource "azurerm_network_interface" "nic" {
count = 2
name = "nic-${count.index+1}"
location = azurerm_resource_group.rg1.location
resource_group_name = azurerm_resource_group.rg1.name
ip_configuration {
name = "nic-ipconfig-${count.index+1}"
subnet_id = azurerm_subnet.backend.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "nic-assoc01" {
count = 2
network_interface_id = azurerm_network_interface.nic[count.index].id
ip_configuration_name = "nic-ipconfig-${count.index+1}"
backend_address_pool_id = tolist(azurerm_application_gateway.network.backend_address_pool).0.id
}
resource "random_password" "password" {
length = 16
special = true
lower = true
upper = true
numeric = true
}
resource "azurerm_windows_virtual_machine" "vm" {
count = 2
name = "myVM${count.index+1}"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
size = "Standard_DS1_v2"
admin_username = "azureadmin"
admin_password = random_password.password.result
network_interface_ids = [
azurerm_network_interface.nic[count.index].id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
resource "azurerm_virtual_machine_extension" "vm-extensions" {
count = 2
name = "vm${count.index+1}-ext"
virtual_machine_id = azurerm_windows_virtual_machine.vm[count.index].id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.10"
settings = <<SETTINGS
{
"commandToExecute": "powershell Add-WindowsFeature Web-Server; powershell Add-Content -Path \"C:\\inetpub\\wwwroot\\Default.htm\" -Value $($env:computername)"
}
SETTINGS
}
In the following the script with the variables:
variable "backend_address_pool_name" {
default = "myBackendPool"
}
variable "frontend_port_name" {
default = "myFrontendPort"
}
variable "frontend_ip_configuration_name" {
default = "myAGIPConfig"
}
variable "http_setting_name" {
default = "myHTTPsetting"
}
variable "listener_name" {
default = "myListener"
}
variable "request_routing_rule_name" {
default = "myRoutingRule"
}
variable "redirect_configuration_name" {
default = "myRedirectConfig"
}
variable "example_wafpolicy_name" {
default = "myFirewallPolicy"
}
At the beginning of the code you can see match_values = ["XX.XX.XX.XX"], the IP address is set in this manner just for opening this question in Stackoverflow, normally in my code there is a normal IP address.
I would really appreciate your help to fix this error and in general to deploy an Application Gateway with WAF and two virtual machines in the backend in Azure through Terraform.
I have tried to search something online but it seems that this topic has never been opened by someone.
Issue was caused because of the naming convention which used in terraform code base "example_wafpolicy" and terraform provider.
Solution:
Need to replace with below mention resource tag
resource "azurerm_web_application_firewall_policy" "example" {
Replicated the same code base in local, please find below code snippet.
Main if file as follows:
resource "azurerm_resource_group" "rg1" {
name = "************"
location = "West Europe"
}
resource "azurerm_web_application_firewall_policy" "exampleWAF" {
name = "example_wafpolicy_name"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
custom_rules {
name = "Rule1"
priority = 1
rule_type = "MatchRule"
match_conditions {
match_variables {
variable_name = "RemoteAddr"
}
operator = "IPMatch"
negation_condition = false
match_values = ["192.168.1.0/24", "10.0.0.0/24"]
}
action = "Block"
}
policy_settings {
enabled = true
mode = "Prevention"
request_body_check = true
file_upload_limit_in_mb = 100
max_request_body_size_in_kb = 128
}
managed_rules {
managed_rule_set {
type = "OWASP"
version = "3.2"
}
}
}
resource "azurerm_virtual_network" "vnet1" {
name = "myVNet"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
address_space = ["10.21.0.0/16"]
}
resource "azurerm_subnet" "frontend" {
name = "myAGSubnet"
resource_group_name = azurerm_resource_group.rg1.name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = ["10.21.0.0/24"]
}
resource "azurerm_subnet" "backend" {
name = "myBackendSubnet"
resource_group_name = azurerm_resource_group.rg1.name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = ["10.21.1.0/24"]
}
resource "azurerm_public_ip" "pip1" {
name = "myAGPublicIPAddress"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
allocation_method = "Dynamic"
sku = "Basic"
}
locals {
backend_address_pool_name = "${azurerm_virtual_network.vnet1.name}-beap"
frontend_port_name = "${azurerm_virtual_network.vnet1.name}-feport"
frontend_ip_configuration_name = "${azurerm_virtual_network.vnet1.name}-feip"
http_setting_name = "${azurerm_virtual_network.vnet1.name}-be-htst"
listener_name = "${azurerm_virtual_network.vnet1.name}-httplstn"
request_routing_rule_name = "${azurerm_virtual_network.vnet1.name}-rqrt"
redirect_configuration_name = "${azurerm_virtual_network.vnet1.name}-rdrcfg"
}
resource "azurerm_application_gateway" "network" {
name = "example-appgateway"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
sku {
name = "Standard_Small"
tier = "Standard"
capacity = 2
}
gateway_ip_configuration {
name = "my-gateway-ip-configuration"
subnet_id = azurerm_subnet.frontend.id
}
frontend_port {
name = local.frontend_port_name
port = 80
}
frontend_ip_configuration {
name = local.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.pip1.id
}
backend_address_pool {
name = local.backend_address_pool_name
}
backend_http_settings {
name = local.http_setting_name
cookie_based_affinity = "Disabled"
path = "/path1/"
port = 80
protocol = "Http"
request_timeout = 60
}
http_listener {
name = local.listener_name
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = local.frontend_port_name
protocol = "Http"
}
request_routing_rule {
name = local.request_routing_rule_name
rule_type = "Basic"
http_listener_name = local.listener_name
backend_address_pool_name = local.backend_address_pool_name
backend_http_settings_name = local.http_setting_name
}
}
resource "azurerm_network_interface" "nic" {
count = 2
name = "nic-${count.index+1}"
location = azurerm_resource_group.rg1.location
resource_group_name = azurerm_resource_group.rg1.name
ip_configuration {
name = "nic-ipconfig-${count.index+1}"
subnet_id = azurerm_subnet.backend.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "nic-assoc01" {
count = 2
network_interface_id = azurerm_network_interface.nic[count.index].id
ip_configuration_name = "nic-ipconfig-${count.index+1}"
backend_address_pool_id = tolist(azurerm_application_gateway.network.backend_address_pool).0.id
}
resource "random_password" "password" {
length = 16
special = true
lower = true
upper = true
numeric = true
}
resource "azurerm_windows_virtual_machine" "vm" {
count = 2
name = "myVM${count.index+1}"
resource_group_name = azurerm_resource_group.rg1.name
location = azurerm_resource_group.rg1.location
size = "Standard_DS1_v2"
admin_username = "azureadmin"
admin_password = random_password.password.result
network_interface_ids = [
azurerm_network_interface.nic[count.index].id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
resource "azurerm_virtual_machine_extension" "vm-extensions" {
count = 2
name = "vm${count.index+1}-ext"
virtual_machine_id = azurerm_windows_virtual_machine.vm[count.index].id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.10"
settings = <<SETTINGS
{
"commandToExecute": "powershell Add-WindowsFeature Web-Server; powershell Add-Content -Path \"C:\\inetpub\\wwwroot\\Default.htm\" -Value $($env:computername)"
}
SETTINGS
}
provider tf file as follows:
terraform {
required_version = "~>1.3.3"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=3.0.0"
}
}
}
provider "azurerm" {
features {}
skip_provider_registration = true
}
upon running terraform plan and apply
terraform plan
terraform apply -auto-approve
Plan as follows:
Apply as follows
Azure Portal verification:
Related
I have created a application gateway, WAF policy, public IP via terraform.
From Azure GUI I have created a Key vault in which I have uploaded the pfx certificate also I have created managed identity and granted full access to azure key vault.
I am trying to create a additional https listener and calling the certificate stored in the keyvault via data block but somehow landing in this error .
Note: Kayvault , managed identity , appgw, waf policy are all in same region.
Error :
│ Error: updating Application Gateway: (Name "abc-xyz-Nonprod-test-us6-Extappgw0001" / Resource Group "xyz-network-vnet-devtest"): network.ApplicationGatewaysClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidResourceReference" Message="Resource /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xyz-network-vnet-devtest/providers/Microsoft.Network/applicationGateways/abc-xyz-Nonprod-test-us6-Extappgw0001/sslCertificates/firepfx referenced by resource /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xyz-network-vnet-devtest/providers/Microsoft.Network/applicationGateways/abc-xyz-Nonprod-test-us6-Extappgw0001/httpListeners/External_app_gtw_nonprod_backend_listener_https was not found. Please make sure that the referenced resource exists, and that both resources are in the same region." Details=[]
│
│ with azurerm_application_gateway.abc-xyz-Nonprod-test-us6-Extappgw0001,
│ on abc-xyz-Nonprod-test-us6-Extappgw0001.tf line 102, in resource "azurerm_application_gateway" "abc-xyz-Nonprod-test-us6-Extappgw0001":
│ 102: resource "azurerm_application_gateway" "abc-xyz-Nonprod-test-us6-Extappgw0001"
code
terraform {
backend "azurerm" {
storage_account_name = "abccloudlbstorage"
resource_group_name = "xyz-NETENG-AppResources-Prod"
container_name = "testlb"
tenant_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
key = "abc-xyz-Nonprod-test-us6-Extappgw0001.tfstate"
}
}
provider "azurerm" {
features {}
}
data "azurerm_client_config" "current" {}
data "azurerm_subnet" "abc-xyz-devtest-us6-vnet00002-sub00001-AppGW" {
name = "abc-xyz-devtest-us6-vnet00002-sub00001-AppGW"
resource_group_name = "xyz-network-vnet-devtest"
virtual_network_name = "abc-xyz-devtest-us6-vnet00002"
}
data "azurerm_user_assigned_identity" "test-appgw-identity-us6"{
name = "test-appgw-identity-us6"
resource_group_name = "xyz-network-vnet-devtest"
}
data "azurerm_key_vault" "xyz-network-kv" {
name = "xyz-network-kv"
resource_group_name = "xyz-network-vnet-devtest"
}
data "azurerm_key_vault_certificate" "firepfx" {
name = "firepfx"
key_vault_id = data.azurerm_key_vault.xyz-network-kv.id
}
resource "azurerm_public_ip" "abc-test-us6-nonprod-FE0001" {
name = "abc-test-us6-nonprod-FE0001"
resource_group_name = "xyz-network-vnet-devtest"
location = "eastus2"
allocation_method = "Static"
sku = "Standard"
zones = ["1", "2", "3"]
tags = {
BusinessUnit = "enterprise-management"
LineOfBusiness = "xyz"
}
}
resource "azurerm_web_application_firewall_policy" "abc-test-us6-nonprod-WFW0001" {
name = "abc-test-us6-nonprod-WFW0001"
resource_group_name = "xyz-network-vnet-devtest"
location = "eastus2"
tags = {
BusinessUnit = "enterprise-management"
LineOfBusiness = "xyz"
}
custom_rules {
name = "Rule1"
priority = 1
rule_type = "MatchRule"
match_conditions {
match_variables {
variable_name = "RemoteAddr"
}
operator = "IPMatch"
negation_condition = false
match_values = ["8.8.8.8"]
}
action = "Block"
}
policy_settings {
enabled = true
mode = "Prevention"
request_body_check = true
file_upload_limit_in_mb = 100
max_request_body_size_in_kb = 128
}
managed_rules {
exclusion {
match_variable = "RequestHeaderNames"
selector = "x-company-secret-header"
selector_match_operator = "Equals"
}
managed_rule_set {
type = "OWASP"
version = "3.2"
}
}
}
resource "azurerm_application_gateway" "abc-xyz-Nonprod-test-us6-Extappgw0001" {
name = "abc-xyz-Nonprod-test-us6-Extappgw0001"
resource_group_name = "xyz-network-vnet-devtest"
location = "eastus2"
zones = ["1", "2", "3"]
firewall_policy_id = azurerm_web_application_firewall_policy.abc-test-us6-nonprod-WFW0001.id
tags = {
BusinessUnit = "enterprise-management"
LineOfBusiness = "xyz"
}
sku {
name = "WAF_v2"
tier = "WAF_v2"
}
autoscale_configuration {
min_capacity = 2
max_capacity = 10
}
gateway_ip_configuration {
name = "abc-test-us6-nonprod-GIP0001"
subnet_id = data.azurerm_subnet.abc-xyz-devtest-us6-vnet00002-sub00001-AppGW.id
}
frontend_port {
name = "abc-us6-gpt-nonprod-PRT-FE0001"
port = 80
}
frontend_ip_configuration {
name = "abc-test-us6-nonprod-CFG-FE0001"
public_ip_address_id = azurerm_public_ip.abc-test-us6-nonprod-FE0001.id
}
frontend_ip_configuration {
name = "abc-test-us6-nonprod-CFG-FE0002"
subnet_id = data.azurerm_subnet.abc-xyz-devtest-us6-vnet00002-sub00001-AppGW.id
private_ip_address = "10.46.72.200"
private_ip_address_allocation = "Static"
}
backend_address_pool {
name = "External_app_gtw_nonprod_backend"
}
backend_http_settings {
name = "External_app_gtw_nonprod_http_setting"
cookie_based_affinity = "Disabled"
path = "/"
port = 80
protocol = "Http"
request_timeout = 60
}
http_listener {
name = "External_app_gtw_nonprod_backend_listener"
frontend_ip_configuration_name = "abc-test-us6-nonprod-CFG-FE0001"
frontend_port_name = "abc-us6-gpt-nonprod-PRT-FE0001"
protocol = "Http"
}
request_routing_rule {
name = "External_app_gtw_nonprod_RR"
rule_type = "Basic"
http_listener_name = "External_app_gtw_nonprod_backend_listener"
backend_address_pool_name = "External_app_gtw_nonprod_backend"
backend_http_settings_name = "External_app_gtw_nonprod_http_setting"
priority = 1
}
frontend_port {
name = "abc-us6-gpt-nonprod-PRT-FE00011"
port = 443
}
backend_http_settings {
name = "External_app_gtw_nonprod_https_setting"
cookie_based_affinity = "Disabled"
path = "/"
port = 443
protocol = "Https"
request_timeout = 60
host_name = "irms.abc.com"
}
http_listener {
name = "External_app_gtw_nonprod_backend_listener_https"
frontend_ip_configuration_name = "abc-test-us6-nonprod-CFG-FE0001"
frontend_port_name = "abc-us6-gpt-nonprod-PRT-FE00011"
protocol = "Https"
ssl_certificate_name = data.azurerm_key_vault_certificate.firepfx.name
}
identity {
type = "UserAssigned"
identity_ids = [data.azurerm_user_assigned_identity.test-appgw-identity-us6.id]
}
request_routing_rule {
name = "External_app_gtw_nonprod_https"
rule_type = "Basic"
http_listener_name = "External_app_gtw_nonprod_backend_listener_https"
backend_address_pool_name = "External_app_gtw_nonprod_backend"
backend_http_settings_name = "External_app_gtw_nonprod_https_setting"
priority = 3
}
}
For Application Gateway, you have to create an ssl_certificate block that references the Key Vault secret ID under the key_vault_secret_id property. Then your listener will reference the name of this ssl_certificate resource instead of the locals variable you declared.
ssl_certificate {
name = "cert2023"
key_vault_secret_id "https://mykv.vault.azure.net/secrets/cert2023"
}
I have created a VM in Azure as mentioned below
resource "azurerm_windows_virtual_machine" "virtual_machine_hub" {
name = "vm-hub"
resource_group_name = azurerm_resource_group.ipz12-dat-np-connection-rg.name
location = azurerm_resource_group.ipz12-dat-np-connection-rg.location
size = "Standard_B8ms"
admin_username = "xxxxx"
admin_password = "xxxxx"
network_interface_ids = [
azurerm_network_interface.virtual_machine_hub_nic.id
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "Windows-10"
sku = "21h1-pro"
version = "latest"
}
depends_on = [
azurerm_network_interface.virtual_machine_hub_nic
]
}
and enabled the AADLoginForWindows extension
resource "azurerm_virtual_machine_extension" "virtual_machine_hub_ext" {
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.virtual_machine_hub.id
type = "AADLoginForWindows"
type_handler_version = "1.0"
auto_upgrade_minor_version = true
publisher = "Microsoft.Azure.ActiveDirectory"
depends_on = [
azurerm_windows_virtual_machine.virtual_machine_hub
] }
however "dsregcmd /status" command shows that it is not connected with Azure AD domain like AzureADJoined is "No"
In order to register the VM in Azure AD, I don't feel that I have the appropriate permissions. If that's the case, what level of permission is required? and what am I missing?
Note: I have manually joined Azure AD like mentioned below
As discussed here, it is described that aadj private extension also to be created for a virtual machine under path:
HKLM\SOFTWARE\Microsoft\RDInfraAgent\AADJPrivate
So, another Custom script extension was added to add the key AADJPRIVATE for the VM.
Followed this template given by #Ansuman Bal in SO thread for Azure AD VM join and made a few changes to achieve the expected results as per your requirements.
vi main.tf:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.37.0"
}
}
}
provider "azurerm" {
features {}
}
provider "azuread" {}
data "azuread_group" "aad_group" {
display_name = "<ADGroup>"
security_enabled = true
}
data "azurerm_role_definition" "vm_user_login" {
name = "<VM User Login>"
}
resource "azurerm_role_assignment" "vm_user_role" {
scope = azurerm_resource_group.rg-xxx.id
role_definition_id = data.azurerm_role_definition.vm_user_login.id
principal_id = data.azuread_group.aad_group.id
}
data "azurerm_role_definition" "desktop_user" {
name = "xxxxxx User"
}
resource "azurerm_role_assignment" "desktop_role" {
scope = azurerm_virtual_desktop_application_group.desktopapp.id
role_definition_id = data.azurerm_role_definition.desktop_user.id
principal_id = data.azuread_group.aad_group.id
}
resource "azurerm_resource_group" "eg-RG" {
name = "xxxxxtest"
location = "West Europe"
}
resource "azurerm_virtual_network" "vnet" {
name = "xxxx-vnet"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "xxxxdefaultSubnet" {
name = "xxxxxsubnet"
resource_group_name = azurerm_resource_group.eg-RG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.0.0/24"]
}
resource "azurerm_network_security_group" "nsg" {
name = "xxxx-nsg"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
security_rule {
name = "allow-rdp"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = 3389
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "nsg_association" {
subnet_id = azurerm_subnet.xxxxdefaultSubnet.id
network_security_group_ID = azurerm_network_security_group.<nsg>.id
}
resource "time_rotating" Gen_token" {
rotation_days = 30
}
resource "azurerm_virtual_desktop_host_pool" "new-hp" {
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
name = "xxxxxhostpool"
friendly_name = "samplepool"
validate_environment = true
start_vm_on_connect = true
custom_rdp_properties = "audiocapturemode:i:1;audiomode:i:0;targetisaadjoined:i:1;"
description = "host-poool demo"
type = "Pooled"
maximum_sessions_allowed = 10
load_balancer_type = "DepthFirst"
}
resource "azurerm_virtual_desktop_host_pool_registration_info" "reginfo" {
hostpool_id = azurerm_virtual_desktop_host_pool.new-hp.id
expiration_date = time_rotating.avd_token.rotation_rfc3339
}
resource "azurerm_virtual_desktop_application_group" "desktopapp" {
name = "xxxx-Desktop"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
type = "Desktop"
host_pool_id = azurerm_virtual_desktop_host_pool.new-hp.id
friendly_name = "xxxxx"
description = "xxxxapplications"
}
resource "azurerm_virtual_desktop_workspace" "workspace" {
name = "xxxxxx-WORKSPACE"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
friendly_name = "xxxxxxx"
description = "Purporse"
}
resource "azurerm_virtual_desktop_workspace_application_group_association" "sampleworkspaceremoteapp" {
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
application_group_id = azurerm_virtual_desktop_application_group.desktopapp.id
}
resource "azurerm_network_interface" "xxxx_nic" {
count=2
name = "xxxx-${count.index}"
location = azurerm_resource_group.eg-RG.location
resource_group_name = azurerm_resource_group.eg-RG.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.xxxxxdefaultSubnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_windows_virtual_machine" "sessionhost" {
depends_on = [
azurerm_network_interface.sessionhost_nic
]
count=2
name = "xxxvm-${count.index}"
resource_group_name = azurerm_resource_group.eg-RG.name
location = azurerm_resource_group.eg-RG.location
size = "Standard_B2MS"
admin_username = "useradmin"
admin_password = "<Password>"
provision_vm_agent = true
network_interface_ids = [azurerm_network_interface.sessionhost_nic.*.id[count.index]]
identity {
type = "SystemAssigned"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsDesktop"
offer = "Windows-10"
sku = "20h2-evd"
version = "latest"
}
}
locals {
registration_token = "${azurerm_virtual_desktop_host_pool_registration_info.reginfo.token}"
shutdown_command = "shutdown -r -t 10"
exit_code_hack = "exit 0"
commandtorun = "New-Item -Path HKLM:/SOFTWARE/Microsoft/RDInfraAgent/AADJPrivate"
powershell_command = "${local.commandtorun}; ${local.shutdown_command}; ${local.exit_code_hack}"
}
resource "azurerm_virtual_machine_extension" "xxxAVDModule" {
depends_on = [
azurerm_windows_virtual_machine.xxx_sessionhost
]
count = 2
name = "Microsoft.PowerShell.DSC"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Powershell"
type = "DSC"
type_handler_version = "2.73"
settings = <<-SETTINGS
{
"modulesUrl": "https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_11-22-2021.zip",
"ConfigurationFunction": "Configuration.ps1\\AddSessionHost",
"Properties" : {
"hostPoolName" : "${azurerm_virtual_desktop_host_pool.new-hp.name}",
"aadJoin": true
}
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"properties": {
"registrationInfoToken": "${azurerm_virtual_desktop_host_pool_registration_info.reginfo.token}"
}
}
PROTECTED_SETTINGS
}
resource "azurerm_virtual_machine_extension" "AADLoginForWindows" {
depends_on = [
azurerm_windows_virtual_machine.xxxx_sessionhost,
azurerm_virtual_machine_extension.AVDModule
]
count = 2
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Azure.ActiveDirectory"
type = "AADLoginForWindows"
type_handler_version = "1.0"
auto_upgrade_minor_version = true
}
resource "azurerm_virtual_machine_extension" "xxxxaadjprivate" {
depends_on = [
azurerm_virtual_machine_extension.AADLoginForWindows
]
count = 2
name = "AADJPRIVATE"
virtual_machine_id = azurerm_windows_virtual_machine.avd_sessionhost.*.id[count.index]
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = <<SETTINGS
{
"commandToExecute": "powershell.exe -Command \"${local.powershell_command}\""
}
SETTINGS
}
terraform plan:
terraform apply:
VM Joined in AD after deployment:
Virtual Machine Overview:
Does anyone could give a hint on how should i do. i want to deploy 4 Az linux VM but 2 in each different resource group.
eg: rg-one will have 2 linux and rg-two will the other two
the way i did it is too create two block with azure_linux_virtual_machine, it is working but i was wondering if it could not be simplify.
thank in advance for the head up
here a snipped what i have done.
# Fetch exisiting resource_group
data "azurerm_resource_group" "rg-dock001" {
name = var.resource_group01
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
name = var.vm_network
resource_group_name = var.rg_name_network
}
output "azurerm_virtual_network" {
value = data.azurerm_virtual_network.vm_network.id
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
name = var.vm_subnet
resource_group_name = var.rg_name_network
virtual_network_name = var.vm_network
}
output "subnet_id" {
value = data.azurerm_subnet.vm_subnet.id
}
resource "azurerm_network_interface" "ens124-01" {
name = var.vm_nic01[count.index]
count = length(var.vm_nic01)
location = var.rg_location
resource_group_name = var.resource_group01
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 10}"
}
tags = var.vm_tags
}
output "private_ip01" {
value = length(azurerm_network_interface.ens124-01.*.private_ip_address)
}
# Fetch existing image
data "azurerm_image" "custom_docker_image" {
name_regex = var.packer_image
sort_descending = true
resource_group_name = var.resource_group_image
}
output "image_id" {
value = data.azurerm_image.custom_docker_image.id
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main01" {
name = var.vm_name01[count.index]
count = length(var.vm_name01)
resource_group_name = var.resource_group01
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-01.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name01[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}
data "azurerm_resource_group" "rg-dock002" {
name = var.resource_group02
}
resource "azurerm_network_interface" "ens124-02" {
name = var.vm_nic02[count.index]
count = length(var.vm_nic02)
location = var.rg_location
resource_group_name = var.resource_group02
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Static"
private_ip_address = "10.241.25.${count.index + 20}"
}
tags = var.vm_tags
}
output "private_ip02" {
value = length(azurerm_network_interface.ens124-02.*.private_ip_address)
}
resource "azurerm_linux_virtual_machine" "main02" {
name = var.vm_name02[count.index]
count = length(var.vm_name02)
resource_group_name = var.resource_group02
location = var.rg_location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = ["${element(azurerm_network_interface.ens124-02.*.id, count.index)}"]
source_image_id = data.azurerm_image.custom_docker_image.id
computer_name = var.vm_name02[count.index]
admin_ssh_key {
username = var.ssh_username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-0${count.index + 1}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
tags = var.vm_tags
}````
As per your requirement you can use something like below :
provider "azurerm" {
features {}
}
variable "VM" {
default= {
vm1={
rg_name= "ajaytest",
vnet_name="ajay-vnet",
subnet_name="default",
nic_name = "ansumanVM-nic",
private_ip="10.0.0.10",
vm_name="ansumanVM"
},
vm2={
rg_name= "kartiktest",
vnet_name="kartik-vnet",
subnet_name="default",
nic_name="terraformVM-nic",
private_ip="10.0.0.20",
vm_name="terraformVM"
}
}
}
variable "username" {
default="ansuman"
}
variable "password" {
default="Password#1234!"
}
data "azurerm_shared_image_version" "example" {
name = "0.0.1"
image_name = "UbuntuwithNginxinstalled"
gallery_name = "ansumantestgallery"
resource_group_name = "ansumantest"
}
data "azurerm_resource_group" "rg-dock" {
for_each = var.VM
name = each.value["rg_name"]
}
# Fetch vm network
data "azurerm_virtual_network" "vm_network" {
for_each = var.VM
name = each.value["vnet_name"]
resource_group_name = each.value["rg_name"]
}
# Fetch vm subnet
data "azurerm_subnet" "vm_subnet" {
for_each = var.VM
name = each.value["subnet_name"]
resource_group_name = each.value["rg_name"]
virtual_network_name = each.value["vnet_name"]
}
resource "azurerm_network_interface" "ens124" {
for_each = var.VM
name = each.value["nic_name"]
location = data.azurerm_resource_group.rg-dock[each.key].location
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.vm_subnet[each.key].id
private_ip_address_allocation = "Static"
private_ip_address = each.value["private_ip"]
}
}
# create and display an SSH key
resource "tls_private_key" "ssh" {
algorithm = "RSA"
rsa_bits = 4096
}
output "tls_private_key" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
}
resource "azurerm_linux_virtual_machine" "main" {
for_each = var.VM
name = each.value["vm_name"]
resource_group_name = data.azurerm_resource_group.rg-dock[each.key].name
location = data.azurerm_resource_group.rg-dock[each.key].location
size = "standard_ds3_v2"
admin_username = var.username
admin_password = var.password
disable_password_authentication = true
network_interface_ids = [azurerm_network_interface.ens124[format("%s", each.key)].id]
source_image_id = data.azurerm_shared_image_version.example.id
computer_name = each.key
admin_ssh_key {
username = var.username
public_key = tls_private_key.ssh.public_key_openssh
}
os_disk {
name = "disk-int-dock-${each.key}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
}
Note: The admin username and the ssh username must be the same due the below limitation :
And the location of the VM ,Vnet ,Image and other resources must be the same.
Output:
After upgrading terraform to 0.14.0 and azurerm to 2.65.0 I got three errors regarding ssl certificate configuration in the application gateway section.
Error: expected "ssl_certificate.0.key_vault_secret_id" to not be an empty string, got
on ~/modules/someservice/gateways.tf line 120, in resource "azurerm_application_gateway" "network":
102: ssl_certificate {
Error: Computed attributes cannot be set
on ~/modules/someservice/gateways.tf line 120, in resource "azurerm_application_gateway" "network":
120: ssl_certificate {
Computed attributes cannot be set, but a value was set for
"ssl_certificate.0.id".
Error: Computed attributes cannot be set
on ~/modules/someservice/gateways.tf line 120, in resource "azurerm_application_gateway" "network":
120: ssl_certificate {
Computed attributes cannot be set, but a value was set for
"ssl_certificate.0.public_cert_data".
But key_vault_secret_id configuratiom is not existing in my code:
ssl_certificate {
name = local.certificate_name
data = filebase64("./ssl-cert/appgwcert.pfx")
password = "SecretPwd"
}
Snippet of the application gateway:
terraform {
required_version = "= 0.14.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.65.0"
}
}
}
provider "azurerm" {
features {}
}
# #################################################################
resource "azurerm_public_ip" "pub-ip" {
name = "appgw-pubIP"
resource_group_name = local.resour_group_name
location = local.resour_group_location
allocation_method = "Dynamic"
}
resource "azurerm_subnet" "subnet-01" {
name = "seubnet-app-gateway"
resource_group_name = local.resour_group_name
virtual_network_name = "vnet-app-gateway"
address_prefixes = ["10.21.0.0/24"]
}
# since these variables are re-used - a locals block makes this more maintainable
locals {
resour_group_name = "app-gateway-test-01"
resour_group_location = "westus2"
backend_address_pool_name = "backend-pool-test-01"
frontend_port_name = "port_443"
frontend_ip_configuration_name = "appGwPublicFrontendIp"
http_setting_name = "http-settings-test-01"
listener_name = "https-listener-01"
request_routing_rule_name = "routrul-test-01"
certificate_name = "appgw-cert-test-01"
}
resource "azurerm_application_gateway" "network" {
name = "app-gateway-test-01"
resource_group_name = local.resour_group_name
location = local.resour_group_location
sku {
name = "Standard_V2"
tier = "Standard"
capacity = 2
}
gateway_ip_configuration {
name = "appGatewayIpConfig"
subnet_id = azurerm_subnet.subnet-01.id
}
frontend_port {
name = local.frontend_port_name
port = 443
}
frontend_ip_configuration {
name = local.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.pub-ip.id
}
backend_address_pool {
name = local.backend_address_pool_name
}
backend_http_settings {
name = local.http_setting_name
cookie_based_affinity = "Disabled"
port = 80
protocol = "Http"
request_timeout = 20
}
http_listener {
name = local.listener_name
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = local.frontend_port_name
protocol = "Https"
ssl_certificate_name = local.certificate_name
}
ssl_certificate {
name = local.certificate_name
# reference the dummy certificate
data = filebase64("./ssl-cert/appgwcert.pfx")
# this is only a dummy and not the actual certificate to be used thus no harm in storing the password
password = "SecretPwd"
}
request_routing_rule {
name = local.request_routing_rule_name
rule_type = "Basic"
http_listener_name = local.listener_name
backend_address_pool_name = local.backend_address_pool_name
backend_http_settings_name = local.http_setting_name
}
lifecycle {
ignore_changes = [ssl_certificate, http_listener]
}
}
I have no idea how to fix it?
There are few problems in your code, I have fixed those and tested on my environment.
The Public IP should have Sku = Standard and allocation_method = static.
The Sku name in application Gateway is standard_v2 but the
tier is Standard , it should be the same i.e. standard_v2 .
I have used terraform version 1.0.5 instead of using terraform
version 0.14.0.
So, after the changes the code is as below:
terraform {
required_version = "1.0.5"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.65.0"
}
}
}
provider "azurerm" {
features {}
}
# #################################################################
resource "azurerm_public_ip" "pub-ip" {
name = "appgw-pubIP"
resource_group_name = local.resour_group_name
location = local.resour_group_location
allocation_method = "Static"
sku = "standard"
}
resource "azurerm_subnet" "subnet-01" {
name = "seubnet-app-gateway"
resource_group_name = local.resour_group_name
virtual_network_name = "ansuman-vnet"
address_prefixes = ["172.31.10.0/24"]
}
# since these variables are re-used - a locals block makes this more maintainable
locals {
resour_group_name = "myresourcegroup"
resour_group_location = "westus2"
backend_address_pool_name = "backend-pool-test-01"
frontend_port_name = "port_443"
frontend_ip_configuration_name = "appGwPublicFrontendIp"
http_setting_name = "http-settings-test-01"
listener_name = "https-listener-01"
request_routing_rule_name = "routrul-test-01"
certificate_name = "appgw-cert-test-01"
}
resource "azurerm_application_gateway" "network" {
name = "app-gateway-test-01"
resource_group_name = local.resour_group_name
location = local.resour_group_location
sku {
name = "Standard_v2"
tier = "Standard_v2"
capacity = 2
}
gateway_ip_configuration {
name = "appGatewayIpConfig"
subnet_id = azurerm_subnet.subnet-01.id
}
frontend_port {
name = local.frontend_port_name
port = 443
}
frontend_ip_configuration {
name = local.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.pub-ip.id
}
backend_address_pool {
name = local.backend_address_pool_name
}
backend_http_settings {
name = local.http_setting_name
cookie_based_affinity = "Disabled"
port = 80
protocol = "Http"
request_timeout = 20
}
http_listener {
name = local.listener_name
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = local.frontend_port_name
protocol = "Https"
ssl_certificate_name = local.certificate_name
}
ssl_certificate {
name = local.certificate_name
# reference the dummy certificate
data = filebase64("C:/powershellpfx.pfx")
# this is only a dummy and not the actual certificate to be used thus no harm in storing the password
password = "password#1234"
}
request_routing_rule {
name = local.request_routing_rule_name
rule_type = "Basic"
http_listener_name = local.listener_name
backend_address_pool_name = local.backend_address_pool_name
backend_http_settings_name = local.http_setting_name
}
lifecycle {
ignore_changes = [ssl_certificate, http_listener]
}
}
Outputs:
I am using an existing template from github and have modified it a little bit. When I terraform.exe plan it says it will deploy 4 resources (NIC, NSG, VM-SA, and Resource Group).
I am trying to deploy a VM and have it joined to an existing VNet.
I have removed the NIC to see if it would add the windows VM for deployment and it does not
main.tf
# Configure the Microsoft Azure Provider
provider "azurerm" {
subscription_id = "************************************"
tenant_id = "************************************"
client_id = "************************************"
client_secret = "************************************"
}
module "os" {
source = "./os"
vm_os_simple = "${var.vm_os_simple}"
}
resource "azurerm_resource_group" "vm" {
name = "${var.resource_group_name}"
location = "${var.location}"
tags = "${var.tags}"
}
resource "random_id" "vm-sa" {
keepers = {
vm_hostname = "${var.vm_hostname}"
}
byte_length = 6
}
resource "azurerm_network_security_group" "nsg" {
name = "${var.network_security_group}"
location = "${var.location}"
resource_group_name = "${var.resource_group_name}"
}
resource "azurerm_storage_account" "vm-sa" {
count = "${var.boot_diagnostics == "true" ? 1 : 0}"
name = "bootdiag${lower(random_id.vm-sa.hex)}"
resource_group_name = "${azurerm_resource_group.vm.name}"
location = "${var.location}"
account_tier = "${element(split("_", var.boot_diagnostics_sa_type),0)}"
account_replication_type = "${element(split("_", var.boot_diagnostics_sa_type),1)}"
tags = "${var.tags}"
}
resource "azurerm_virtual_machine" "vm-windows" {
count = "${((var.is_windows_image == "true" || contains(list("${var.vm_os_simple}","${var.vm_os_offer}"), "Windows")) && var.data_disk == "false") ? var.nb_instances : 0}"
name = "${var.vm_hostname}${count.index}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.vm.name}"
vm_size = "${var.vm_size}"
network_interface_ids = ["${element(azurerm_network_interface.vm.*.id, count.index)}"]
delete_os_disk_on_termination = "${var.delete_os_disk_on_termination}"
storage_image_reference {
id = "${var.vm_os_id}"
publisher = "${var.vm_os_id == "" ? coalesce(var.vm_os_publisher, module.os.calculated_value_os_publisher) : ""}"
offer = "${var.vm_os_id == "" ? coalesce(var.vm_os_offer, module.os.calculated_value_os_offer) : ""}"
sku = "${var.vm_os_id == "" ? coalesce(var.vm_os_sku, module.os.calculated_value_os_sku) : ""}"
version = "${var.vm_os_id == "" ? var.vm_os_version : ""}"
}
storage_os_disk {
name = "osdisk-${var.vm_hostname}-${count.index}"
create_option = "FromImage"
caching = "ReadWrite"
managed_disk_type = "${var.storage_account_type}"
}
os_profile {
computer_name = "${var.vm_hostname}${count.index}"
admin_username = "${var.admin_username}"
admin_password = "${var.admin_password}"
}
tags = "${var.tags}"
os_profile_windows_config {
provision_vm_agent = true
}
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
#refer to a subnet
data "azurerm_subnet" "test" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
resource "azurerm_network_interface" "vm" {
count = "${var.nb_instances}"
name = "nic-${var.vm_hostname}-${count.index}"
location = "${azurerm_resource_group.vm.location}"
resource_group_name = "${azurerm_resource_group.vm.name}"
network_security_group_id = "${azurerm_network_security_group.nsg.id}"
ip_configuration {
name = "ipconfig${count.index}"
subnet_id = "${data.azurerm_subnet.test.id}"
private_ip_address_allocation = "Dynamic"
}
tags = "${var.tags}"
}
Expected results should be Deploy a VM, Storage Account, Network Security Group and Nic that is joined to an existing VNet
To create an Azure VM through Terraform, you can see the whole steps in Create a complete Linux virtual machine infrastructure in Azure with Terraform, it's a Linux VM, but you can change the image into windows and the os_profile_linux_config into os_profile_windows_config.
In an existing Vnet, you can use the Terraform data to quote the Vnet as you provide:
data "azurerm_subnet" "existing" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
resource "azurerm_network_interface" "myterraformnic" {
name = "myNIC"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${data.azurerm_subnet.existing.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}"
}
tags {
environment = "Terraform Demo"
}
}
The whole Terraform code here and you can change the information about the VM as you want.
# Configure the Microsoft Azure Provider
provider "azurerm" {
subscription_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_secret = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
tenant_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
# Create a resource group if it doesn’t exist
resource "azurerm_resource_group" "myterraformgroup" {
name = "myResourceGroup"
location = "eastus"
tags {
environment = "Terraform Demo"
}
}
# the existing subnet of the virtual network
data "azurerm_subnet" "existing" {
name = "SubnetName"
virtual_network_name = "VNetName"
resource_group_name = "VNetresourceGroupName"
}
# Create public IPs
resource "azurerm_public_ip" "myterraformpublicip" {
name = "myPublicIP"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
allocation_method = "Dynamic"
tags {
environment = "Terraform Demo"
}
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "myterraformnsg" {
name = "myNetworkSecurityGroup"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
security_rule {
name = "RDP"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3306"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags {
environment = "Terraform Demo"
}
}
# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
name = "myNIC"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${data.azurerm_subnet.existing.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.myterraformpublicip.id}"
}
tags {
environment = "Terraform Demo"
}
}
# Generate random text for a unique storage account name
resource "random_id" "randomId" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = "${azurerm_resource_group.myterraformgroup.name}"
}
byte_length = 8
}
# Create storage account for boot diagnostics
resource "azurerm_storage_account" "mystorageaccount" {
name = "diag${random_id.randomId.hex}"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
location = "eastus"
account_tier = "Standard"
account_replication_type = "LRS"
tags {
environment = "Terraform Demo"
}
}
# Create virtual machine
resource "azurerm_virtual_machine" "myterraformvm" {
name = "myVM"
location = "eastus"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter-Server-Core-smalldisk"
version = "latest"
}
os_profile {
computer_name = "myvm"
admin_username = "azureuser"
admin_password = "Passwd#!1234"
}
os_profile_windows_config {
provision_vm_agent = true
}
boot_diagnostics {
enabled = "true"
storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}"
}
tags {
environment = "Terraform Demo"
}
}
For more details, see Azure Virtual Machine in Terraform.