Skip to content

Instantly share code, notes, and snippets.

@Tcarters
Created October 24, 2024 15:55
Show Gist options
  • Select an option

  • Save Tcarters/61a5093058565fd3f0104fb40d8b6ee4 to your computer and use it in GitHub Desktop.

Select an option

Save Tcarters/61a5093058565fd3f0104fb40d8b6ee4 to your computer and use it in GitHub Desktop.
Building a 4-Tier Virtual Network on Azure Cloud using Terraform
## Step 1: App Subnet
resource "azurerm_subnet" "appsubnet" {
name = "${azurerm_virtual_network.vnet.name}-${var.app_subnetName}"
resource_group_name = azurerm_resource_group.mainRG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = var.app_subnetAddress
}
## Step 2: App Network Security Group
resource "azurerm_network_security_group" "app_subnet_nsg" {
name = "${azurerm_subnet.appsubnet.name}-nsg"
resource_group_name = azurerm_resource_group.mainRG.name
location = azurerm_resource_group.mainRG.location
}
## Step 3: App Security Rules
### Define locals Blocks for Security Rules
locals {
app_inbound_ports_map = {
"100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "="
"110" : "443",
"120" : "8080",
"130" : "22"
}
}
resource "azurerm_network_security_rule" "app_nsg_inbound" {
for_each = local.app_inbound_ports_map
name = "Allow-Rule-Port-${each.value}"
priority = "${each.key}"
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "${each.value}"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.mainRG.name
network_security_group_name = azurerm_network_security_group.app_subnet_nsg.name
}
## Step 4: App Association Subnet and NSG
resource "azurerm_subnet_network_security_group_association" "app_subnet_nsg_association" {
depends_on = [ azurerm_network_security_rule.app_nsg_inbound ]
subnet_id = azurerm_subnet.appsubnet.id
network_security_group_id = azurerm_network_security_group.app_subnet_nsg.id
}
# This manifest file is used to create bastion subnets and its NSG
## Step 1: Bastion / Management Subnet
resource "azurerm_subnet" "bastionsubnet" {
name = "${azurerm_virtual_network.vnet.name}-${var.bastion_subnetName}"
resource_group_name = azurerm_resource_group.mainRG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = var.bastion_subnetAddress
}
## Step 2: Bastion Network Security Group (NSG)
resource "azurerm_network_security_group" "bastion_subnet_nsg" {
name = "${azurerm_subnet.bastionsubnet.name}-nsg"
resource_group_name = azurerm_resource_group.mainRG.name
location = azurerm_resource_group.mainRG.location
}
## Step 3: Bastion Security Rules
### Define locals Blocks for Security Rules
locals {
bastion_inbound_ports_map = {
"400" : "22", # If the key starts with a number, you must use the colon syntax ":" instead of "="
"410" : "3389"
}
}
resource "azurerm_network_security_rule" "bastion_nsg_inbound" {
for_each = local.bastion_inbound_ports_map
name = "Allow-Rule-Port-${each.value}"
priority = "${each.key}"
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "${each.value}"
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.mainRG.name
network_security_group_name = azurerm_network_security_group.bastion_subnet_nsg.name
}
## Step 4: bastion Association Subnet and NSG
resource "azurerm_subnet_network_security_group_association" "bastion_subnet_nsg_association" {
depends_on = [ azurerm_network_security_rule.bastion_nsg_inbound ]
subnet_id = azurerm_subnet.bastionsubnet.id
network_security_group_id = azurerm_network_security_group.bastion_subnet_nsg.id
}
# This file define the creation of db subnets
## Step 1: Create dbTier Subnet
resource "azurerm_subnet" "dbsubnet" {
name = "${azurerm_virtual_network.vnet.name}-${var.db_subnetName}"
resource_group_name = azurerm_resource_group.mainRG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = var.db_subnetAddress
}
## Step 2: Create Network Security Group (NSG)
resource "azurerm_network_security_group" "db_subnet_nsg" {
name = "${azurerm_subnet.dbsubnet.name}-nsg"
location = azurerm_resource_group.mainRG.location
resource_group_name = azurerm_resource_group.mainRG.name
}
## Step 3: Associate NSG and Subnet
resource "azurerm_subnet_network_security_group_association" "db_subnet_nsg_association" {
depends_on = [ azurerm_network_security_rule.db_nsg_inbound ]
subnet_id = azurerm_subnet.dbsubnet.id
network_security_group_id = azurerm_network_security_group.db_subnet_nsg.id
}
## Step 4: Create NSG Rules for port 1433, 3306,
locals { # For each port we use the local blocks for security rules creation
db_inbound_ports_map = {
# We use colon below cause the key starts with a number
"300" : "3306",
"310" : "1433"
#"120" : "22"
}
}
# Defining NSG Inbound Rules for port 80, 443, 22 in the dbTier Subnets
resource "azurerm_network_security_rule" "db_nsg_inbound" {
for_each = local.db_inbound_ports_map
name = "Allow-Rule-Port-${each.value}"
priority = "${each.key}"
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*" # Allow all incoming connections
destination_port_range = "${each.value}" # Allow to port 22
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.mainRG.name
network_security_group_name = azurerm_network_security_group.db_subnet_nsg.name
}
# This file contains all varibles for building the Virtual Network and its subnets
## Virtual Network
variable "vnet_name" {
description = "This is the Virtual Network Name"
type = string
default = "mainVnet"
}
# Virtual Network Address space
variable "vnet_address_space" {
description = "Vnet Address Space"
type = list(string)
default = [ "10.0.0.0/16" ]
}
#--------->
## Subnet 1: Bastion / Management Subnet
variable "bastion_subnetName" {
description = "Vnet Subnet bastion"
type = string
default = "bastionSubnet"
}
# Bastion Subnet Address space
variable "bastion_subnetAddress" {
description = "Bastion Address Space"
type = list(string)
default = [ "10.0.200.0/24" ]
}
#-------->
## Subnet 2: DB Subnet
variable "db_subnetName" {
description = "Vnet Subnet db"
type = string
default = "dbSubnet"
}
# Db Subnet Address space
variable "db_subnetAddress" {
description = "DB Address Space"
type = list(string)
default = [ "10.0.10.0/24" ]
}
#-------->
## Subnet 3: Web Subnet
variable "web_subnetName" {
description = "Vnet Subnet web"
type = string
default = "webSubnet"
}
# Web Subnet Address space
variable "web_subnetAddress" {
description = "Web Address Space"
type = list(string)
default = [ "10.0.20.0/24" ]
}
#-------->
## Subnet 4: App Subnet
variable "app_subnetName" {
description = "Vnet Subnet app"
type = string
default = "appSubnet"
}
# App Subnet Address space
variable "app_subnetAddress" {
description = "App Address Space"
type = list(string)
default = [ "10.0.30.0/24" ]
}
# Input variables serve as parameters for a Terraform module , allowing aspects of the module to be customised without altering
# the module's own source code, and allowing modules to be shared between different configurations.
# Subscript ID
variable "subscription_id" {
}
# Dpartment division in the Entreprise
variable "department_division" {
description = "Department / Business Division refers to the large organization in this Infrastructure"
type = string
default = "guest"
}
# Environment variable
variable "environment" {
description = "this is the variable used as a prefix"
default = "staging"
}
# Az Resource Group name
variable "resource_group_name" {
description = "This is the Resource Group name variable"
type = string
default = "mainRG"
}
# Az Resource Location
variable "resource_location" {
description = "Azure resource Region"
type = string
default = "West Europe"
}
# A local value assigns a name to an expression, so you can use that name multiple times within a module without repeating it.
# Local values are like a function's temporary local variables.
locals {
owners = var.department_division
environment = var.environment
resourceName_prefix = "${var.department_division}-${var.environment}"
common_tags = {
owners = local.owners,
environment = local.environment
}
}
# Virtual Network Outputs
## Vnet name
output "vnet_name" {
description = "Virtual Network name"
value = azurerm_virtual_network.vnet.name
}
## Vnet ID
output "virtual_network_name_id" {
description = "Vnet ID"
value = azurerm_virtual_network.vnet.id
}
## Subnets Outputs
output "web_subnetName" {
description = "webTier Subnet name"
value = azurerm_subnet.websubnet.name
}
output "app_subnetName" {
description = "appTier Subnet name"
value = azurerm_subnet.appsubnet.name
}
output "db_subnetName" {
description = "dbTier Subnet name"
value = azurerm_subnet.dbsubnet.name
}
output "bastion_subnetName" {
description = "bastionTier Subnet name"
value = azurerm_subnet.bastionsubnet.name
}
## Network Security Group and IDs Outputs
### Web Subnet NSG Name 1
output "web_subnet_nsg" {
description = "webTier Subnet NSG Name"
value = azurerm_network_security_group.web_subnet_nsg.name
}
### Web Subnet NSG ID
output "web_subnet_nsg_id" {
description = "webTier Subnet NSG ID"
value = azurerm_network_security_group.web_subnet_nsg.id
}
### App Subnet NSG Name 2
output "app_subnet_nsg" {
description = "appTier Subnet NSG Name"
value = azurerm_network_security_group.app_subnet_nsg.name
}
### Web Subnet NSG ID
output "app_subnet_nsg_id" {
description = "appTier Subnet NSG ID"
value = azurerm_network_security_group.app_subnet_nsg.id
}
### Db Subnet NSG Name 3
output "db_subnet_nsg" {
description = "dbTier Subnet NSG Name"
value = azurerm_network_security_group.db_subnet_nsg.name
}
### Web Subnet NSG ID
output "db_subnet_nsg_id" {
description = "dbTier Subnet NSG ID"
value = azurerm_network_security_group.db_subnet_nsg.id
}
### Bastion Subnet NSG Name 4
output "bastion_subnet_nsg" {
description = "bastionTier Subnet NSG Name"
value = azurerm_network_security_group.bastion_subnet_nsg.name
}
### Web Subnet NSG ID
output "bastion_subnet_nsg_id" {
description = "bastionTier Subnet NSG ID"
value = azurerm_network_security_group.bastion_subnet_nsg.id
}
# locals {
# list_subnets = {
# "subnet1" = "web",
# subnet2 = "app",
# subnet3 = "db",
# subnet4 = "bastion"
# }
# }
# for_each = local.list_subnets
# # output "$${each.value}_subnetName" {
# # description = "${each.key} - ${each.value}"
# # value = "azure_subnet.${each.value}_subnetName.name"
# # }
# output "subnet_outputs" {
# value = { for key, value in local.list_subnets : "${value}_subnetName" => azure_subnet[value].name }
# }
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 4.5.0"
}
}
}
# Provider Block
provider "azurerm" {
subscription_id = var.subscription_id
features {
}
}
# Random string Resource
resource "random_string" "myRandom" {
length = 6
upper = false
special = false
}
# Resource Group definition
resource "azurerm_resource_group" "mainRG" {
name = "${local.resourceName_prefix}-${var.resource_group_name}-${random_string.myRandom.id}"
location = var.resource_location
tags = local.common_tags
}
department_division = "eng" #<Put your real department division here, recommended for production>
subscription_id = "" # <Put your azure account subscription here>
# this is the definition of the virtual network to be created
resource "azurerm_virtual_network" "vnet" {
name = "${local.resourceName_prefix}-${var.vnet_name}"
resource_group_name = azurerm_resource_group.mainRG.name
location = azurerm_resource_group.mainRG.location
address_space = var.vnet_address_space
tags = local.common_tags
}
# This file define the creation of web subnets
## Step 1: Create WebTier Subnet
resource "azurerm_subnet" "websubnet" {
name = "${azurerm_virtual_network.vnet.name}-${var.web_subnetName}"
resource_group_name = azurerm_resource_group.mainRG.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = var.web_subnetAddress
}
## Step 2: Create Network Security Group (NSG)
resource "azurerm_network_security_group" "web_subnet_nsg" {
name = "${azurerm_subnet.websubnet.name}-nsg"
location = azurerm_resource_group.mainRG.location
resource_group_name = azurerm_resource_group.mainRG.name
}
## Step 3: Associate NSG and Subnet
resource "azurerm_subnet_network_security_group_association" "web_subnet_nsg_association" {
depends_on = [ azurerm_network_security_rule.web_nsg_inbound ]
subnet_id = azurerm_subnet.websubnet.id
network_security_group_id = azurerm_network_security_group.web_subnet_nsg.id
}
## Step 4: Create NSG Rules for port 22, 80, 443, 8080, 8081, 8082, 9090, 9091
locals { # For each port we use the local blocks for security rules creation
web_inbound_ports_map = {
# We use colon below cause the key starts with a number
"200" : "80",
"210" : "443",
"220" : "22"
}
}
# Defining NSG Inbound Rules for port 80, 443, 22 in the WebTier Subnets
resource "azurerm_network_security_rule" "web_nsg_inbound" {
for_each = local.web_inbound_ports_map
name = "Allow-Rule-Port-${each.value}"
priority = "${each.key}"
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*" # Allow all incoming connections
destination_port_range = "${each.value}" # Allow to port 22
source_address_prefix = "*"
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.mainRG.name
network_security_group_name = azurerm_network_security_group.web_subnet_nsg.name
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment