├── .gitignore ├── LICENSE ├── README.md └── code ├── 01-hello-world ├── README.md └── main.tf ├── 02-one-server ├── README.md └── main.tf ├── 03-one-webserver ├── README.md └── main.tf ├── 04-one-webserver-with-vars ├── README.md ├── main.tf ├── outputs.tf └── vars.tf ├── 05-cluster-webserver ├── README.md ├── main.tf ├── outputs.tf └── vars.tf ├── 06-create-blob-storage ├── README.md ├── main.tf ├── outputs.tf └── vars.tf └── 07-terraform-state ├── README.md ├── backend.tf └── main.tf /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | .terraform/ 3 | **/.terraform/* 4 | 5 | # Terraform .tfstate files 6 | *.tfstate 7 | *.tfstate.* 8 | 9 | # Terraform .tfvars files, which are likely to contain sensitive data 10 | *.tfvars 11 | *.tfvars.json 12 | 13 | # Terraform override files as they are usually used to override resources locally 14 | override.tf 15 | override.tf.json 16 | *_override.tf 17 | *_override.tf.json 18 | 19 | # Terraform CLI configuration files 20 | .terraformrc 21 | terraform.rc 22 | 23 | # logs 24 | *.log 25 | 26 | # Mac .DS_Store files 27 | .DS_Store 28 | 29 | # vscode files 30 | .vscode/ 31 | 32 | # SSH Keys 33 | *.pem 34 | 35 | # Backup files 36 | *.bak 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Alfonso Fernandez-Barandiaran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform examples on Microsoft Azure 2 | 3 | Terraform is an open-source infrastructure as code software tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files. 4 | 5 | Terraform is used to create, manage, and update infrastructure resources such as VMs, storage, containers, and more. Almost any infrastructure type can be represented as a resource in Terraform. 6 | 7 | This repo contains [Terraform](https://www.terraform.io/) code examples on Microsoft Azure. 8 | 9 | The Github repository 10 | [https://github.com/alfonsof/terraform-examples-aws](https://github.com/alfonsof/terraform-examples-aws) 11 | contains the code samples based in the book *[Terraform: Up and Running](http://www.terraformupandrunning.com)* by [Yevgeniy Brikman](http://www.ybrikman.com). But those examples use AWS (Amazon Web Services). 12 | 13 | Terraform also supports other Cloud providers and this Github repository contains the code samples of the book on Microsoft Azure. 14 | 15 | ## Quick start 16 | 17 | You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 18 | 19 | The code consists of Terraform examples using HashiCorp Configuration Language (HCL) on Microsoft Azure. 20 | 21 | All the code is in the [code](/code) folder. 22 | 23 | For instructions on running the code, please consult the README in each folder. 24 | 25 | This is the list of examples: 26 | 27 | * [01-hello-world](code/01-hello-world) - Terraform "Hello, World": Example of how to deploy a single server on Microsoft Azure using the shortest script. 28 | * [02-one-server](code/02-one-server) - Terraform One Server: Example of how deploy a single server on Microsoft Azure. 29 | * [03-one-webserver](code/03-one-webserver) - Terraform Web Server: Example of how deploy a single web server on Microsoft Azure. The web server returns "Hello, World" for the URL `/` listening on port 8080. 30 | * [04-one-webserver-with-vars](code/04-one-webserver-with-vars) - Terraform Web Server with vars: Example of how deploy a single web server on Microsoft Azure. The web server returns "Hello, World" for the URL `/` listening on port 8080, which is defined as a variable. 31 | * [05-cluster-webserver](code/05-cluster-webserver) - Terraform Cluster Web Server: Example of how deploy a cluster of web servers on Microsoft Azure using Azure Virtual Machine Scale Set, as well as a load balancer using Azure Load Balancer. The cluster of web servers returns "Hello, World" for the URL `/`. The load balancer listens on port 80. 32 | * [06-create-blob-storage](code/06-create-blob-storage) - Terraform Create Blob Storage: Example of how deploy the creation of a Blob Storage container on Microsoft Azure. 33 | * [07-terraform-state](code/07-terraform-state) - Terraform State: Example of how to store the information about what infrastructure has been created on Microsoft Azure. 34 | 35 | ## License 36 | 37 | This code is released under the MIT License. See LICENSE file. 38 | -------------------------------------------------------------------------------- /code/01-hello-world/README.md: -------------------------------------------------------------------------------- 1 | # Terraform "Hello, World" example 2 | 3 | This folder contains a "Hello, World" example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a single server on Microsoft Azure by provisioning the necessary infrastructure, and using the shortest script. 6 | 7 | ## Requirements 8 | 9 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 10 | 11 | * You must have the following installed: 12 | * [Terraform](https://www.terraform.io/) CLI 13 | * Azure CLI tool 14 | 15 | * The code was written for: 16 | * Terraform 0.14 or later 17 | 18 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 19 | 20 | ## Using the code 21 | 22 | * Configure your access to Azure. 23 | 24 | * Authenticate using the Azure CLI. 25 | 26 | Terraform must authenticate to Azure to create infrastructure. 27 | 28 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 29 | 30 | ```bash 31 | az login 32 | ``` 33 | 34 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 35 | 36 | You have logged in. Now let us find all the subscriptions to which you have access... 37 | 38 | ```bash 39 | [ 40 | { 41 | "cloudName": "", 42 | "homeTenantId": "", 43 | "id": "", 44 | "isDefault": true, 45 | "managedByTenants": [], 46 | "name": "", 47 | "state": "Enabled", 48 | "tenantId": "", 49 | "user": { 50 | "name": "", 51 | "type": "user" 52 | } 53 | } 54 | ] 55 | ``` 56 | 57 | Find the `id` column for the subscription account you want to use. 58 | 59 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 60 | 61 | ```bash 62 | az account set --subscription "" 63 | ``` 64 | 65 | * Create a Service Principal. 66 | 67 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 68 | 69 | Create a Service Principal: 70 | 71 | ```bash 72 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 73 | 74 | Creating 'Contributor' role assignment under scope '/subscriptions/' 75 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 76 | { 77 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 78 | "displayName": "azure-cli-2022-xxxx", 79 | "password": "xxxxxx~xxxxxx~xxxxx", 80 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 81 | } 82 | ``` 83 | 84 | * Set your environment variables. 85 | 86 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 87 | 88 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 89 | 90 | * For MacOS/Linux: 91 | 92 | ```bash 93 | export ARM_CLIENT_ID="" 94 | export ARM_CLIENT_SECRET="" 95 | export ARM_SUBSCRIPTION_ID="" 96 | export ARM_TENANT_ID="" 97 | ``` 98 | 99 | * For Windows (PowerShell): 100 | 101 | ```bash 102 | $env:ARM_CLIENT_ID="" 103 | $env:ARM_CLIENT_SECRET="" 104 | $env:ARM_SUBSCRIPTION_ID="" 105 | $env:ARM_TENANT_ID="" 106 | ``` 107 | 108 | * Initialize Terraform configuration. 109 | 110 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 111 | 112 | 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. 113 | 114 | Run command: 115 | 116 | ```bash 117 | terraform init 118 | ``` 119 | 120 | * Validate the changes. 121 | 122 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 123 | 124 | Run command: 125 | 126 | ```bash 127 | terraform plan 128 | ``` 129 | 130 | * Apply the changes. 131 | 132 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 133 | 134 | Run command: 135 | 136 | ```bash 137 | terraform apply 138 | ``` 139 | 140 | * Test the changes. 141 | 142 | When the `terraform apply` command completes, use the Azure console, you should see the new Virtual Machine created. 143 | 144 | * Clean up the resources created. 145 | 146 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 147 | 148 | Run command: 149 | 150 | ```bash 151 | terraform destroy 152 | ``` 153 | -------------------------------------------------------------------------------- /code/01-hello-world/main.tf: -------------------------------------------------------------------------------- 1 | # Configure the Microsoft Azure provider 2 | provider "azurerm" { 3 | features {} 4 | } 5 | 6 | # Create a Resource Group if it doesn’t exist 7 | resource "azurerm_resource_group" "tfexample" { 8 | name = "my-terraform-rg" 9 | location = "West Europe" 10 | } 11 | 12 | # Create a Virtual Network 13 | resource "azurerm_virtual_network" "tfexample" { 14 | name = "my-terraform-vnet" 15 | location = azurerm_resource_group.tfexample.location 16 | resource_group_name = azurerm_resource_group.tfexample.name 17 | address_space = ["10.0.0.0/16"] 18 | } 19 | 20 | # Create a Subnet in the Virtual Network 21 | resource "azurerm_subnet" "tfexample" { 22 | name = "my-terraform-subnet" 23 | resource_group_name = azurerm_resource_group.tfexample.name 24 | virtual_network_name = azurerm_virtual_network.tfexample.name 25 | address_prefixes = ["10.0.2.0/24"] 26 | } 27 | 28 | # Create a Network Interface 29 | resource "azurerm_network_interface" "tfexample" { 30 | name = "my-terraform-nic" 31 | location = azurerm_resource_group.tfexample.location 32 | resource_group_name = azurerm_resource_group.tfexample.name 33 | 34 | ip_configuration { 35 | name = "my-terraform-nic-ip-config" 36 | subnet_id = azurerm_subnet.tfexample.id 37 | private_ip_address_allocation = "Dynamic" 38 | } 39 | } 40 | 41 | # Create a Virtual Machine 42 | resource "azurerm_linux_virtual_machine" "tfexample" { 43 | name = "my-terraform-vm" 44 | location = azurerm_resource_group.tfexample.location 45 | resource_group_name = azurerm_resource_group.tfexample.name 46 | network_interface_ids = [azurerm_network_interface.tfexample.id] 47 | size = "Standard_DS1_v2" 48 | computer_name = "myvm" 49 | admin_username = "azureuser" 50 | admin_password = "Password1234!" 51 | disable_password_authentication = false 52 | 53 | source_image_reference { 54 | publisher = "Canonical" 55 | offer = "UbuntuServer" 56 | sku = "18.04-LTS" 57 | version = "latest" 58 | } 59 | 60 | os_disk { 61 | name = "my-terraform-os-disk" 62 | storage_account_type = "Standard_LRS" 63 | caching = "ReadWrite" 64 | } 65 | } -------------------------------------------------------------------------------- /code/02-one-server/README.md: -------------------------------------------------------------------------------- 1 | # Terraform One Server example 2 | 3 | This folder contains a one server example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a single server on Microsoft Azure by provisioning the necessary infrastructure, and using an Azure Virtual Machine. 6 | 7 | ## Requirements 8 | 9 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 10 | 11 | * You must have the following installed: 12 | * [Terraform](https://www.terraform.io/) CLI 13 | * Azure CLI tool 14 | 15 | * The code was written for: 16 | * Terraform 0.14 or later 17 | 18 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 19 | 20 | ## Using the code 21 | 22 | * Configure your access to Azure. 23 | 24 | * Authenticate using the Azure CLI. 25 | 26 | Terraform must authenticate to Azure to create infrastructure. 27 | 28 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 29 | 30 | ```bash 31 | az login 32 | ``` 33 | 34 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 35 | 36 | You have logged in. Now let us find all the subscriptions to which you have access... 37 | 38 | ```bash 39 | [ 40 | { 41 | "cloudName": "", 42 | "homeTenantId": "", 43 | "id": "", 44 | "isDefault": true, 45 | "managedByTenants": [], 46 | "name": "", 47 | "state": "Enabled", 48 | "tenantId": "", 49 | "user": { 50 | "name": "", 51 | "type": "user" 52 | } 53 | } 54 | ] 55 | ``` 56 | 57 | Find the `id` column for the subscription account you want to use. 58 | 59 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 60 | 61 | ```bash 62 | az account set --subscription "" 63 | ``` 64 | 65 | * Create a Service Principal. 66 | 67 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 68 | 69 | Create a Service Principal: 70 | 71 | ```bash 72 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 73 | 74 | Creating 'Contributor' role assignment under scope '/subscriptions/' 75 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 76 | { 77 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 78 | "displayName": "azure-cli-2022-xxxx", 79 | "password": "xxxxxx~xxxxxx~xxxxx", 80 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 81 | } 82 | ``` 83 | 84 | * Set your environment variables. 85 | 86 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 87 | 88 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 89 | 90 | * For MacOS/Linux: 91 | 92 | ```bash 93 | export ARM_CLIENT_ID="" 94 | export ARM_CLIENT_SECRET="" 95 | export ARM_SUBSCRIPTION_ID="" 96 | export ARM_TENANT_ID="" 97 | ``` 98 | 99 | * For Windows (PowerShell): 100 | 101 | ```bash 102 | $env:ARM_CLIENT_ID="" 103 | $env:ARM_CLIENT_SECRET="" 104 | $env:ARM_SUBSCRIPTION_ID="" 105 | $env:ARM_TENANT_ID="" 106 | ``` 107 | 108 | * Initialize Terraform configuration. 109 | 110 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 111 | 112 | 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. 113 | 114 | Run command: 115 | 116 | ```bash 117 | terraform init 118 | ``` 119 | 120 | * Validate the changes. 121 | 122 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 123 | 124 | Run command: 125 | 126 | ```bash 127 | terraform plan 128 | ``` 129 | 130 | * Apply the changes. 131 | 132 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 133 | 134 | Run command: 135 | 136 | ```bash 137 | terraform apply 138 | ``` 139 | 140 | * Test the changes. 141 | 142 | When the `terraform apply` command completes, use the Azure console, you should see the new Virtual Machine, and all the resources created with the `environment: TerraformExamples` tag. 143 | 144 | * Clean up the resources created. 145 | 146 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 147 | 148 | Run command: 149 | 150 | ```bash 151 | terraform destroy 152 | ``` 153 | -------------------------------------------------------------------------------- /code/02-one-server/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | 18 | # Create a Resource Group if it doesn’t exist 19 | resource "azurerm_resource_group" "tfexample" { 20 | name = "my-terraform-rg" 21 | location = "West Europe" 22 | } 23 | 24 | # Create a Virtual Network 25 | resource "azurerm_virtual_network" "tfexample" { 26 | name = "my-terraform-vnet" 27 | location = azurerm_resource_group.tfexample.location 28 | resource_group_name = azurerm_resource_group.tfexample.name 29 | address_space = ["10.0.0.0/16"] 30 | 31 | tags = { 32 | environment = "my-terraform-env" 33 | } 34 | } 35 | 36 | # Create a Subnet in the Virtual Network 37 | resource "azurerm_subnet" "tfexample" { 38 | name = "my-terraform-subnet" 39 | resource_group_name = azurerm_resource_group.tfexample.name 40 | virtual_network_name = azurerm_virtual_network.tfexample.name 41 | address_prefixes = ["10.0.2.0/24"] 42 | } 43 | 44 | # Create a Network Interface 45 | resource "azurerm_network_interface" "tfexample" { 46 | name = "my-terraform-nic" 47 | location = azurerm_resource_group.tfexample.location 48 | resource_group_name = azurerm_resource_group.tfexample.name 49 | 50 | ip_configuration { 51 | name = "my-terraform-nic-ip-config" 52 | subnet_id = azurerm_subnet.tfexample.id 53 | private_ip_address_allocation = "Dynamic" 54 | } 55 | 56 | tags = { 57 | environment = "my-terraform-env" 58 | } 59 | } 60 | 61 | # Create a Virtual Machine 62 | resource "azurerm_linux_virtual_machine" "tfexample" { 63 | name = "my-terraform-vm" 64 | location = azurerm_resource_group.tfexample.location 65 | resource_group_name = azurerm_resource_group.tfexample.name 66 | network_interface_ids = [azurerm_network_interface.tfexample.id] 67 | size = "Standard_DS1_v2" 68 | computer_name = "myvm" 69 | admin_username = "azureuser" 70 | admin_password = "Password1234!" 71 | disable_password_authentication = false 72 | 73 | source_image_reference { 74 | publisher = "Canonical" 75 | offer = "UbuntuServer" 76 | sku = "18.04-LTS" 77 | version = "latest" 78 | } 79 | 80 | os_disk { 81 | name = "my-terraform-os-disk" 82 | storage_account_type = "Standard_LRS" 83 | caching = "ReadWrite" 84 | } 85 | 86 | tags = { 87 | environment = "my-terraform-env" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /code/03-one-webserver/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Web Server example 2 | 3 | This folder contains a one server example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a single web server on Microsoft Azure by provisioning the necessary infrastructure, and using an Azure Virtual Machine. The web server returns "Hello, World" for the URL `/` listening on port 8080. 6 | 7 | ## Requirements 8 | 9 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 10 | 11 | * You must have the following installed: 12 | * [Terraform](https://www.terraform.io/) CLI 13 | * Azure CLI tool 14 | 15 | * The code was written for: 16 | * Terraform 0.14 or later 17 | 18 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 19 | 20 | ## Using the code 21 | 22 | * Configure your access to Azure. 23 | 24 | * Authenticate using the Azure CLI. 25 | 26 | Terraform must authenticate to Azure to create infrastructure. 27 | 28 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 29 | 30 | ```bash 31 | az login 32 | ``` 33 | 34 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 35 | 36 | You have logged in. Now let us find all the subscriptions to which you have access... 37 | 38 | ```bash 39 | [ 40 | { 41 | "cloudName": "", 42 | "homeTenantId": "", 43 | "id": "", 44 | "isDefault": true, 45 | "managedByTenants": [], 46 | "name": "", 47 | "state": "Enabled", 48 | "tenantId": "", 49 | "user": { 50 | "name": "", 51 | "type": "user" 52 | } 53 | } 54 | ] 55 | ``` 56 | 57 | Find the `id` column for the subscription account you want to use. 58 | 59 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 60 | 61 | ```bash 62 | az account set --subscription "" 63 | ``` 64 | 65 | * Create a Service Principal. 66 | 67 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 68 | 69 | Create a Service Principal: 70 | 71 | ```bash 72 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 73 | 74 | Creating 'Contributor' role assignment under scope '/subscriptions/' 75 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 76 | { 77 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 78 | "displayName": "azure-cli-2022-xxxx", 79 | "password": "xxxxxx~xxxxxx~xxxxx", 80 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 81 | } 82 | ``` 83 | 84 | * Set your environment variables. 85 | 86 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 87 | 88 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 89 | 90 | * For MacOS/Linux: 91 | 92 | ```bash 93 | export ARM_CLIENT_ID="" 94 | export ARM_CLIENT_SECRET="" 95 | export ARM_SUBSCRIPTION_ID="" 96 | export ARM_TENANT_ID="" 97 | ``` 98 | 99 | * For Windows (PowerShell): 100 | 101 | ```bash 102 | $env:ARM_CLIENT_ID="" 103 | $env:ARM_CLIENT_SECRET="" 104 | $env:ARM_SUBSCRIPTION_ID="" 105 | $env:ARM_TENANT_ID="" 106 | ``` 107 | 108 | * Initialize Terraform configuration. 109 | 110 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 111 | 112 | 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. 113 | 114 | Run command: 115 | 116 | ```bash 117 | terraform init 118 | ``` 119 | 120 | * Validate the changes. 121 | 122 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 123 | 124 | Run command: 125 | 126 | ```bash 127 | terraform plan 128 | ``` 129 | 130 | * Apply the changes. 131 | 132 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 133 | 134 | Run command: 135 | 136 | ```bash 137 | terraform apply 138 | ``` 139 | 140 | * Test the web server. 141 | 142 | When the `terraform apply` command completes, it will output the public IP address of the web server. 143 | 144 | You can test it in two ways, but be sure to replace the value of `` by the public IP address that you have got in the previous command: 145 | 146 | * Running this command: 147 | 148 | ```bash 149 | curl http://:8080/ 150 | ``` 151 | 152 | * Writing in your browser this URL: `http://:8080/` 153 | 154 | You should get a `Hello, World` response message. 155 | 156 | * Clean up the resources created. 157 | 158 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 159 | 160 | Run command: 161 | 162 | ```bash 163 | terraform destroy 164 | ``` 165 | -------------------------------------------------------------------------------- /code/03-one-webserver/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | 18 | # Create a Resource Group if it doesn’t exist 19 | resource "azurerm_resource_group" "tfexample" { 20 | name = "my-terraform-rg" 21 | location = "West Europe" 22 | } 23 | 24 | # Create a Virtual Network 25 | resource "azurerm_virtual_network" "tfexample" { 26 | name = "my-terraform-vnet" 27 | location = azurerm_resource_group.tfexample.location 28 | resource_group_name = azurerm_resource_group.tfexample.name 29 | address_space = ["10.0.0.0/16"] 30 | 31 | tags = { 32 | environment = "my-terraform-env" 33 | } 34 | } 35 | 36 | # Create a Subnet in the Virtual Network 37 | resource "azurerm_subnet" "tfexample" { 38 | name = "my-terraform-subnet" 39 | resource_group_name = azurerm_resource_group.tfexample.name 40 | virtual_network_name = azurerm_virtual_network.tfexample.name 41 | address_prefixes = ["10.0.2.0/24"] 42 | } 43 | 44 | # Create a Public IP 45 | resource "azurerm_public_ip" "tfexample" { 46 | name = "my-terraform-public-ip" 47 | location = azurerm_resource_group.tfexample.location 48 | resource_group_name = azurerm_resource_group.tfexample.name 49 | allocation_method = "Static" 50 | 51 | tags = { 52 | environment = "my-terraform-env" 53 | } 54 | } 55 | 56 | # Create a Network Security Group and rule 57 | resource "azurerm_network_security_group" "tfexample" { 58 | name = "my-terraform-nsg" 59 | location = azurerm_resource_group.tfexample.location 60 | resource_group_name = azurerm_resource_group.tfexample.name 61 | 62 | security_rule { 63 | name = "HTTP" 64 | priority = 1001 65 | direction = "Inbound" 66 | access = "Allow" 67 | protocol = "Tcp" 68 | source_port_range = "*" 69 | destination_port_range = "8080" 70 | source_address_prefix = "*" 71 | destination_address_prefix = "*" 72 | } 73 | 74 | tags = { 75 | environment = "my-terraform-env" 76 | } 77 | } 78 | 79 | # Create a Network Interface 80 | resource "azurerm_network_interface" "tfexample" { 81 | name = "my-terraform-nic" 82 | location = azurerm_resource_group.tfexample.location 83 | resource_group_name = azurerm_resource_group.tfexample.name 84 | 85 | ip_configuration { 86 | name = "my-terraform-nic-ip-config" 87 | subnet_id = azurerm_subnet.tfexample.id 88 | private_ip_address_allocation = "Dynamic" 89 | public_ip_address_id = azurerm_public_ip.tfexample.id 90 | } 91 | 92 | tags = { 93 | environment = "my-terraform-env" 94 | } 95 | } 96 | 97 | # Create a Network Interface Security Group association 98 | resource "azurerm_network_interface_security_group_association" "tfexample" { 99 | network_interface_id = azurerm_network_interface.tfexample.id 100 | network_security_group_id = azurerm_network_security_group.tfexample.id 101 | } 102 | 103 | # Create a Virtual Machine 104 | resource "azurerm_linux_virtual_machine" "tfexample" { 105 | name = "my-terraform-vm" 106 | location = azurerm_resource_group.tfexample.location 107 | resource_group_name = azurerm_resource_group.tfexample.name 108 | network_interface_ids = [azurerm_network_interface.tfexample.id] 109 | size = "Standard_DS1_v2" 110 | computer_name = "myvm" 111 | admin_username = "azureuser" 112 | admin_password = "Password1234!" 113 | disable_password_authentication = false 114 | 115 | source_image_reference { 116 | publisher = "Canonical" 117 | offer = "UbuntuServer" 118 | sku = "18.04-LTS" 119 | version = "latest" 120 | } 121 | 122 | os_disk { 123 | name = "my-terraform-os-disk" 124 | storage_account_type = "Standard_LRS" 125 | caching = "ReadWrite" 126 | } 127 | 128 | tags = { 129 | environment = "my-terraform-env" 130 | } 131 | } 132 | 133 | # Configurate to run automated tasks in the VM start-up 134 | resource "azurerm_virtual_machine_extension" "tfexample" { 135 | name = "hostname" 136 | virtual_machine_id = azurerm_linux_virtual_machine.tfexample.id 137 | publisher = "Microsoft.Azure.Extensions" 138 | type = "CustomScript" 139 | type_handler_version = "2.1" 140 | 141 | settings = < index.html ; nohup busybox httpd -f -p 8080 &" 144 | } 145 | SETTINGS 146 | 147 | tags = { 148 | environment = "my-terraform-env" 149 | } 150 | } 151 | 152 | # Data source to access the properties of an existing Azure Public IP Address 153 | data "azurerm_public_ip" "tfexample" { 154 | name = azurerm_public_ip.tfexample.name 155 | resource_group_name = azurerm_linux_virtual_machine.tfexample.resource_group_name 156 | } 157 | 158 | # Output variable: Public IP address 159 | output "public_ip" { 160 | value = data.azurerm_public_ip.tfexample.ip_address 161 | } 162 | -------------------------------------------------------------------------------- /code/04-one-webserver-with-vars/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Web Server with vars example 2 | 3 | This folder contains a one server example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a single web server on Microsoft Azure by provisioning the necessary infrastructure, and using an Azure Virtual Machine. The web server returns "Hello, World" for the URL `/` listening on port 8080, which is defined as a variable. 6 | 7 | ## Requirements 8 | 9 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 10 | 11 | * You must have the following installed: 12 | * [Terraform](https://www.terraform.io/) CLI 13 | * Azure CLI tool 14 | 15 | * The code was written for: 16 | * Terraform 0.14 or later 17 | 18 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 19 | 20 | ## Using the code 21 | 22 | * Configure your access to Azure. 23 | 24 | * Authenticate using the Azure CLI. 25 | 26 | Terraform must authenticate to Azure to create infrastructure. 27 | 28 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 29 | 30 | ```bash 31 | az login 32 | ``` 33 | 34 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 35 | 36 | You have logged in. Now let us find all the subscriptions to which you have access... 37 | 38 | ```bash 39 | [ 40 | { 41 | "cloudName": "", 42 | "homeTenantId": "", 43 | "id": "", 44 | "isDefault": true, 45 | "managedByTenants": [], 46 | "name": "", 47 | "state": "Enabled", 48 | "tenantId": "", 49 | "user": { 50 | "name": "", 51 | "type": "user" 52 | } 53 | } 54 | ] 55 | ``` 56 | 57 | Find the `id` column for the subscription account you want to use. 58 | 59 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 60 | 61 | ```bash 62 | az account set --subscription "" 63 | ``` 64 | 65 | * Create a Service Principal. 66 | 67 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 68 | 69 | Create a Service Principal: 70 | 71 | ```bash 72 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 73 | 74 | Creating 'Contributor' role assignment under scope '/subscriptions/' 75 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 76 | { 77 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 78 | "displayName": "azure-cli-2022-xxxx", 79 | "password": "xxxxxx~xxxxxx~xxxxx", 80 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 81 | } 82 | ``` 83 | 84 | * Set your environment variables. 85 | 86 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 87 | 88 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 89 | 90 | * For MacOS/Linux: 91 | 92 | ```bash 93 | export ARM_CLIENT_ID="" 94 | export ARM_CLIENT_SECRET="" 95 | export ARM_SUBSCRIPTION_ID="" 96 | export ARM_TENANT_ID="" 97 | ``` 98 | 99 | * For Windows (PowerShell): 100 | 101 | ```bash 102 | $env:ARM_CLIENT_ID="" 103 | $env:ARM_CLIENT_SECRET="" 104 | $env:ARM_SUBSCRIPTION_ID="" 105 | $env:ARM_TENANT_ID="" 106 | ``` 107 | 108 | * Initialize Terraform configuration. 109 | 110 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 111 | 112 | 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. 113 | 114 | Run command: 115 | 116 | ```bash 117 | terraform init 118 | ``` 119 | 120 | * Modify server port configuration. 121 | 122 | The web server is listening on port 8080, which is defined as an input variable `server_port` in `vars.tf` file. 123 | 124 | If you want to modify the server port you will be able to do it in several ways, but be sure to replace the value of `` by your server port: 125 | 126 | * Loading variables from command line option. 127 | 128 | Run Terraform commands in this way: 129 | 130 | ```bash 131 | terraform plan -var 'server_port=' 132 | ``` 133 | 134 | ```bash 135 | terraform apply -var 'server_port=' 136 | ``` 137 | 138 | * Loading variables from a file. 139 | 140 | When Terraform runs it will look for a file called `terraform.tfvars`. You can populate this file with variable values that will be loaded when Terraform runs. An example for the content of the `terraform.tfvars` file: 141 | 142 | ```bash 143 | server_port = "" 144 | ``` 145 | 146 | * Loading variables from environment variables. 147 | 148 | Terraform will also parse any environment variables that are prefixed with `TF_VAR`. You can create an environment variable `TF_VAR_server_port`: 149 | 150 | ```bash 151 | export TF_VAR_server_port= 152 | ``` 153 | 154 | * Variable defaults. 155 | 156 | Change the value of the `default` attribute of `server_port` input variable in `vars.tf` file. 157 | 158 | ```hcl 159 | variable "server_port" { 160 | description = "The port the server will use for HTTP requests" 161 | default = "" 162 | } 163 | ``` 164 | 165 | * Validate the changes. 166 | 167 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 168 | 169 | Run command: 170 | 171 | ```bash 172 | terraform plan 173 | ``` 174 | 175 | * Apply the changes. 176 | 177 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 178 | 179 | Run command: 180 | 181 | ```bash 182 | terraform apply 183 | ``` 184 | 185 | * Test the web server. 186 | 187 | When the `terraform apply` command completes, it will output the public IP address of the web server. 188 | 189 | You can test it in two ways, but be sure to replace the value of `` by the public IP address that you have got in the previous command: 190 | 191 | * Running this command: 192 | 193 | ```bash 194 | curl http://:8080/ 195 | ``` 196 | 197 | * Writing in your browser this URL: `http://:8080/` 198 | 199 | You should get a `Hello, World` response message. 200 | 201 | * Clean up the resources created. 202 | 203 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 204 | 205 | Run command: 206 | 207 | ```bash 208 | terraform destroy 209 | ``` 210 | -------------------------------------------------------------------------------- /code/04-one-webserver-with-vars/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | 18 | # Create a Resource Group if it doesn’t exist 19 | resource "azurerm_resource_group" "tfexample" { 20 | name = "my-terraform-rg" 21 | location = "West Europe" 22 | } 23 | 24 | # Create a Virtual Network 25 | resource "azurerm_virtual_network" "tfexample" { 26 | name = "my-terraform-vnet" 27 | location = azurerm_resource_group.tfexample.location 28 | resource_group_name = azurerm_resource_group.tfexample.name 29 | address_space = ["10.0.0.0/16"] 30 | 31 | tags = { 32 | environment = "my-terraform-env" 33 | } 34 | } 35 | 36 | # Create a Subnet in the Virtual Network 37 | resource "azurerm_subnet" "tfexample" { 38 | name = "my-terraform-subnet" 39 | resource_group_name = azurerm_resource_group.tfexample.name 40 | virtual_network_name = azurerm_virtual_network.tfexample.name 41 | address_prefixes = ["10.0.2.0/24"] 42 | } 43 | 44 | # Create a Public IP 45 | resource "azurerm_public_ip" "tfexample" { 46 | name = "my-terraform-public-ip" 47 | location = azurerm_resource_group.tfexample.location 48 | resource_group_name = azurerm_resource_group.tfexample.name 49 | allocation_method = "Static" 50 | 51 | tags = { 52 | environment = "my-terraform-env" 53 | } 54 | } 55 | 56 | # Create a Network Security Group and rule 57 | resource "azurerm_network_security_group" "tfexample" { 58 | name = "my-terraform-nsg" 59 | location = azurerm_resource_group.tfexample.location 60 | resource_group_name = azurerm_resource_group.tfexample.name 61 | 62 | security_rule { 63 | name = "HTTP" 64 | priority = 1001 65 | direction = "Inbound" 66 | access = "Allow" 67 | protocol = "Tcp" 68 | source_port_range = "*" 69 | destination_port_range = var.server_port 70 | source_address_prefix = "*" 71 | destination_address_prefix = "*" 72 | } 73 | 74 | tags = { 75 | environment = "my-terraform-env" 76 | } 77 | } 78 | 79 | # Create a Network Interface 80 | resource "azurerm_network_interface" "tfexample" { 81 | name = "my-terraform-nic" 82 | location = azurerm_resource_group.tfexample.location 83 | resource_group_name = azurerm_resource_group.tfexample.name 84 | 85 | ip_configuration { 86 | name = "my-terraform-nic-ip" 87 | subnet_id = azurerm_subnet.tfexample.id 88 | private_ip_address_allocation = "Dynamic" 89 | public_ip_address_id = azurerm_public_ip.tfexample.id 90 | } 91 | 92 | tags = { 93 | environment = "my-terraform-env" 94 | } 95 | } 96 | 97 | # Create a Network Interface Security Group association 98 | resource "azurerm_network_interface_security_group_association" "tfexample" { 99 | network_interface_id = azurerm_network_interface.tfexample.id 100 | network_security_group_id = azurerm_network_security_group.tfexample.id 101 | } 102 | 103 | # Create a Virtual Machine 104 | resource "azurerm_linux_virtual_machine" "tfexample" { 105 | name = "my-terraform-vm" 106 | location = azurerm_resource_group.tfexample.location 107 | resource_group_name = azurerm_resource_group.tfexample.name 108 | network_interface_ids = [azurerm_network_interface.tfexample.id] 109 | size = "Standard_DS1_v2" 110 | computer_name = "myvm" 111 | admin_username = "azureuser" 112 | admin_password = "Password1234!" 113 | disable_password_authentication = false 114 | 115 | source_image_reference { 116 | publisher = "Canonical" 117 | offer = "UbuntuServer" 118 | sku = "18.04-LTS" 119 | version = "latest" 120 | } 121 | 122 | os_disk { 123 | name = "my-terraform-os-disk" 124 | storage_account_type = "Standard_LRS" 125 | caching = "ReadWrite" 126 | } 127 | 128 | tags = { 129 | environment = "my-terraform-env" 130 | } 131 | } 132 | 133 | # Configurate to run automated tasks in the VM start-up 134 | resource "azurerm_virtual_machine_extension" "tfexample" { 135 | name = "hostname" 136 | virtual_machine_id = azurerm_linux_virtual_machine.tfexample.id 137 | publisher = "Microsoft.Azure.Extensions" 138 | type = "CustomScript" 139 | type_handler_version = "2.1" 140 | 141 | settings = < index.html ; nohup busybox httpd -f -p ${var.server_port} &" 144 | } 145 | SETTINGS 146 | 147 | tags = { 148 | environment = "my-terraform-env" 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /code/04-one-webserver-with-vars/outputs.tf: -------------------------------------------------------------------------------- 1 | # Data source to access the properties of an existing Azure Public IP Address 2 | data "azurerm_public_ip" "tfexample" { 3 | name = azurerm_public_ip.tfexample.name 4 | resource_group_name = azurerm_linux_virtual_machine.tfexample.resource_group_name 5 | } 6 | 7 | # Output variable: Public IP address 8 | output "public_ip" { 9 | value = data.azurerm_public_ip.tfexample.ip_address 10 | } 11 | -------------------------------------------------------------------------------- /code/04-one-webserver-with-vars/vars.tf: -------------------------------------------------------------------------------- 1 | # Input variable: server port 2 | variable "server_port" { 3 | description = "The port the server will use for HTTP requests" 4 | default = "8080" 5 | } 6 | -------------------------------------------------------------------------------- /code/05-cluster-webserver/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Cluster Web Server example 2 | 3 | This folder contains a one server example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a cluster of web servers on Microsoft Azure by provisioning the necessary infrastructure, and using an Azure Virtual Machine Scale Set, as well as a load balancer using Azure Load Balancer. 6 | 7 | The cluster of web servers returns "Hello, World" for the URL `/`. The load balancer listens on port 80. 8 | 9 | ## Requirements 10 | 11 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 12 | 13 | * You must have the following installed: 14 | * [Terraform](https://www.terraform.io/) CLI 15 | * Azure CLI tool 16 | 17 | * The code was written for: 18 | * Terraform 0.14 or later 19 | 20 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 21 | 22 | ## Using the code 23 | 24 | * Configure your access to Azure. 25 | 26 | * Authenticate using the Azure CLI. 27 | 28 | Terraform must authenticate to Azure to create infrastructure. 29 | 30 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 31 | 32 | ```bash 33 | az login 34 | ``` 35 | 36 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 37 | 38 | You have logged in. Now let us find all the subscriptions to which you have access... 39 | 40 | ```bash 41 | [ 42 | { 43 | "cloudName": "", 44 | "homeTenantId": "", 45 | "id": "", 46 | "isDefault": true, 47 | "managedByTenants": [], 48 | "name": "", 49 | "state": "Enabled", 50 | "tenantId": "", 51 | "user": { 52 | "name": "", 53 | "type": "user" 54 | } 55 | } 56 | ] 57 | ``` 58 | 59 | Find the `id` column for the subscription account you want to use. 60 | 61 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 62 | 63 | ```bash 64 | az account set --subscription "" 65 | ``` 66 | 67 | * Create a Service Principal. 68 | 69 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 70 | 71 | Create a Service Principal: 72 | 73 | ```bash 74 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 75 | 76 | Creating 'Contributor' role assignment under scope '/subscriptions/' 77 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 78 | { 79 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 80 | "displayName": "azure-cli-2022-xxxx", 81 | "password": "xxxxxx~xxxxxx~xxxxx", 82 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 83 | } 84 | ``` 85 | 86 | * Set your environment variables. 87 | 88 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 89 | 90 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 91 | 92 | * For MacOS/Linux: 93 | 94 | ```bash 95 | export ARM_CLIENT_ID="" 96 | export ARM_CLIENT_SECRET="" 97 | export ARM_SUBSCRIPTION_ID="" 98 | export ARM_TENANT_ID="" 99 | ``` 100 | 101 | * For Windows (PowerShell): 102 | 103 | ```bash 104 | $env:ARM_CLIENT_ID="" 105 | $env:ARM_CLIENT_SECRET="" 106 | $env:ARM_SUBSCRIPTION_ID="" 107 | $env:ARM_TENANT_ID="" 108 | ``` 109 | 110 | * Initialize working directory. 111 | 112 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 113 | 114 | ```bash 115 | terraform init 116 | ``` 117 | 118 | * Modify server port configuration. 119 | 120 | The web server is listening on port 8080, which is defined as an input variable `server_port` in `vars.tf` file. 121 | 122 | If you want to modify the server port you will be able to do it in several ways, but be sure to replace the value of `` by your server port: 123 | 124 | * Loading variables from command line option. 125 | 126 | Run Terraform commands in this way: 127 | 128 | ```bash 129 | terraform plan -var 'server_port=' 130 | ``` 131 | 132 | ```bash 133 | terraform apply -var 'server_port=' 134 | ``` 135 | 136 | * Loading variables from a file. 137 | 138 | When Terraform runs it will look for a file called `terraform.tfvars`. You can populate this file with variable values that will be loaded when Terraform runs. An example for the content of the `terraform.tfvars` file: 139 | 140 | ```bash 141 | server_port = "" 142 | ``` 143 | 144 | * Loading variables from environment variables. 145 | 146 | Terraform will also parse any environment variables that are prefixed with `TF_VAR`. You can create an environment variable `TF_VAR_server_port`: 147 | 148 | ```bash 149 | export TF_VAR_server_port= 150 | ``` 151 | 152 | * Variable defaults. 153 | 154 | Change the value of the `default` attribute of `server_port` input variable in `vars.tf` file. 155 | 156 | ```hcl 157 | variable "server_port" { 158 | description = "The port the server will use for HTTP requests" 159 | default = "" 160 | } 161 | ``` 162 | 163 | * Validate the changes. 164 | 165 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 166 | 167 | Run command: 168 | 169 | ```bash 170 | terraform plan 171 | ``` 172 | 173 | * Apply the changes. 174 | 175 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 176 | 177 | Run command: 178 | 179 | ```bash 180 | terraform apply 181 | ``` 182 | 183 | * Test the cluster of web servers. 184 | 185 | When the `terraform apply` command completes, it will output the public IP address of the load balancer. 186 | 187 | You can test it in two ways, but be sure to replace the value of `` by the public IP address that you have got in the previous command: 188 | 189 | * Running this command: 190 | 191 | ```bash 192 | curl http://LOAD_BALANCER_PUBLIC_IP/ 193 | ``` 194 | 195 | * Writing in your browser this URL: `http://LOAD_BALANCER_PUBLIC_IP/` 196 | 197 | You should get a `Hello, World` response message. 198 | 199 | * Clean up the resources created. 200 | 201 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 202 | 203 | Run command: 204 | 205 | ```bash 206 | terraform destroy 207 | ``` 208 | -------------------------------------------------------------------------------- /code/05-cluster-webserver/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | 18 | # Create a Resource Group if it doesn’t exist 19 | resource "azurerm_resource_group" "tfexample" { 20 | name = "my-terraform-rg" 21 | location = "West Europe" 22 | } 23 | 24 | # Create a Virtual Network 25 | resource "azurerm_virtual_network" "tfexample" { 26 | name = "my-terraform-vnet" 27 | location = azurerm_resource_group.tfexample.location 28 | resource_group_name = azurerm_resource_group.tfexample.name 29 | address_space = ["10.0.0.0/16"] 30 | 31 | tags = { 32 | environment = "my-terraform-env" 33 | } 34 | } 35 | 36 | # Create a Subnet in the Virtual Network 37 | resource "azurerm_subnet" "tfexample" { 38 | name = "my-terraform-subnet" 39 | resource_group_name = azurerm_resource_group.tfexample.name 40 | virtual_network_name = azurerm_virtual_network.tfexample.name 41 | address_prefixes = ["10.0.2.0/24"] 42 | } 43 | 44 | # Create a Public IP 45 | resource "azurerm_public_ip" "tfexample" { 46 | name = "my-terraform-public-ip" 47 | location = azurerm_resource_group.tfexample.location 48 | resource_group_name = azurerm_resource_group.tfexample.name 49 | allocation_method = "Static" 50 | 51 | tags = { 52 | environment = "my-terraform-env" 53 | } 54 | } 55 | 56 | # Create a Load Balancer 57 | resource "azurerm_lb" "tfexample" { 58 | name = "my-terraform-lb" 59 | location = azurerm_resource_group.tfexample.location 60 | resource_group_name = azurerm_resource_group.tfexample.name 61 | 62 | frontend_ip_configuration { 63 | name = "my-terraform-lb-frontend-ip" 64 | public_ip_address_id = azurerm_public_ip.tfexample.id 65 | } 66 | 67 | tags = { 68 | environment = "my-terraform-env" 69 | } 70 | } 71 | 72 | # Create a Load Balancer Backend Address Pool 73 | resource "azurerm_lb_backend_address_pool" "tfexample" { 74 | name = "my-terraform-lb-backend-pool" 75 | loadbalancer_id = azurerm_lb.tfexample.id 76 | } 77 | 78 | # Creste a Load Balancer health probes 79 | resource "azurerm_lb_probe" "tfexample" { 80 | name = "my-terraform-lb-probe" 81 | loadbalancer_id = azurerm_lb.tfexample.id 82 | port = var.server_port 83 | } 84 | 85 | # Create a Load Balancer Rule 86 | resource "azurerm_lb_rule" "tfexample" { 87 | name = "my-terraform-lb-rule" 88 | loadbalancer_id = azurerm_lb.tfexample.id 89 | protocol = "Tcp" 90 | frontend_port = 80 91 | backend_port = var.server_port 92 | frontend_ip_configuration_name = "my-terraform-lb-frontend-ip" 93 | backend_address_pool_ids = [azurerm_lb_backend_address_pool.tfexample.id] 94 | probe_id = azurerm_lb_probe.tfexample.id 95 | } 96 | 97 | # Create a Virtual Machine Scale Set 98 | resource "azurerm_linux_virtual_machine_scale_set" "tfexample" { 99 | name = "my-terraform-vm-scale-set" 100 | location = azurerm_resource_group.tfexample.location 101 | resource_group_name = azurerm_resource_group.tfexample.name 102 | sku = "Standard_DS1_v2" 103 | instances = 2 104 | admin_username = "azureuser" 105 | admin_password = "Password1234!" 106 | disable_password_authentication = false 107 | 108 | source_image_reference { 109 | publisher = "Canonical" 110 | offer = "UbuntuServer" 111 | sku = "18.04-LTS" 112 | version = "latest" 113 | } 114 | 115 | os_disk { 116 | storage_account_type = "Standard_LRS" 117 | caching = "ReadWrite" 118 | } 119 | 120 | network_interface { 121 | name = "my-terraform-vm-ss-nic" 122 | primary = true 123 | 124 | ip_configuration { 125 | name = "my-terraform-vm-ss-nic-ip" 126 | primary = true 127 | subnet_id = azurerm_subnet.tfexample.id 128 | load_balancer_backend_address_pool_ids = [azurerm_lb_backend_address_pool.tfexample.id] 129 | } 130 | } 131 | 132 | extension { 133 | name = "hostname" 134 | publisher = "Microsoft.Azure.Extensions" 135 | type = "CustomScript" 136 | type_handler_version = "2.1" 137 | 138 | settings = < index.html ; nohup busybox httpd -f -p ${var.server_port} &" 141 | } 142 | SETTINGS 143 | } 144 | 145 | tags = { 146 | environment = "my-terraform-env" 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /code/05-cluster-webserver/outputs.tf: -------------------------------------------------------------------------------- 1 | # Data source to access the properties of an existing Azure Public IP Address 2 | data "azurerm_public_ip" "tfexample" { 3 | name = azurerm_public_ip.tfexample.name 4 | resource_group_name = azurerm_linux_virtual_machine_scale_set.tfexample.resource_group_name 5 | } 6 | 7 | # # Output variable: Public IP address 8 | output "public_ip" { 9 | value = data.azurerm_public_ip.tfexample.ip_address 10 | } 11 | -------------------------------------------------------------------------------- /code/05-cluster-webserver/vars.tf: -------------------------------------------------------------------------------- 1 | # Input variable: server port 2 | variable "server_port" { 3 | description = "The port the server will use for HTTP requests" 4 | default = "8080" 5 | } 6 | -------------------------------------------------------------------------------- /code/06-create-blob-storage/README.md: -------------------------------------------------------------------------------- 1 | # Terraform Create Blob Storage example 2 | 3 | This folder contains the create Blob Storage example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file create a Blob Storage container on Microsoft Azure by provisioning the necessary infrastructure. 6 | 7 | ## Requirements 8 | 9 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 10 | 11 | * You must have the following installed: 12 | * [Terraform](https://www.terraform.io/) CLI 13 | * Azure CLI tool 14 | 15 | * The code was written for: 16 | * Terraform 0.14 or later 17 | 18 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 19 | 20 | ## Using the code 21 | 22 | * Configure your access to Azure. 23 | 24 | * Authenticate using the Azure CLI. 25 | 26 | Terraform must authenticate to Azure to create infrastructure. 27 | 28 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 29 | 30 | ```bash 31 | az login 32 | ``` 33 | 34 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 35 | 36 | You have logged in. Now let us find all the subscriptions to which you have access... 37 | 38 | ```bash 39 | [ 40 | { 41 | "cloudName": "", 42 | "homeTenantId": "", 43 | "id": "", 44 | "isDefault": true, 45 | "managedByTenants": [], 46 | "name": "", 47 | "state": "Enabled", 48 | "tenantId": "", 49 | "user": { 50 | "name": "", 51 | "type": "user" 52 | } 53 | } 54 | ] 55 | ``` 56 | 57 | Find the `id` column for the subscription account you want to use. 58 | 59 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 60 | 61 | ```bash 62 | az account set --subscription "" 63 | ``` 64 | 65 | * Create a Service Principal. 66 | 67 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 68 | 69 | Create a Service Principal: 70 | 71 | ```bash 72 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 73 | 74 | Creating 'Contributor' role assignment under scope '/subscriptions/' 75 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 76 | { 77 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 78 | "displayName": "azure-cli-2022-xxxx", 79 | "password": "xxxxxx~xxxxxx~xxxxx", 80 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 81 | } 82 | ``` 83 | 84 | * Set your environment variables. 85 | 86 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 87 | 88 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 89 | 90 | * For MacOS/Linux: 91 | 92 | ```bash 93 | export ARM_CLIENT_ID="" 94 | export ARM_CLIENT_SECRET="" 95 | export ARM_SUBSCRIPTION_ID="" 96 | export ARM_TENANT_ID="" 97 | ``` 98 | 99 | * For Windows (PowerShell): 100 | 101 | ```bash 102 | $env:ARM_CLIENT_ID="" 103 | $env:ARM_CLIENT_SECRET="" 104 | $env:ARM_SUBSCRIPTION_ID="" 105 | $env:ARM_TENANT_ID="" 106 | ``` 107 | 108 | * Configure your storage account. 109 | 110 | An Azure storage account provides a unique namespace to store and access your Azure Storage data objects. 111 | 112 | An storage account can content containers and every container can content blobs. 113 | 114 | ```bash 115 | Storage Account 116 | ├── Container_1/ 117 | │ ├── Blob_1_1/ 118 | │ └── Blob_1_2/ 119 | │ 120 | └── Container_2/ 121 | ├── Blob_2_1/ 122 | ├── Blob_2_2/ 123 | └── Blob_2_3/ 124 | ``` 125 | 126 | The terraform file creates your storage account. 127 | 128 | * Initialize working directory. 129 | 130 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 131 | 132 | ```bash 133 | terraform init 134 | ``` 135 | 136 | * Configure Storage Account and container names. 137 | 138 | The default names of storage account and container are defined as two input variables in `vars.tf` file: 139 | 140 | * `storage_account_name` 141 | * `container_name` 142 | 143 | If you want to modify both you will be able to do it in several ways, but be sure to replace the value of `` by your storage account name, and the value of `` by your container name: 144 | 145 | * Loading variables from command line option. 146 | 147 | Run Terraform commands in this way: 148 | 149 | ```bash 150 | terraform plan -var 'storage_account_name=' -var 'container_name=' 151 | ``` 152 | 153 | ```bash 154 | terraform apply -var 'storage_account_name=' -var 'container_name=' 155 | ``` 156 | 157 | * Loading variables from a file. 158 | 159 | When Terraform runs it will look for a file called `terraform.tfvars`. You can populate this file with variable values that will be loaded when Terraform runs. An example for the content of the `terraform.tfvars` file: 160 | 161 | ```bash 162 | storage_account_name="" 163 | container_name="" 164 | ``` 165 | 166 | * Loading variables from environment variables. 167 | 168 | Terraform will also parse any environment variables that are prefixed with `TF_VAR`. You can create environment variables `TF_VAR_storage_account_name` and `TF_VAR_container_name`: 169 | 170 | ```bash 171 | export TF_VAR_storage_account_name= 172 | export TF_VAR_container_name= 173 | ``` 174 | 175 | * Variable defaults. 176 | 177 | Change the value of the `default` attribute of `storage_account_name` and `container_name` input variables in `vars.tf` file. 178 | 179 | ```hcl 180 | variable "storage_account_name" { 181 | description = "The name of the storage account. Must be globally unique, length between 3 and 24 characters and contain numbers and lowercase letters only." 182 | default = "" 183 | } 184 | 185 | variable "container_name" { 186 | description = "The name of the Blob Storage container." 187 | default = "" 188 | } 189 | ``` 190 | 191 | * Validate the changes. 192 | 193 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 194 | 195 | Run command: 196 | 197 | ```bash 198 | terraform plan 199 | ``` 200 | 201 | * Apply the changes. 202 | 203 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 204 | 205 | Run command: 206 | 207 | ```bash 208 | terraform apply 209 | ``` 210 | 211 | * Test the changes. 212 | 213 | When the `terraform apply` command completes, use the Azure console, you should see: 214 | 215 | * The new Azure storage account. 216 | 217 | * The new Blob Storage container created in the Azure storage account. 218 | 219 | * Clean up the resources created. 220 | 221 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 222 | 223 | Run command: 224 | 225 | ```bash 226 | terraform destroy 227 | ``` 228 | -------------------------------------------------------------------------------- /code/06-create-blob-storage/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | 18 | # Create a Resource Group if it doesn’t exist 19 | resource "azurerm_resource_group" "tfexample" { 20 | name = "my-terraform-rg" 21 | location = "West Europe" 22 | } 23 | 24 | # Create a Storage account 25 | resource "azurerm_storage_account" "terraform_state" { 26 | name = var.storage_account_name 27 | resource_group_name = azurerm_resource_group.tfexample.name 28 | location = azurerm_resource_group.tfexample.location 29 | account_tier = "Standard" 30 | account_replication_type = "LRS" 31 | 32 | tags = { 33 | environment = "my-terraform-env" 34 | } 35 | } 36 | 37 | # Create a Storage container 38 | resource "azurerm_storage_container" "terraform_state" { 39 | name = var.container_name 40 | storage_account_name = azurerm_storage_account.terraform_state.name 41 | container_access_type = "private" 42 | } 43 | -------------------------------------------------------------------------------- /code/06-create-blob-storage/outputs.tf: -------------------------------------------------------------------------------- 1 | # Output variable: Blob Storage container name 2 | output "blob_storage_container" { 3 | value = "https://${azurerm_storage_account.terraform_state.name}.blob.core.windows.net/${azurerm_storage_container.terraform_state.name}/" 4 | } 5 | -------------------------------------------------------------------------------- /code/06-create-blob-storage/vars.tf: -------------------------------------------------------------------------------- 1 | # Input variable: Name of Storage Account 2 | variable "storage_account_name" { 3 | description = "The name of the storage account. Must be globally unique, length between 3 and 24 characters and contain numbers and lowercase letters only." 4 | default = "mytfstorageaccount" 5 | } 6 | 7 | # Input variable: Name of Storage container 8 | variable "container_name" { 9 | description = "The name of the Blob Storage container." 10 | default = "my-terraform-state-container" 11 | } 12 | -------------------------------------------------------------------------------- /code/07-terraform-state/README.md: -------------------------------------------------------------------------------- 1 | # Terraform State example 2 | 3 | This folder contains a state example of a [Terraform](https://www.terraform.io/) file on Microsoft Azure. 4 | 5 | This Terraform file use the Azure Blob Storage container created in the previous example [06-create-blob-storage](../06-create-blob-storage/) to store the information about what infrastructure has been created. 6 | 7 | This information is stored in the Terraform state file `terraform.tfstate`. This file contains a JSON format that records a mapping from the representation of the resources on Microsoft Azure to Terrafom resources in the configuration files. 8 | 9 | Backends are responsible for storing state and providing an API for state locking. State locking is optional. 10 | 11 | Backends determine where state is stored. For example, the local (default) backend stores state in a local JSON file on disk. The Azurerm backend stores the state within a blob storage account. 12 | 13 | ## Requirements 14 | 15 | * You must have a [Microsoft Azure](https://azure.microsoft.com/) subscription. 16 | 17 | * You must have the following installed: 18 | * [Terraform](https://www.terraform.io/) CLI 19 | * Azure CLI tool 20 | 21 | * The code was written for: 22 | * Terraform 0.14 or later 23 | 24 | * It uses the Terraform AzureRM Provider v 3.1 that interacts with the many resources supported by Azure Resource Manager (AzureRM) through its APIs. 25 | 26 | ## Using the code 27 | 28 | * Configure your access to Azure. 29 | 30 | * Authenticate using the Azure CLI. 31 | 32 | Terraform must authenticate to Azure to create infrastructure. 33 | 34 | In your terminal, use the Azure CLI tool to setup your account permissions locally. 35 | 36 | ```bash 37 | az login 38 | ``` 39 | 40 | Your browser will open and prompt you to enter your Azure login credentials. After successful authentication, your terminal will display your subscription information. 41 | 42 | You have logged in. Now let us find all the subscriptions to which you have access... 43 | 44 | ```bash 45 | [ 46 | { 47 | "cloudName": "", 48 | "homeTenantId": "", 49 | "id": "", 50 | "isDefault": true, 51 | "managedByTenants": [], 52 | "name": "", 53 | "state": "Enabled", 54 | "tenantId": "", 55 | "user": { 56 | "name": "", 57 | "type": "user" 58 | } 59 | } 60 | ] 61 | ``` 62 | 63 | Find the `id` column for the subscription account you want to use. 64 | 65 | Once you have chosen the account subscription ID, set the account with the Azure CLI. 66 | 67 | ```bash 68 | az account set --subscription "" 69 | ``` 70 | 71 | * Create a Service Principal. 72 | 73 | A Service Principal is an application within Azure Active Directory with the authentication tokens Terraform needs to perform actions on your behalf. Update the `` with the subscription ID you specified in the previous step. 74 | 75 | Create a Service Principal: 76 | 77 | ```bash 78 | az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/" 79 | 80 | Creating 'Contributor' role assignment under scope '/subscriptions/' 81 | The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli 82 | { 83 | "appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx", 84 | "displayName": "azure-cli-2022-xxxx", 85 | "password": "xxxxxx~xxxxxx~xxxxx", 86 | "tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx" 87 | } 88 | ``` 89 | 90 | * Set your environment variables. 91 | 92 | HashiCorp recommends setting these values as environment variables rather than saving them in your Terraform configuration. 93 | 94 | In your terminal, set the following environment variables. Be sure to update the variable values with the values Azure returned in the previous command. 95 | 96 | * For MacOS/Linux: 97 | 98 | ```bash 99 | export ARM_CLIENT_ID="" 100 | export ARM_CLIENT_SECRET="" 101 | export ARM_SUBSCRIPTION_ID="" 102 | export ARM_TENANT_ID="" 103 | ``` 104 | 105 | * For Windows (PowerShell): 106 | 107 | ```bash 108 | $env:ARM_CLIENT_ID="" 109 | $env:ARM_CLIENT_SECRET="" 110 | $env:ARM_SUBSCRIPTION_ID="" 111 | $env:ARM_TENANT_ID="" 112 | ``` 113 | 114 | * Initialize working directory. 115 | 116 | The first command that should be run after writing a new Terraform configuration is the `terraform init` command in order to initialize a working directory containing Terraform configuration files. It is safe to run this command multiple times. 117 | 118 | ```bash 119 | terraform init 120 | ``` 121 | 122 | * Configure Terraform backend. 123 | 124 | You must modify two attributes in `backend.tf` file: 125 | 126 | * Storage Account name, which is defined in the `storage_account_name` attribute. 127 | * Container Name, which is defined in the `container_name` attribute. 128 | 129 | ```bash 130 | storage_account_name = "" 131 | container_name = "" 132 | ``` 133 | 134 | Be sure to replace the value of `` by your storage account name, and the value of `` by your container name. 135 | 136 | * Validate the changes. 137 | 138 | The `terraform plan` command lets you see what Terraform will do before actually making any changes. 139 | 140 | Run command: 141 | 142 | ```bash 143 | terraform plan 144 | ``` 145 | 146 | * Apply the changes. 147 | 148 | The `terraform apply` command lets you apply your configuration and it creates the infrastructure. 149 | 150 | Run command: 151 | 152 | ```bash 153 | terraform apply 154 | ``` 155 | 156 | * Test the changes. 157 | 158 | When the `terraform apply` command completes, use the Azure console, you should see the `terraform.tfstate` file created in the Blob Storage container in the storage account. 159 | 160 | The `terraform.tfstate` file is where is stored the terraform state. 161 | 162 | * Clean up the resources created. 163 | 164 | When you have finished, the `terraform destroy` command destroys the infrastructure you created. 165 | 166 | Run command: 167 | 168 | ```bash 169 | terraform destroy 170 | ``` 171 | -------------------------------------------------------------------------------- /code/07-terraform-state/backend.tf: -------------------------------------------------------------------------------- 1 | # Define Terraform backend using a blob storage container on Microsoft Azure for storing the Terraform state 2 | terraform { 3 | backend "azurerm" { 4 | resource_group_name = "my-terraform-rg" 5 | storage_account_name = "mytfstorageaccount" 6 | container_name = "my-terraform-state-container" 7 | key = "terraform.tfstate" 8 | } 9 | } -------------------------------------------------------------------------------- /code/07-terraform-state/main.tf: -------------------------------------------------------------------------------- 1 | # Set the Azure Provider source and version being used 2 | terraform { 3 | required_version = ">= 0.14" 4 | 5 | required_providers { 6 | azurerm = { 7 | source = "hashicorp/azurerm" 8 | version = "~> 3.1.0" 9 | } 10 | } 11 | } 12 | 13 | # Configure the Microsoft Azure provider 14 | provider "azurerm" { 15 | features {} 16 | } 17 | --------------------------------------------------------------------------------