I am trying to create two centos 8 machines with terraform on azure.
My templates github link
When I try to apply, I am getting below error related to policy.
Could you please suggest how to fix this?
> │ Error: creating Subnet: (Name "subnetforAutomation" / Virtual Network Name "vnetforAutomation" / Resource Group "automation_mart"):
> network.SubnetsClient#CreateOrUpdate: Failure sending request:
> StatusCode=0 -- Original Error: Code="RequestDisallowedByPolicy"
> Message="Resource 'subnetforAutomation' was disallowed by policy.
> Policy identifiers:
> '[{\"policyAssignment\":{\"name\":\"Deny-Subnet-Without-Nsg\",\"id\":\"/providers/Microsoft.Management/managementGroups/QSFT-landingzones/providers/Microsoft.Authorization/policyAssignments/Deny-Subnet-Without-Nsg\"},\"policyDefinition\":{\"name\":\"Subnets
> should have a Network Security Group
> \",\"id\":\"/providers/Microsoft.Management/managementGroups/QSFT/providers/Microsoft.Authorization/policyDefinitions/Deny-Subnet-Without-Nsg\"}}]'."
> Target="subnetforAutomation"
> AdditionalInfo=[{"info":{"evaluationDetails":{"evaluatedExpressions":[{"expression":"type","expressionKind":"Field","expressionValue":"Microsoft.Network/virtualNetworks/subnets","operator":"Equals","path":"type","result":"True","targetValue":"Microsoft.Network/virtualNetworks/subnets"},{"expression":"Microsoft.Network/virtualNetworks/subnets/networkSecurityGroup.id","expressionKind":"Field","operator":"Exists","path":"properties.networkSecurityGroup.id","result":"True","targetValue":"false"}]},"policyAssignmentDisplayName":"Deny-Subnet-Without-Nsg","policyAssignmentId":"/providers/Microsoft.Management/managementGroups/QSFT-landingzones/providers/Microsoft.Authorization/policyAssignments/Deny-Subnet-Without-Nsg","policyAssignmentName":"Deny-Subnet-Without-Nsg","policyAssignmentScope":"/providers/Microsoft.Management/managementGroups/QSFT-landingzones","policyDefinitionDisplayName":"Subnets
> should have a Network Security Group
> ","policyDefinitionEffect":"Deny","policyDefinitionId":"/providers/Microsoft.Management/managementGroups/QSFT/providers/Microsoft.Authorization/policyDefinitions/Deny-Subnet-Without-Nsg","policyDefinitionName":"Deny-Subnet-Without-Nsg"},"type":"PolicyViolation"}]
>
> │
> │ with azurerm_subnet.subnet,
> │ on main.tf line 24, in resource "azurerm_subnet" "subnet":
> │ 24: resource "azurerm_subnet" "subnet" {
> │
I tried keeping inline, the subnet inside vnet. And the issue comes now when referring the subnet from VM instance resource block at the plan stage itself.
Error: Unsupported attribute
│
│ on network.tf line 26, in resource "azurerm_network_interface" "example":
│ 26: subnet_id = azurerm_virtual_network.vnet.subnet.id #azurerm_subnet.subnet.id
│
│ Can't access attributes on a set of objects. Did you mean to access an attribute across all elements of the set?
╵
//main.tf
## <https://www.terraform.io/docs/providers/azurerm/r/windows_virtual_machine.html>
resource "azurerm_windows_virtual_machine" "example" {
name = var.machine_details.name
computer_name = var.machine_details.name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = var.machine_details.size
admin_username = var.machine_details.username
admin_password = var.machine_details.password
network_interface_ids = [
azurerm_network_interface.example.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
//network.tf
## <https://www.terraform.io/docs/providers/azurerm/r/virtual_network.html>
resource "azurerm_virtual_network" "vnet" {
name = "vNet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet{
name = "internal"
address_prefix = "10.0.2.0/24"
security_group = azurerm_network_security_group.example.id
}
}
## <https://www.terraform.io/docs/providers/azurerm/r/network_interface.html>
resource "azurerm_network_interface" "example" {
name = "example-nic"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "internal"
subnet_id = azurerm_virtual_network.vnet.subnet.id #azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.myvm1publicip.id
}
}
resource "azurerm_public_ip" "myvm1publicip" {
name = var.public_ip.name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = var.public_ip.allocation_method
sku = var.public_ip.sku
}
resource "azurerm_network_security_group" "example" {
name = var.nsg
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = "test123"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "*"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
//provider.tf
## <https://www.terraform.io/docs/providers/azurerm/index.html>
provider "azurerm" {
features {}
}
//rg.tf
## <https://www.terraform.io/docs/providers/azurerm/r/resource_group.html>
resource "azurerm_resource_group" "rg" {
name = "TerraformTesting2"
location = var.location
}
//variables.tf
variable "location" {
type = string
description = "Azure Region where all these resources will be provisioned"
default = "eastus2"
}
variable "public_ip" {
default = {
name = "pip1"
allocation_method = "Dynamic"
sku = "Basic"
}
}
variable "nsg" {
type = string
description = "Azure NSG"
default = "example-nsg"
}
variable "machine_details" {
default = {
name = "example-vm2"
size = "Standard_E2s_v3" #"Standard_F2"
username = "adminnasme"
password = "MyPaword!@3"
}
}
Best Answer
The subnet is failing to be created because it is not compliant with a policy your administrators have applied. This indicates that the subnet must have an NSG applied to it before it can be created. Unfortunately the way Terraform does creation of the resources is that you create the subnet first, then associate the NSG with it. This is two API calls, and the first one is failing because it doesn't have an NSG associated with it. Policy is not aware that a second call is coming to associate the NSG with the subnet.
This is the downside to the way Terraform builds on top of the ARM API. There isn't a great solution to this, other than getting your admins to relax this policy.
Edit:
So looking at this issue which is pretty similar to what you are seeing, it seems you can work around this by defining your subnets inside your
virtual_network
resource, rather than as separate subnet resources. Using this you can define the NSG association inline and it this may do it in a single cale: