Azure Terraform Getting Started

Hello guys, here I shall show you some examples of Azure configuration with Terraform, because there are a lot information out there and sometimes is kind of crazy a lot of them with a lot of kinds of configuration that there is no start point for a beginner that why I will try to show the basic until the advanced. I will try to write as much as possible in my free time. So let's get started with Azure and Terraform.

My Terraform configuration if you want to reproduce the configurations below.

terraform --version                                                                          191ms  Sat Apr  4 12:22:01 2020
Terraform v0.12.24
+ provider.azurerm v1.44.0

When we start to work with Terraform and Azure we need to define the provider and there a lot of options we can use here, following the link about the provider documentation take a look: Azure Provider

As we can use the code showed below in a team or another kind of sharing I will approach the configuration via environment variables that I think is the most secure for the how to. If you don't have idea how to set up the SPN for your azure account you can take a look at the following link: Configuring Azure SPN for Terraform

Now we need to configure the environment variables for our project.

The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.

export ARM_SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-62f9d45b6957"

The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.

export ARM_CLIENT_ID="xxxxxxxx-xxxx-xxxx-xxxx-e684b975d113"

The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.

export ARM_CLIENT_SECRET="8Z:s.?3pa@2zjuM4Y-JEoUdlj@w9SXfb"

The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.

export ARM_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-9c8a75bbff3e"

Now let's create our first resource group, try to make all the resources group by it, so if your configuration grows and you need to remove or change it, it'll be a lot easer than try to figure out what's going on.

Let's create a directory to hold all the configuration about our project.

mkdir terraform-azure

Now let's access it

cd terraform-azure

Now let's create our first resource group

vim main.tf
# Provider
# https://www.terraform.io/docs/providers/azurerm/index.html
provider "azurerm" {
  # With Terraform 12 we need to stick with 1.27
  version         = "~> 1.27"
  # The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.
  # subscription_id = "${var.subscription_id}"
  # The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.
  # client_id       = "${var.client_id}"
  # The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.
  # client_secret   = "${var.client_secret}"
  # The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.
  # tenant_id       = "${var.tenant_id}"
}

# Manages a Resource Group.
# https://www.terraform.io/docs/providers/azurerm/r/resource_group.html
resource "azurerm_resource_group" "web_server_rg" {
  # The Name which should be used for this Resource Group. 
  name     = "web-rg"
  # The Azure Region where the Resource Group should exist.
  location = "westus2"
}

Now we need to init the terraform

terraform init                                                                                  4089ms  Sat Apr  4 08:38:21 2020

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 1.44.0...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Now we can run the terraform plan to take a look what will happen if we apply the configuration

terraform plan                                                                                           Sat Apr  4 08:55:43 2020
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

As we can see the terraform plan didn't throw any errors, now we can apply the configuration

terraform apply                                                                                   7.4s  Sat Apr  4 08:56:05 2020

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Creating...
azurerm_resource_group.web_server_rg: Creation complete after 7s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Now we can check if there is a new resource group into Azure Portal or we can check in the command line

az group list                                                                                    23.7s  Sat Apr  4 08:58:48 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg",
    "location": "westus2",
    "managedBy": null,
    "name": "web-rg",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {},
    "type": "Microsoft.Resources/resourceGroups"
  }
]

As we can see there is a new resource group create by Terraform. Now let's destroy it to continue the configuration.

terraform destroy                                                                               2229ms  Sat Apr  4 09:00:32 2020
azurerm_resource_group.web_server_rg: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be destroyed
  - resource "azurerm_resource_group" "web_server_rg" {
      - id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg" -> null
      - location = "westus2" -> null
      - name     = "web-rg" -> null
      - tags     = {} -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 10s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 20s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 30s elapsed]
azurerm_resource_group.web_server_rg: Destruction complete after 39s

Destroy complete! Resources: 1 destroyed.

Now let's make sure that there is no resource group named web-rg

az group show --name web-rg                                                                     1971ms  Sat Apr  4 09:05:12 2020
Resource group 'web-rg' could not be found.

Let's list all the resource groups

az group list                                                                                    58.4s  Sat Apr  4 09:04:17 2020
[]

Resources:

Variables:

  • main.tf
  • Variable Files “terraform.tfvars or *.auto.tfvars
  • Environment
  • Precedence - Command passed, environment & defaults

Example of using a tfvars file and command passed variable

terraform apply -var-file "var.tfvars" -var "server=web"

Let's create a file with some variables to take a look how to handle them

vim variables.tf
variable "server_name" {
  default = "web-server"
}
 
variable "locations" {
  type    = map
  default = {
    location1 = "westus2"
    location2 = "westeurope"
  }
}
 
variable "subnets" {
  type    = list
  default = ["10.0.1.10","10.0.1.11"]
}
 
variable "live" {
  type    = string
  default = false
}

Now we can access the terraform console

terraform console                                                                                 1.8m  Sat Apr  4 09:19:28 2020
>

Now lets get the name of server name inside the terraform console

> var.server_name
web-server

As we could see the form to get the information of a string is var.variable_name just that simple.

Let's take a look how to get information about a map

> var.locations
{
  "location1" = "westus2"
  "location2" = "westeurope"
}

As we can see we have the information about the map and two values location1 and location2, to get the information about only location1 we can do

var.locations["location1"]
westus2

Let's take a look how to get information about a list

> var.subnets
[
  "10.0.1.10",
  "10.0.1.11",
]

As we can see we have the information about the list and two values 10.0.1.10 and 10.0.1.11, to get the information about only first id of the list we can do

> var.subnets[0]
10.0.1.10

We can take a look of Terraform Variables in the following link: Input Variables

We can get the global infrastructure from the following link: Azure locations

But usually we need to get it from the Azure CLI so.

Let's log in

az login --service-principal -u $ARM_CLIENT_ID -p $ARM_CLIENT_SECRET -t $ARM_TENANT_ID

Now we can get the locations

az account list-locations -o table                                                                                          Sat Apr  4 08:19:38 2020
DisplayName           Latitude    Longitude    Name
--------------------  ----------  -----------  ------------------
East Asia             22.267      114.188      eastasia
Southeast Asia        1.283       103.833      southeastasia
Central US            41.5908     -93.6208     centralus
East US               37.3719     -79.8164     eastus
East US 2             36.6681     -78.3889     eastus2
West US               37.783      -122.417     westus
North Central US      41.8819     -87.6278     northcentralus
South Central US      29.4167     -98.5        southcentralus
North Europe          53.3478     -6.2597      northeurope
West Europe           52.3667     4.9          westeurope
Japan West            34.6939     135.5022     japanwest
Japan East            35.68       139.77       japaneast
Brazil South          -23.55      -46.633      brazilsouth
Australia East        -33.86      151.2094     australiaeast
Australia Southeast   -37.8136    144.9631     australiasoutheast
South India           12.9822     80.1636      southindia
Central India         18.5822     73.9197      centralindia
West India            19.088      72.868       westindia
Canada Central        43.653      -79.383      canadacentral
Canada East           46.817      -71.217      canadaeast
UK South              50.941      -0.799       uksouth
UK West               53.427      -3.084       ukwest
West Central US       40.890      -110.234     westcentralus
West US 2             47.233      -119.852     westus2
Korea Central         37.5665     126.9780     koreacentral
Korea South           35.1796     129.0756     koreasouth
France Central        46.3772     2.3730       francecentral
France South          43.8345     2.1972       francesouth
Australia Central     -35.3075    149.1244     australiacentral
Australia Central 2   -35.3075    149.1244     australiacentral2
UAE Central           24.466667   54.366669    uaecentral
UAE North             25.266666   55.316666    uaenorth
South Africa North    -25.731340  28.218370    southafricanorth
South Africa West     -34.075691  18.843266    southafricawest
Switzerland North     47.451542   8.564572     switzerlandnorth
Switzerland West      46.204391   6.143158     switzerlandwest
Germany North         53.073635   8.806422     germanynorth
Germany West Central  50.110924   8.682127     germanywestcentral
Norway West           58.969975   5.733107     norwaywest
Norway East           59.913868   10.752245    norwayeast

Let's create the resource group using variables

Now let's create the file that will hold the variables

vim terraform.tfvars
# Define the Web server Location
web_server_location   = "westus2"
# Define the Web Server Resource Group Name
web_server_rg         = "web-rg"

Note: A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables.

Now let's refactor the main.tf to use the variables

vim main.tf
## Defining the Variables
variable "web_server_location" {}
variable "web_server_rg" {}


# Provider
# https://www.terraform.io/docs/providers/azurerm/index.html
provider "azurerm" {
  # With Terraform 12 we need to stick with 1.27
  version         = "~> 1.27"
  # The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.
  # subscription_id = "${var.subscription_id}"
  # The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.
  # client_id       = "${var.client_id}"
  # The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.
  # client_secret   = "${var.client_secret}"
  # The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.
  # tenant_id       = "${var.tenant_id}"
}

# Manages a Resource Group.
# https://www.terraform.io/docs/providers/azurerm/r/resource_group.html
resource "azurerm_resource_group" "web_server_rg" {
  # The Name which should be used for this Resource Group.
  # Here we'll use the variable web_server_rg that was declared into terraform.tfvars
  name     = var.web_server_rg
  # The Azure Region where the Resource Group should exist.
  # Here we'll use the variable web_server_location that was declared into terraform.tfvars
  location = var.web_server_location
}

Now we can run the terraform plan to take a look what will happen if we apply the configuration

terraform plan                                                                               238ms  Sat Apr  4 09:44:02 2020
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

As we can see the terraform plan didn't throw any errors, and we have the same configuration as before, now we can apply the configuration

terraform apply                                                                                   7.5s  Sat Apr  4 09:44:20 2020

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Creating...
azurerm_resource_group.web_server_rg: Creation complete after 7s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Now we can check if there is a new resource group into Azure Portal or we can check in the command line

az group list                                                                                    27.8s  Sat Apr  4 09:46:13 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg",
    "location": "westus2",
    "managedBy": null,
    "name": "web-rg",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {},
    "type": "Microsoft.Resources/resourceGroups"
  }
]

As we can see there is a new resource group create by Terraform. Now let's destroy it to continue the configuration.

terraform destroy                                                                               3338ms  Sat Apr  4 09:46:17 2020
azurerm_resource_group.web_server_rg: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be destroyed
  - resource "azurerm_resource_group" "web_server_rg" {
      - id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg" -> null
      - location = "westus2" -> null
      - name     = "web-rg" -> null
      - tags     = {} -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 10s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 20s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 30s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 40s elapsed]
azurerm_resource_group.web_server_rg: Destruction complete after 42s

Destroy complete! Resources: 1 destroyed.

Now let's make sure that there is no resource group named web-rg

az group show --name web-rg                                                                       1.2m  Sat Apr  4 09:48:24 2020
Resource group 'web-rg' could not be found.

Let's list all the resource groups

az group list                                                                               2396ms  Sat Apr  4 09:48:26 2020
[]

Resources:

Azure VNET:

  • Virtual Network
  • Logical isolated network
  • Address space
  • Subnets
  • Connectivity - VNET, VPN, Endpoints
  • NSG

Let's update the file that will hold the variables with the new variables for the VNET

vim terraform.tfvars
# Define the Web server Location
web_server_location       = "westus2"
# Define the Web Server Resource Group Name
web_server_rg             = "web-rg"
# Resource Prefix 
resource_prefix           = "web-server"
# Address Space
web_server_address_space  = "10.0.0.0/22" 

Note: A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables.

Let's Edit the main.tf to use add the new resource called azurerm_virtual_network

vim main.tf
## Defining the Variables
variable "web_server_location" {}
variable "web_server_rg" {}
variable "resource_prefix" {}
variable "web_server_address_space" {}

# Provider
# https://www.terraform.io/docs/providers/azurerm/index.html
provider "azurerm" {
  # With Terraform 12 we need to stick with 1.27
  version         = "~> 1.27"
  # The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.
  # subscription_id = "${var.subscription_id}"
  # The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.
  # client_id       = "${var.client_id}"
  # The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.
  # client_secret   = "${var.client_secret}"
  # The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.
  # tenant_id       = "${var.tenant_id}"
}

# Manages a Resource Group.
# https://www.terraform.io/docs/providers/azurerm/r/resource_group.html
resource "azurerm_resource_group" "web_server_rg" {
  # The Name which should be used for this Resource Group.
  # Here we'll use the variable web_server_rg that was declared into terraform.tfvars
  name     = var.web_server_rg
  # The Azure Region where the Resource Group should exist.
  # Here we'll use the variable web_server_location that was declared into terraform.tfvars
  location = var.web_server_location
}


# Manages a virtual network including any configured subnets. 
# Each subnet can optionally be configured with a security group to be associated with the subnet.
# https://www.terraform.io/docs/providers/azurerm/r/virtual_network.html
resource "azurerm_virtual_network" "web_server_vnet" {
  # (Required) The name of the virtual network. Changing this forces a new resource to be created.
  # Note: here as we need to interpolate the variable with some kind of string we need to use "${}-string" inside quotes
  name                  = "${var.resource_prefix}-vnet"
  # (Required) The location/region where the virtual network is created. Changing this forces a new resource to be created.
  location              = var.web_server_location
  #  (Required) The name of the resource group in which to create the virtual network.
  resource_group_name   = azurerm_resource_group.web_server_rg.name
  # (Required) The address space that is used the virtual network. You can supply more than one address space. Changing this forces a new resource to be created.
  address_space         = [var.web_server_address_space]
}

Now we can run the terraform plan to take a look what will happen if we apply the configuration

terraform plan                                                                                    9.2s  Sat Apr  4 10:12:00 2020
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

As we can see the terraform plan didn't throw any errors, now we can apply the configuration

terraform apply                                                                                 2674ms  Sat Apr  4 10:18:15 2020

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Creating...
azurerm_resource_group.web_server_rg: Creation complete after 8s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Creating...
azurerm_virtual_network.web_server_vnet: Still creating... [10s elapsed]
azurerm_virtual_network.web_server_vnet: Creation complete after 14s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Now we can check if there is a new resource group into Azure Portal or we can check in the command line

az group list                                                                                    38.2s  Sat Apr  4 10:23:07 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg",
    "location": "westus2",
    "managedBy": null,
    "name": "web-rg",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {},
    "type": "Microsoft.Resources/resourceGroups"
  },
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now let's list the VNET

az network vnet list                                                                            2261ms  Sat Apr  4 10:23:15 2020
[
  {
    "addressSpace": {
      "addressPrefixes": [
        "10.0.0.0/22"
      ]
    },
    "bgpCommunities": null,
    "ddosProtectionPlan": null,
    "dhcpOptions": {
      "dnsServers": []
    },
    "enableDdosProtection": false,
    "enableVmProtection": false,
    "etag": "W/\"5d2178ea-d82a-438e-81fc-658424826beb\"",
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet",
    "location": "westus2",
    "name": "web-server-vnet",
    "provisioningState": "Succeeded",
    "resourceGroup": "web-rg",
    "resourceGuid": "00e0ddcd-1a88-4395-8a1c-980c6bec4bdb",
    "subnets": [],
    "tags": {},
    "type": "Microsoft.Network/virtualNetworks",
    "virtualNetworkPeerings": []
  }
]

As we can see there is a new resource group create by Terraform. Now let's destroy it to continue the configuration.

terraform destroy                                                                               2882ms  Sat Apr  4 10:26:53 2020
azurerm_resource_group.web_server_rg: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be destroyed
  - resource "azurerm_resource_group" "web_server_rg" {
      - id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg" -> null
      - location = "westus2" -> null
      - name     = "web-rg" -> null
      - tags     = {} -> null
    }

  # azurerm_virtual_network.web_server_vnet will be destroyed
  - resource "azurerm_virtual_network" "web_server_vnet" {
      - address_space       = [
          - "10.0.0.0/22",
        ] -> null
      - dns_servers         = [] -> null
      - id                  = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet" -> null
      - location            = "westus2" -> null
      - name                = "web-server-vnet" -> null
      - resource_group_name = "web-rg" -> null
      - tags                = {} -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_virtual_network.web_server_vnet: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_virtual_network.web_server_vnet: Destruction complete after 2s
azurerm_resource_group.web_server_rg: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 10s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 20s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 30s elapsed]
azurerm_resource_group.web_server_rg: Destruction complete after 38s

Destroy complete! Resources: 2 destroyed.

Let's list all the resource groups

az group list                                                                                       1m  Sat Apr  4 10:29:56 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now we have only one resource group Called: NetworkWatcherRG, bellow the description about it.

Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. Network diagnostic and visualization tools available with Network Watcher help you understand, diagnose, and gain insights to your network in Azure. Network Watcher is enabled through the creation of a Network Watcher resource. This resource allows you to utilize Network Watcher capabilities.

Resources:

Let's take a look the kinds of dependencies that we may face

This resource has no dependency of another one, it just dependes of the variable web_server_rg and if does not has any default value or declaration when you run plan or apply it will ask you about it.

# No dependency 
resource "azurerm_resource_group" "web_server_rg" { 
  name = var.web_server_rg
}

# No dependency 
resource "azurerm_virtual_network" "web_server_vnet" {
  name                = "${var.resource_prefix}-vnet"
  resource_group_name = var.web_server_rg
}

This resource has indirect dependency of another one, in this case we depend of azurerm_resource_group.web_server_rg.name, when we run the plan or apply and the resource required is not present we shall have a failure about it

# Indirect dependency 
resource "azurerm_virtual_network" "web_server_vnet" {
  name                = "${var.resource_prefix}-vnet"
  resource_group_name = azurerm_resource_group.web_server_rg.name
}

This resource has direct dependency of this one, in this case we depend of azurerm_resource_group.web_server_rg when we run the plan or apply and the resource required is not present we shall have a failure about it. For example we try to create the virtual network inside the resource group that should've be created before this resource we'll have a failure about the dependency.

# Direct dependency 
resource "azurerm_virtual_network" "web_server_vnet" {
  name                = "${var.resource_prefix}-vnet"
  resource_group_name = var.web_server_rg
  depends_on          = [ "azurerm_resource_group.web_server_rg" ]
}

Azure Subnet:

  • Subnetwork within a VNET
  • Address space
  • Segmentation
  • NSG

Let's update the file that will hold the variables with the new variables for the Subnets

vim terraform.tfvars
# Define the Web server Location
web_server_location       = "westus2"
# Define the Web Server Resource Group Name
web_server_rg             = "web-rg"
# Resource Prefix 
resource_prefix           = "web-server"
# Address Space
web_server_address_space  = "10.0.0.0/22" 
# Web Server Address Prefix 
web_server_address_prefix = "10.0.1.0/24"

Note: A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables.

Let's Edit the main.tf to use add the new resource called azurerm_subnet

vim main.tf
## Defining the Variables
variable "web_server_location" {}
variable "web_server_rg" {}
variable "resource_prefix" {}
variable "web_server_address_space" {}
variable "web_server_address_prefix" {}


# Provider
# https://www.terraform.io/docs/providers/azurerm/index.html
provider "azurerm" {
  # With Terraform 12 we need to stick with 1.27
  version         = "~> 1.27"
  # The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.
  # subscription_id = "${var.subscription_id}"
  # The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.
  # client_id       = "${var.client_id}"
  # The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.
  # client_secret   = "${var.client_secret}"
  # The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.
  # tenant_id       = "${var.tenant_id}"
}

# Manages a Resource Group.
# https://www.terraform.io/docs/providers/azurerm/r/resource_group.html
resource "azurerm_resource_group" "web_server_rg" {
  # The Name which should be used for this Resource Group.
  # Here we'll use the variable web_server_rg that was declared into terraform.tfvars
  name     = var.web_server_rg
  # The Azure Region where the Resource Group should exist.
  # Here we'll use the variable web_server_location that was declared into terraform.tfvars
  location = var.web_server_location
}


# Manages a virtual network including any configured subnets. 
# Each subnet can optionally be configured with a security group to be associated with the subnet.
# https://www.terraform.io/docs/providers/azurerm/r/virtual_network.html
resource "azurerm_virtual_network" "web_server_vnet" {
  # (Required) The name of the virtual network. Changing this forces a new resource to be created.
  # Note: here as we need to interpolate the variable with some kind of string we need to use "${}-string" inside quotes
  name                  = "${var.resource_prefix}-vnet"
  # (Required) The location/region where the virtual network is created. Changing this forces a new resource to be created.
  location              = var.web_server_location
  #  (Required) The name of the resource group in which to create the virtual network.
  resource_group_name   = azurerm_resource_group.web_server_rg.name
  # (Required) The address space that is used the virtual network. You can supply more than one address space. Changing this forces a new resource to be created.
  address_space         = [var.web_server_address_space]
}


# Manages a subnet. Subnets represent network segments within the IP space defined by the virtual network.
# https://www.terraform.io/docs/providers/azurerm/r/subnet.html
resource "azurerm_subnet" "web_server_subnet" {
  #  (Required) The name of the subnet. Changing this forces a new resource to be created
  name                      = "${var.resource_prefix}-subnet"
  # (Required) The name of the resource group in which to create the subnet. Changing this forces a new resource to be created.
  resource_group_name       = azurerm_resource_group.web_server_rg.name
  # (Required) The name of the virtual network to which to attach the subnet. Changing this forces a new resource to be created.
  virtual_network_name      = azurerm_virtual_network.web_server_vnet.name
  # (Required) The address prefix to use for the subnet.
  address_prefix            = var.web_server_address_prefix
}

Now we can run the terraform plan to take a look what will happen if we apply the configuration

terraform plan                                                                                  2688ms  Sat Apr  4 10:30:29 2020
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_subnet.web_server_subnet will be created
  + resource "azurerm_subnet" "web_server_subnet" {
      + address_prefix                                 = "10.0.1.0/24"
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + ip_configurations                              = (known after apply)
      + name                                           = "web-server-subnet"
      + resource_group_name                            = "web-rg"
      + virtual_network_name                           = "web-server-vnet"
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 3 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

As we can see the terraform plan didn't throw any errors, now we can apply the configuration

terraform apply                                                                                   7.2s  Sat Apr  4 11:14:35 2020

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_subnet.web_server_subnet will be created
  + resource "azurerm_subnet" "web_server_subnet" {
      + address_prefix                                 = "10.0.1.0/24"
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + ip_configurations                              = (known after apply)
      + name                                           = "web-server-subnet"
      + resource_group_name                            = "web-rg"
      + virtual_network_name                           = "web-server-vnet"
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Creating...
azurerm_resource_group.web_server_rg: Creation complete after 4s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Creating...
azurerm_virtual_network.web_server_vnet: Still creating... [10s elapsed]
azurerm_virtual_network.web_server_vnet: Creation complete after 13s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_subnet.web_server_subnet: Creating...
azurerm_subnet.web_server_subnet: Creation complete after 3s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Now we can check if there is a new resource group into Azure Portal or we can check in the command line

az group list                                                                                    43.2s  Sat Apr  4 11:22:47 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  },
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg",
    "location": "westus2",
    "managedBy": null,
    "name": "web-rg",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {},
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now let's list the VNET

az network vnet list                                                                            2999ms  Sat Apr  4 11:22:53 2020
[
  {
    "addressSpace": {
      "addressPrefixes": [
        "10.0.0.0/22"
      ]
    },
    "bgpCommunities": null,
    "ddosProtectionPlan": null,
    "dhcpOptions": {
      "dnsServers": []
    },
    "enableDdosProtection": false,
    "enableVmProtection": false,
    "etag": "W/\"41bc2a42-e22f-49c8-a396-6aae118adae3\"",
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet",
    "location": "westus2",
    "name": "web-server-vnet",
    "provisioningState": "Succeeded",
    "resourceGroup": "web-rg",
    "resourceGuid": "a1b2d72a-c6c4-4314-8b19-4019519229c6",
    "subnets": [
      {
        "addressPrefix": "10.0.1.0/24",
        "addressPrefixes": null,
        "delegations": [],
        "etag": "W/\"41bc2a42-e22f-49c8-a396-6aae118adae3\"",
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet",
        "ipConfigurationProfiles": null,
        "ipConfigurations": null,
        "name": "web-server-subnet",
        "natGateway": null,
        "networkSecurityGroup": null,
        "privateEndpointNetworkPolicies": "Enabled",
        "privateEndpoints": null,
        "privateLinkServiceNetworkPolicies": "Enabled",
        "provisioningState": "Succeeded",
        "purpose": null,
        "resourceGroup": "web-rg",
        "resourceNavigationLinks": null,
        "routeTable": null,
        "serviceAssociationLinks": null,
        "serviceEndpointPolicies": null,
        "serviceEndpoints": [],
        "type": "Microsoft.Network/virtualNetworks/subnets"
      }
    ],
    "tags": {},
    "type": "Microsoft.Network/virtualNetworks",
    "virtualNetworkPeerings": []
  }
]

Now let's list the subnet that we've just created

az network vnet subnet list -g web-rg --vnet-name web-server-vnet                               2398ms  Sat Apr  4 11:23:48 2020
[
  {
    "addressPrefix": "10.0.1.0/24",
    "addressPrefixes": null,
    "delegations": [],
    "etag": "W/\"41bc2a42-e22f-49c8-a396-6aae118adae3\"",
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet",
    "ipConfigurationProfiles": null,
    "ipConfigurations": null,
    "name": "web-server-subnet",
    "natGateway": null,
    "networkSecurityGroup": null,
    "privateEndpointNetworkPolicies": "Enabled",
    "privateEndpoints": null,
    "privateLinkServiceNetworkPolicies": "Enabled",
    "provisioningState": "Succeeded",
    "purpose": null,
    "resourceGroup": "web-rg",
    "resourceNavigationLinks": null,
    "routeTable": null,
    "serviceAssociationLinks": null,
    "serviceEndpointPolicies": null,
    "serviceEndpoints": [],
    "type": "Microsoft.Network/virtualNetworks/subnets"
  }
]

As we can see there is a new resource group create by Terraform. Now let's destroy it to continue the configuration.

terraform destroy                                                                               1657ms  Sat Apr  4 11:25:19 2020
azurerm_resource_group.web_server_rg: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_subnet.web_server_subnet: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_resource_group.web_server_rg will be destroyed
  - resource "azurerm_resource_group" "web_server_rg" {
      - id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg" -> null
      - location = "westus2" -> null
      - name     = "web-rg" -> null
      - tags     = {} -> null
    }

  # azurerm_subnet.web_server_subnet will be destroyed
  - resource "azurerm_subnet" "web_server_subnet" {
      - address_prefix                                 = "10.0.1.0/24" -> null
      - enforce_private_link_endpoint_network_policies = false -> null
      - enforce_private_link_service_network_policies  = false -> null
      - id                                             = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet" -> null
      - ip_configurations                              = [] -> null
      - name                                           = "web-server-subnet" -> null
      - resource_group_name                            = "web-rg" -> null
      - service_endpoints                              = [] -> null
      - virtual_network_name                           = "web-server-vnet" -> null
    }

  # azurerm_virtual_network.web_server_vnet will be destroyed
  - resource "azurerm_virtual_network" "web_server_vnet" {
      - address_space       = [
          - "10.0.0.0/22",
        ] -> null
      - dns_servers         = [] -> null
      - id                  = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet" -> null
      - location            = "westus2" -> null
      - name                = "web-server-vnet" -> null
      - resource_group_name = "web-rg" -> null
      - tags                = {} -> null

      - subnet {
          - address_prefix = "10.0.1.0/24" -> null
          - id             = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet" -> null
          - name           = "web-server-subnet" -> null
        }
    }

Plan: 0 to add, 0 to change, 3 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_subnet.web_server_subnet: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]
azurerm_subnet.web_server_subnet: Destruction complete after 2s
azurerm_virtual_network.web_server_vnet: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_virtual_network.web_server_vnet: Destruction complete after 2s
azurerm_resource_group.web_server_rg: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 10s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 20s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 30s elapsed]
azurerm_resource_group.web_server_rg: Destruction complete after 39s

Destroy complete! Resources: 3 destroyed.

Let's list all the resource groups

az group list                                                                                       1m  Sat Apr  4 11:29:01 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now we have only one resource group Called: NetworkWatcherRG, bellow the description about it.

Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. Network diagnostic and visualization tools available with Network Watcher help you understand, diagnose, and gain insights to your network in Azure. Network Watcher is enabled through the creation of a Network Watcher resource. This resource allows you to utilize Network Watcher capabilities.

Resources:

Azure Network Interface:

  • Subnet/VNET
  • IP Private and Public
  • Static and Dynamic
  • DNS Settings
  • NSG

Let's update the file that will hold the variables with the new variables for the Network Interfaces

vim terraform.tfvars
# Define the Web server Location
web_server_location       = "westus2"
# Define the Web Server Resource Group Name
web_server_rg             = "web-rg"
# Resource Prefix 
resource_prefix           = "web-server"
# Address Space
web_server_address_space  = "10.0.0.0/22" 
# Web Server Address Prefix 
web_server_address_prefix = "10.0.1.0/24"
# Web Server Name
web_server_name           = "web-01"

Note: A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables.

Let's Edit the main.tf to use add the new resource called azurerm_subnet

vim main.tf
## Defining the Variables
variable "web_server_location" {}
variable "web_server_rg" {}
variable "resource_prefix" {}
variable "web_server_address_space" {}
variable "web_server_address_prefix" {}
variable "web_server_name" {}



# Provider
# https://www.terraform.io/docs/providers/azurerm/index.html
provider "azurerm" {
  # With Terraform 12 we need to stick with 1.27
  version         = "~> 1.27"
  # The Subscription ID which should be used. This can also be sourced from the ARM_SUBSCRIPTION_ID Environment Variable.
  # subscription_id = "${var.subscription_id}"
  # The Client ID which should be used. This can also be sourced from the ARM_CLIENT_ID Environment Variable.
  # client_id       = "${var.client_id}"
  # The Client Secret which should be used. This can also be sourced from the ARM_CLIENT_SECRET Environment Variable.
  # client_secret   = "${var.client_secret}"
  # The Tenant ID which should be used. This can also be sourced from the ARM_TENANT_ID Environment Variable.
  # tenant_id       = "${var.tenant_id}"
}

# Manages a Resource Group.
# https://www.terraform.io/docs/providers/azurerm/r/resource_group.html
resource "azurerm_resource_group" "web_server_rg" {
  # The Name which should be used for this Resource Group.
  # Here we'll use the variable web_server_rg that was declared into terraform.tfvars
  name     = var.web_server_rg
  # The Azure Region where the Resource Group should exist.
  # Here we'll use the variable web_server_location that was declared into terraform.tfvars
  location = var.web_server_location
}


# Manages a virtual network including any configured subnets. 
# Each subnet can optionally be configured with a security group to be associated with the subnet.
# https://www.terraform.io/docs/providers/azurerm/r/virtual_network.html
resource "azurerm_virtual_network" "web_server_vnet" {
  # (Required) The name of the virtual network. Changing this forces a new resource to be created.
  # Note: here as we need to interpolate the variable with some kind of string we need to use "${}-string" inside quotes
  name                  = "${var.resource_prefix}-vnet"
  # (Required) The location/region where the virtual network is created. Changing this forces a new resource to be created.
  location              = var.web_server_location
  #  (Required) The name of the resource group in which to create the virtual network.
  resource_group_name   = azurerm_resource_group.web_server_rg.name
  # (Required) The address space that is used the virtual network. You can supply more than one address space. Changing this forces a new resource to be created.
  address_space         = [var.web_server_address_space]
}


# Manages a subnet. Subnets represent network segments within the IP space defined by the virtual network.
# https://www.terraform.io/docs/providers/azurerm/r/subnet.html
resource "azurerm_subnet" "web_server_subnet" {
  #  (Required) The name of the subnet. Changing this forces a new resource to be created
  name                      = "${var.resource_prefix}-subnet"
  # (Required) The name of the resource group in which to create the subnet. Changing this forces a new resource to be created.
  resource_group_name       = azurerm_resource_group.web_server_rg.name
  # (Required) The name of the virtual network to which to attach the subnet. Changing this forces a new resource to be created.
  virtual_network_name      = azurerm_virtual_network.web_server_vnet.name
  # (Required) The address prefix to use for the subnet.
  address_prefix            = var.web_server_address_prefix
}

# Manages a Network Interface.
# https://www.terraform.io/docs/providers/azurerm/r/network_interface.html
resource "azurerm_network_interface" "web_server_nic" {
  # (Required) The name of the Network Interface. Changing this forces a new resource to be created.
  name                      = "${var.web_server_name}-nic"
  # (Required) The location where the Network Interface should exist. Changing this forces a new resource to be created.
  location                  = var.web_server_location
  # (Required) The name of the Resource Group in which to create the Network Interface. Changing this forces a new resource to be created.
  resource_group_name       = azurerm_resource_group.web_server_rg.name

  # (Required) One or more ip_configuration blocks as defined below.
  ip_configuration {
    # (Required) A name used for this IP Configuration.
    name                          = "${var.web_server_name}-ip"
    # (Optional) The ID of the Subnet where this Network Interface should be located in.
    subnet_id                     = azurerm_subnet.web_server_subnet.id
    # (Optional) The IP Version to use. Possible values are IPv4 or IPv6. Defaults to IPv4.
    private_ip_address_version    = "IPv4"
    # (Required) The allocation method used for the Private IP Address. Possible values are Dynamic and Static.
    private_ip_address_allocation = "Dynamic"
  }
}

Now we can run the terraform plan to take a look what will happen if we apply the configuration

terraform plan                                                                                  3389ms  Sat Apr  4 11:29:34 2020
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_network_interface.web_server_nic will be created
  + resource "azurerm_network_interface" "web_server_nic" {
      + applied_dns_servers           = (known after apply)
      + dns_servers                   = (known after apply)
      + enable_accelerated_networking = false
      + enable_ip_forwarding          = false
      + id                            = (known after apply)
      + internal_dns_name_label       = (known after apply)
      + internal_fqdn                 = (known after apply)
      + location                      = "westus2"
      + mac_address                   = (known after apply)
      + name                          = "web-01-nic"
      + private_ip_address            = (known after apply)
      + private_ip_addresses          = (known after apply)
      + resource_group_name           = "web-rg"
      + tags                          = (known after apply)
      + virtual_machine_id            = (known after apply)

      + ip_configuration {
          + application_gateway_backend_address_pools_ids = (known after apply)
          + application_security_group_ids                = (known after apply)
          + load_balancer_backend_address_pools_ids       = (known after apply)
          + load_balancer_inbound_nat_rules_ids           = (known after apply)
          + name                                          = "web-01-ip"
          + primary                                       = (known after apply)
          + private_ip_address                            = (known after apply)
          + private_ip_address_allocation                 = "dynamic"
          + private_ip_address_version                    = "IPv4"
          + subnet_id                                     = (known after apply)
        }
    }

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_subnet.web_server_subnet will be created
  + resource "azurerm_subnet" "web_server_subnet" {
      + address_prefix                                 = "10.0.1.0/24"
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + ip_configurations                              = (known after apply)
      + name                                           = "web-server-subnet"
      + resource_group_name                            = "web-rg"
      + virtual_network_name                           = "web-server-vnet"
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

As we can see the terraform plan didn't throw any errors, now we can apply the configuration

terraform apply                                                                                     9s  Sat Apr  4 12:05:28 2020

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_network_interface.web_server_nic will be created
  + resource "azurerm_network_interface" "web_server_nic" {
      + applied_dns_servers           = (known after apply)
      + dns_servers                   = (known after apply)
      + enable_accelerated_networking = false
      + enable_ip_forwarding          = false
      + id                            = (known after apply)
      + internal_dns_name_label       = (known after apply)
      + internal_fqdn                 = (known after apply)
      + location                      = "westus2"
      + mac_address                   = (known after apply)
      + name                          = "web-01-nic"
      + private_ip_address            = (known after apply)
      + private_ip_addresses          = (known after apply)
      + resource_group_name           = "web-rg"
      + tags                          = (known after apply)
      + virtual_machine_id            = (known after apply)

      + ip_configuration {
          + application_gateway_backend_address_pools_ids = (known after apply)
          + application_security_group_ids                = (known after apply)
          + load_balancer_backend_address_pools_ids       = (known after apply)
          + load_balancer_inbound_nat_rules_ids           = (known after apply)
          + name                                          = "web-01-ip"
          + primary                                       = (known after apply)
          + private_ip_address                            = (known after apply)
          + private_ip_address_allocation                 = "dynamic"
          + private_ip_address_version                    = "IPv4"
          + subnet_id                                     = (known after apply)
        }
    }

  # azurerm_resource_group.web_server_rg will be created
  + resource "azurerm_resource_group" "web_server_rg" {
      + id       = (known after apply)
      + location = "westus2"
      + name     = "web-rg"
      + tags     = (known after apply)
    }

  # azurerm_subnet.web_server_subnet will be created
  + resource "azurerm_subnet" "web_server_subnet" {
      + address_prefix                                 = "10.0.1.0/24"
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + ip_configurations                              = (known after apply)
      + name                                           = "web-server-subnet"
      + resource_group_name                            = "web-rg"
      + virtual_network_name                           = "web-server-vnet"
    }

  # azurerm_virtual_network.web_server_vnet will be created
  + resource "azurerm_virtual_network" "web_server_vnet" {
      + address_space       = [
          + "10.0.0.0/22",
        ]
      + id                  = (known after apply)
      + location            = "westus2"
      + name                = "web-server-vnet"
      + resource_group_name = "web-rg"
      + tags                = (known after apply)

      + subnet {
          + address_prefix = (known after apply)
          + id             = (known after apply)
          + name           = (known after apply)
          + security_group = (known after apply)
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_resource_group.web_server_rg: Creating...
azurerm_resource_group.web_server_rg: Creation complete after 8s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Creating...
azurerm_virtual_network.web_server_vnet: Still creating... [10s elapsed]
azurerm_virtual_network.web_server_vnet: Creation complete after 11s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_subnet.web_server_subnet: Creating...
azurerm_subnet.web_server_subnet: Creation complete after 4s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]
azurerm_network_interface.web_server_nic: Creating...
azurerm_network_interface.web_server_nic: Still creating... [10s elapsed]
azurerm_network_interface.web_server_nic: Creation complete after 11s [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Now we can check if there is a new resource group into Azure Portal or we can check in the command line

az group list                                                                                    55.5s  Sat Apr  4 12:06:37 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  },
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg",
    "location": "westus2",
    "managedBy": null,
    "name": "web-rg",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": {},
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now let's list the VNET

az network vnet list                                                                            2279ms  Sat Apr  4 12:07:09 2020
[
  {
    "addressSpace": {
      "addressPrefixes": [
        "10.0.0.0/22"
      ]
    },
    "bgpCommunities": null,
    "ddosProtectionPlan": null,
    "dhcpOptions": {
      "dnsServers": []
    },
    "enableDdosProtection": false,
    "enableVmProtection": false,
    "etag": "W/\"c02bebd6-a1a2-4f17-adbc-fa6b80d5d8d5\"",
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet",
    "location": "westus2",
    "name": "web-server-vnet",
    "provisioningState": "Succeeded",
    "resourceGroup": "web-rg",
    "resourceGuid": "9d8309a8-6867-4f34-93b0-e82af625acd5",
    "subnets": [
      {
        "addressPrefix": "10.0.1.0/24",
        "addressPrefixes": null,
        "delegations": [],
        "etag": "W/\"c02bebd6-a1a2-4f17-adbc-fa6b80d5d8d5\"",
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet",
        "ipConfigurationProfiles": null,
        "ipConfigurations": [
          {
            "etag": null,
            "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic/ipConfigurations/web-01-ip",
            "name": null,
            "privateIpAddress": null,
            "privateIpAllocationMethod": null,
            "provisioningState": null,
            "publicIpAddress": null,
            "resourceGroup": "web-rg",
            "subnet": null
          }
        ],
        "name": "web-server-subnet",
        "natGateway": null,
        "networkSecurityGroup": null,
        "privateEndpointNetworkPolicies": "Enabled",
        "privateEndpoints": null,
        "privateLinkServiceNetworkPolicies": "Enabled",
        "provisioningState": "Succeeded",
        "purpose": null,
        "resourceGroup": "web-rg",
        "resourceNavigationLinks": null,
        "routeTable": null,
        "serviceAssociationLinks": null,
        "serviceEndpointPolicies": null,
        "serviceEndpoints": [],
        "type": "Microsoft.Network/virtualNetworks/subnets"
      }
    ],
    "tags": {},
    "type": "Microsoft.Network/virtualNetworks",
    "virtualNetworkPeerings": []
  }
]

Now let's list the subnet that we've just created

az network vnet subnet list -g web-rg --vnet-name web-server-vnet                               1799ms  Sat Apr  4 12:07:47 2020
[
  {
    "addressPrefix": "10.0.1.0/24",
    "addressPrefixes": null,
    "delegations": [],
    "etag": "W/\"c02bebd6-a1a2-4f17-adbc-fa6b80d5d8d5\"",
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet",
    "ipConfigurationProfiles": null,
    "ipConfigurations": [
      {
        "etag": null,
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic/ipConfigurations/web-01-ip",
        "name": null,
        "privateIpAddress": null,
        "privateIpAllocationMethod": null,
        "provisioningState": null,
        "publicIpAddress": null,
        "resourceGroup": "web-rg",
        "subnet": null
      }
    ],
    "name": "web-server-subnet",
    "natGateway": null,
    "networkSecurityGroup": null,
    "privateEndpointNetworkPolicies": "Enabled",
    "privateEndpoints": null,
    "privateLinkServiceNetworkPolicies": "Enabled",
    "provisioningState": "Succeeded",
    "purpose": null,
    "resourceGroup": "web-rg",
    "resourceNavigationLinks": null,
    "routeTable": null,
    "serviceAssociationLinks": null,
    "serviceEndpointPolicies": null,
    "serviceEndpoints": [],
    "type": "Microsoft.Network/virtualNetworks/subnets"
  }
]

Now Let's list the network Interface

az network nic list                                                                         1133ms  Sat Apr  4 12:16:13 2020
[
  {
    "dnsSettings": {
      "appliedDnsServers": [],
      "dnsServers": [],
      "internalDnsNameLabel": null,
      "internalDomainNameSuffix": "vaeyhhlhna0e5e3q3avpmjnm0f.xx.internal.cloudapp.net",
      "internalFqdn": null
    },
    "enableAcceleratedNetworking": false,
    "enableIpForwarding": false,
    "etag": "W/\"83c39a33-4a93-4f8a-a57b-3513dbd8f95a\"",
    "hostedWorkloads": [],
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic",
    "ipConfigurations": [
      {
        "applicationGatewayBackendAddressPools": null,
        "applicationSecurityGroups": null,
        "etag": "W/\"83c39a33-4a93-4f8a-a57b-3513dbd8f95a\"",
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic/ipConfigurations/web-01-ip",
        "loadBalancerBackendAddressPools": null,
        "loadBalancerInboundNatRules": null,
        "name": "web-01-ip",
        "primary": true,
        "privateIpAddress": "10.0.1.4",
        "privateIpAddressVersion": "IPv4",
        "privateIpAllocationMethod": "Dynamic",
        "privateLinkConnectionProperties": null,
        "provisioningState": "Succeeded",
        "publicIpAddress": null,
        "resourceGroup": "web-rg",
        "subnet": {
          "addressPrefix": null,
          "addressPrefixes": null,
          "delegations": null,
          "etag": null,
          "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet",
          "ipConfigurationProfiles": null,
          "ipConfigurations": null,
          "name": null,
          "natGateway": null,
          "networkSecurityGroup": null,
          "privateEndpointNetworkPolicies": null,
          "privateEndpoints": null,
          "privateLinkServiceNetworkPolicies": null,
          "provisioningState": null,
          "purpose": null,
          "resourceGroup": "web-rg",
          "resourceNavigationLinks": null,
          "routeTable": null,
          "serviceAssociationLinks": null,
          "serviceEndpointPolicies": null,
          "serviceEndpoints": null
        },
        "type": "Microsoft.Network/networkInterfaces/ipConfigurations",
        "virtualNetworkTaps": null
      }
    ],
    "location": "westus2",
    "macAddress": null,
    "name": "web-01-nic",
    "networkSecurityGroup": null,
    "primary": null,
    "privateEndpoint": null,
    "provisioningState": "Succeeded",
    "resourceGroup": "web-rg",
    "resourceGuid": "7f7c3993-8682-41c6-868a-87afaedb4618",
    "tags": {},
    "tapConfigurations": [],
    "type": "Microsoft.Network/networkInterfaces",
    "virtualMachine": null
  }
]

As we can see there is a new resource group create by Terraform. Now let's destroy it to continue the configuration.

terraform destroy                                                                               1855ms  Sat Apr  4 12:17:05 2020
azurerm_resource_group.web_server_rg: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_virtual_network.web_server_vnet: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_subnet.web_server_subnet: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]
azurerm_network_interface.web_server_nic: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_network_interface.web_server_nic will be destroyed
  - resource "azurerm_network_interface" "web_server_nic" {
      - applied_dns_servers           = [] -> null
      - dns_servers                   = [] -> null
      - enable_accelerated_networking = false -> null
      - enable_ip_forwarding          = false -> null
      - id                            = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic" -> null
      - location                      = "westus2" -> null
      - name                          = "web-01-nic" -> null
      - private_ip_address            = "10.0.1.4" -> null
      - private_ip_addresses          = [
          - "10.0.1.4",
        ] -> null
      - resource_group_name           = "web-rg" -> null
      - tags                          = {} -> null

      - ip_configuration {
          - application_gateway_backend_address_pools_ids = [] -> null
          - application_security_group_ids                = [] -> null
          - load_balancer_backend_address_pools_ids       = [] -> null
          - load_balancer_inbound_nat_rules_ids           = [] -> null
          - name                                          = "web-01-ip" -> null
          - primary                                       = true -> null
          - private_ip_address                            = "10.0.1.4" -> null
          - private_ip_address_allocation                 = "dynamic" -> null
          - private_ip_address_version                    = "IPv4" -> null
          - subnet_id                                     = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet" -> null
        }
    }

  # azurerm_resource_group.web_server_rg will be destroyed
  - resource "azurerm_resource_group" "web_server_rg" {
      - id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg" -> null
      - location = "westus2" -> null
      - name     = "web-rg" -> null
      - tags     = {} -> null
    }

  # azurerm_subnet.web_server_subnet will be destroyed
  - resource "azurerm_subnet" "web_server_subnet" {
      - address_prefix                                 = "10.0.1.0/24" -> null
      - enforce_private_link_endpoint_network_policies = false -> null
      - enforce_private_link_service_network_policies  = false -> null
      - id                                             = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet" -> null
      - ip_configurations                              = [
          - "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic/ipConfigurations/web-01-ip",
        ] -> null
      - name                                           = "web-server-subnet" -> null
      - resource_group_name                            = "web-rg" -> null
      - service_endpoints                              = [] -> null
      - virtual_network_name                           = "web-server-vnet" -> null
    }

  # azurerm_virtual_network.web_server_vnet will be destroyed
  - resource "azurerm_virtual_network" "web_server_vnet" {
      - address_space       = [
          - "10.0.0.0/22",
        ] -> null
      - dns_servers         = [] -> null
      - id                  = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet" -> null
      - location            = "westus2" -> null
      - name                = "web-server-vnet" -> null
      - resource_group_name = "web-rg" -> null
      - tags                = {} -> null

      - subnet {
          - address_prefix = "10.0.1.0/24" -> null
          - id             = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet" -> null
          - name           = "web-server-subnet" -> null
        }
    }

Plan: 0 to add, 0 to change, 4 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

azurerm_network_interface.web_server_nic: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/networkInterfaces/web-01-nic]
azurerm_network_interface.web_server_nic: Destruction complete after 3s
azurerm_subnet.web_server_subnet: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet/subnets/web-server-subnet]
azurerm_subnet.web_server_subnet: Destruction complete after 3s
azurerm_virtual_network.web_server_vnet: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet]
azurerm_virtual_network.web_server_vnet: Destruction complete after 2s
azurerm_resource_group.web_server_rg: Destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 10s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 20s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 30s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 40s elapsed]
azurerm_resource_group.web_server_rg: Still destroying... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/web-rg, 50s elapsed]
azurerm_resource_group.web_server_rg: Destruction complete after 53s

Destroy complete! Resources: 4 destroyed.

Let's list all the resource groups

az group list                                                                                       1m  Sat Apr  4 11:29:01 2020
[
  {
    "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/NetworkWatcherRG",
    "location": "westus2",
    "managedBy": null,
    "name": "NetworkWatcherRG",
    "properties": {
      "provisioningState": "Succeeded"
    },
    "tags": null,
    "type": "Microsoft.Resources/resourceGroups"
  }
]

Now we have only one resource group Called: NetworkWatcherRG, bellow the description about it.

Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. Network diagnostic and visualization tools available with Network Watcher help you understand, diagnose, and gain insights to your network in Azure. Network Watcher is enabled through the creation of a Network Watcher resource. This resource allows you to utilize Network Watcher capabilities.

Resources: