Creating the infrastructure for a secure 3-tier application on Azure

main.tf file :

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "appservice-rg"
  location = "francecentral"
}

resource "azurerm_virtual_network" "vnet" {
  name                = "vnet"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  address_space       = ["10.0.0.0/16"]
}

resource "azurerm_subnet" "integrationsubnet" {
  name                 = "integrationsubnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
  delegation {
    name = "delegation"
    service_delegation {
      name = "Microsoft.Web/serverFarms"
    }
  }
}

resource "azurerm_subnet" "endpointsubnet" {
  name                 = "endpointsubnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.2.0/24"]
  private_endpoint_network_policies_enabled = true
}

resource "azurerm_service_plan" "appserviceplan" {
  name                = "appserviceplan"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  os_type             = "Windows"
  sku_name            = "S1"
}

resource "azurerm_windows_web_app" "frontwebapp" {
  name                = "frontend-kk"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  service_plan_id     = azurerm_service_plan.appserviceplan.id

  site_config {}
  app_settings = {
    "WEBSITE_DNS_SERVER" = "168.63.129.16",
    "BACKEND_URL"        = "http://${azurerm_private_dns_zone_virtual_network_link.dnszonelink.private_dns_zone_name}/api/message"
  }
}

resource "azurerm_app_service_virtual_network_swift_connection" "vnetintegrationconnection" {
  app_service_id = azurerm_windows_web_app.frontwebapp.id
  subnet_id      = azurerm_subnet.integrationsubnet.id
}

resource "azurerm_windows_web_app" "backwebapp" {
  name                = "backend-kk"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  service_plan_id     = azurerm_service_plan.appserviceplan.id

  site_config {}
}

resource "azurerm_private_dns_zone" "dnsprivatezone" {
  name                = "privatelink.azurewebsites.net"
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "dnszonelink" {
  name                  = "dnszonelink"
  resource_group_name   = azurerm_resource_group.rg.name
  private_dns_zone_name = azurerm_private_dns_zone.dnsprivatezone.name
  virtual_network_id    = azurerm_virtual_network.vnet.id
}

resource "azurerm_private_endpoint" "privateendpoint" {
  name                = "backwebappprivateendpoint"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  subnet_id           = azurerm_subnet.endpointsubnet.id

  private_dns_zone_group {
    name = "privatednszonegroup"
    private_dns_zone_ids = [azurerm_private_dns_zone.dnsprivatezone.id]
  }

  private_service_connection {
    name                           = "privateendpointconnection"
    private_connection_resource_id = azurerm_windows_web_app.backwebapp.id
    subresource_names              = ["sites"]
    is_manual_connection           = false
  }
}

resource "random_pet" "azurerm_mssql_server_name" {
  prefix = "sql"
}

resource "azurerm_mssql_server" "server" {
   name                         = random_pet.azurerm_mssql_server_name.id
   resource_group_name          = azurerm_resource_group.rg.name
   location                     = azurerm_resource_group.rg.location  
   version                      = "12.0"
   administrator_login          = "sqladmin"
   administrator_login_password = "ENTER THE PASSWORD"
 }

# MSSQL Database
resource "azurerm_mssql_database" "sqldatabase" {
  name           = "appdatabase"
  server_id      = azurerm_mssql_server.server.id
  collation      = "SQL_Latin1_General_CP1_CI_AS"
  license_type   = "LicenseIncluded"
  max_size_gb    = 10
  sku_name       = "S0"
  zone_redundant = false
}

# Network Security Group for MSSQL Database
resource "azurerm_network_security_group" "sqlnsg" {
  name                = "sqlnsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

# Network Security Rule to allow SQL traffic
resource "azurerm_network_security_rule" "sqlrule" {
  name                        = "SQLTraffic"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "1433"
  source_address_prefix       = "VirtualNetwork"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.rg.name
  network_security_group_name = azurerm_network_security_group.sqlnsg.name
}

# Associate NSG to the Subnet
resource "azurerm_subnet_network_security_group_association" "sqlsubnetnsgassociation" {
  subnet_id                 = azurerm_subnet.endpointsubnet.id
  network_security_group_id = azurerm_network_security_group.sqlnsg.id
}

Then we have to follow the below commands :

terraform init

terraform plan

terraform apply

On doing this, the Terraform code provisions a secure 3-tier application infrastructure on Azure. It creates a resource group, virtual network with two subnets, an app service plan, frontend and backend web apps, a private DNS zone, and a private endpoint for the backend app. It also sets up an MSSQL server and database, along with a network security group and rules to allow SQL traffic within the virtual network.

10
Subscribe to my newsletter

Read articles from Kishaloy Kar Chowdhury directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kishaloy Kar Chowdhury
Kishaloy Kar Chowdhury