Merge pull request #94 from svc-design/codex/add-azure-terraform-template-with-modules

Add Azure Terraform template aligned with AWS structure
This commit is contained in:
shenlan 2025-11-21 12:30:03 +08:00 committed by GitHub
commit 3f318c08a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 1235 additions and 0 deletions

View File

@ -0,0 +1,33 @@
# Azure Cloud Terraform Standard
该目录提供与 `aws-cloud` 模板一一对应的 Azure 版本延续相同的目录与模块命名bootstrap、config、modules、envs便于将 AWS 使用习惯映射到 Azure。
## 模板映射AWS → Azure
- **bootstrap-s3 → Storage Account**:创建存储账户与容器用于 Terraform 远端状态。
- **bootstrap-dynamodb → Cosmos DB Table API**:提供无服务器键值表存储。
- **bootstrap-iam → RBAC 角色分配**:为指定主体分配内置角色,替代 AWS IAM 角色/策略。
- **modules**:保留 AWS 模块命名,内部实现替换为 Azure 服务:
- `vpc`:虚拟网络 + 子网Virtual Network/Subnet
- `alb`应用程序网关Application Gateway
- `nlb`标准负载均衡器Standard Load Balancer
- `ec2`Linux 虚拟机Virtual Machine
- `s3`存储账户与容器Storage Account + Container
- `rds`PostgreSQL 灵活服务器Flexible Server
- `redis`Azure Cache for Redis。
- `sg`网络安全组与规则Network Security Group
- `iam`基于内置角色的角色分配Role Assignment
- `ami_lookup`公共镜像查找Ubuntu 平台镜像)。
- `landingzone`:基础资源组与日志工作区。
- `keypair`:生成 SSH 密钥对。
- `msk`:事件中心命名空间与 HubEvent Hubs
## 使用方式
1. 在 `config/backend.tf` 中配置 Azure 存储作为 Terraform 远端状态(资源组、存储账户、容器)。
2. 在 `config/provider.tf` 中设置 `subscription_id`、`tenant_id`、`location` 等参数。
3. 参考 `envs/dev/main.tf`,按需修改变量后执行:
```bash
terraform -chdir=envs/dev init
terraform -chdir=envs/dev apply
```
本目录新增 Azure 代码,不改动现有 AWS 模板。

View File

@ -0,0 +1,68 @@
variable "resource_group_name" {
description = "Resource group for the Cosmos DB account"
type = string
}
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "account_name" {
description = "Cosmos DB account name"
type = string
}
variable "table_name" {
description = "Table (Table API) name"
type = string
default = "tfstate-lock"
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "cosmos" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_cosmosdb_account" "table" {
name = var.account_name
location = azurerm_resource_group.cosmos.location
resource_group_name = azurerm_resource_group.cosmos.name
offer_type = "Standard"
kind = "GlobalDocumentDB"
consistency_policy {
consistency_level = "Session"
}
capabilities {
name = "EnableTable"
}
geo_location {
location = azurerm_resource_group.cosmos.location
failover_priority = 0
}
}
resource "azurerm_cosmosdb_table" "state_lock" {
name = var.table_name
resource_group_name = azurerm_resource_group.cosmos.name
account_name = azurerm_cosmosdb_account.table.name
throughput = 400
}
output "account" {
value = azurerm_cosmosdb_account.table.name
description = "Cosmos DB account for lock table"
}
output "table" {
value = azurerm_cosmosdb_table.state_lock.name
description = "Table API collection used for state locking"
}

View File

@ -0,0 +1,50 @@
variable "resource_group_name" {
description = "Resource group where role assignment is scoped"
type = string
}
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "principal_id" {
description = "Object ID of the user/service principal/group to assign"
type = string
}
variable "role_definition_name" {
description = "Built-in role to assign"
type = string
default = "Contributor"
}
provider "azurerm" {
features {}
}
data "azurerm_role_definition" "selected" {
name = var.role_definition_name
}
resource "azurerm_resource_group" "iam" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_role_assignment" "scope_assignment" {
scope = azurerm_resource_group.iam.id
role_definition_id = data.azurerm_role_definition.selected.id
principal_id = var.principal_id
}
output "role_definition" {
value = data.azurerm_role_definition.selected.name
description = "Role assigned to the principal"
}
output "scope" {
value = azurerm_resource_group.iam.id
description = "Scope where the role assignment is created"
}

View File

@ -0,0 +1,63 @@
variable "resource_group_name" {
description = "Resource group for state storage"
type = string
default = "tfstate-rg"
}
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "storage_account_name" {
description = "Storage account name for Terraform state"
type = string
default = "tfstateaccount"
}
variable "container_name" {
description = "Blob container to store state"
type = string
default = "tfstate"
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "state" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_storage_account" "state" {
name = var.storage_account_name
resource_group_name = azurerm_resource_group.state.name
location = azurerm_resource_group.state.location
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2"
allow_blob_public_access = false
}
resource "azurerm_storage_container" "state" {
name = var.container_name
storage_account_name = azurerm_storage_account.state.name
container_access_type = "private"
}
output "resource_group" {
value = azurerm_resource_group.state.name
description = "Resource group created for Terraform state"
}
output "storage_account" {
value = azurerm_storage_account.state.name
description = "Storage account for Terraform state"
}
output "container" {
value = azurerm_storage_container.state.name
description = "Blob container used for Terraform state"
}

View File

@ -0,0 +1,9 @@
terraform {
backend "azurerm" {
# 使
resource_group_name = "tfstate-rg"
storage_account_name = "tfstateaccount"
container_name = "tfstate"
key = "terraform.tfstate"
}
}

View File

@ -0,0 +1,15 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.90.0"
}
}
}
provider "azurerm" {
features {}
subscription_id = var.subscription_id
tenant_id = var.tenant_id
}

View File

@ -0,0 +1,15 @@
variable "subscription_id" {
description = "Azure subscription id"
type = string
}
variable "tenant_id" {
description = "Azure AD tenant id"
type = string
}
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}

View File

@ -0,0 +1,142 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.90.0"
}
tls = {
source = "hashicorp/tls"
version = ">= 4.0"
}
}
}
variable "subscription_id" {
type = string
description = "Target subscription"
}
variable "tenant_id" {
type = string
description = "AAD tenant id"
}
variable "location" {
type = string
description = "Azure region"
default = "eastus"
}
variable "principal_id" {
type = string
description = "Principal to grant Contributor on the landing zone"
}
provider "azurerm" {
features {}
subscription_id = var.subscription_id
tenant_id = var.tenant_id
}
locals {
resource_group_name = "demo-rg"
vnet_name = "demo-vnet"
}
module "landingzone" {
source = "../../modules/landingzone"
resource_group_name = local.resource_group_name
location = var.location
}
module "iam" {
source = "../../modules/iam"
scope = module.landingzone.resource_group_id
principal_id = var.principal_id
role_definition_name = "Contributor"
}
module "vpc" {
source = "../../modules/vpc"
resource_group_name = module.landingzone.resource_group_name
location = var.location
vnet_name = local.vnet_name
address_space = ["10.20.0.0/16"]
subnets = [
{
name = "app"
address_prefix = "10.20.1.0/24"
}
]
}
module "nsg" {
source = "../../modules/sg"
resource_group_name = module.landingzone.resource_group_name
location = var.location
name = "demo-nsg"
}
resource "azurerm_subnet_network_security_group_association" "app" {
subnet_id = module.vpc.subnet_ids["app"]
network_security_group_id = module.nsg.nsg_id
}
module "keypair" {
source = "../../modules/keypair"
}
module "vm" {
source = "../../modules/ec2"
resource_group_name = module.landingzone.resource_group_name
location = var.location
vm_name = "demo-vm"
subnet_id = module.vpc.subnet_ids["app"]
admin_username = "azureuser"
ssh_public_key = module.keypair.public_key_openssh
}
module "storage" {
source = "../../modules/s3"
resource_group_name = module.landingzone.resource_group_name
location = var.location
storage_account_name = "demostorageacct01"
container_name = "artifacts"
}
module "database" {
source = "../../modules/rds"
resource_group_name = module.landingzone.resource_group_name
location = var.location
server_name = "demo-postgres"
admin_username = "pgadmin"
admin_password = "P@ssword12345!"
db_name = "appdb"
public_network_access_enabled = true
}
module "cache" {
source = "../../modules/redis"
resource_group_name = module.landingzone.resource_group_name
location = var.location
name = "demorediscache"
sku_name = "Standard"
capacity = 1
}
output "resource_group" {
value = module.landingzone.resource_group_name
description = "Resource group provisioned for demo"
}
output "vm_id" {
value = module.vm.vm_id
description = "Demo VM ID"
}
output "ssh_private_key" {
value = module.keypair.private_key_pem
description = "Private key to access the VM"
sensitive = true
}

View File

@ -0,0 +1,114 @@
variable "resource_group_name" {
description = "Resource group for the Application Gateway"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "name" {
description = "Application Gateway name"
type = string
default = "app-gateway"
}
variable "subnet_id" {
description = "Subnet ID used by the Application Gateway"
type = string
}
variable "backend_port" {
description = "Backend port for the default pool"
type = number
default = 80
}
variable "sku_name" {
description = "Application Gateway SKU"
type = string
default = "Standard_v2"
}
variable "capacity" {
description = "Instance count"
type = number
default = 1
}
resource "azurerm_public_ip" "gateway" {
name = "${var.name}-pip"
resource_group_name = var.resource_group_name
location = var.location
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_application_gateway" "this" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
sku {
name = var.sku_name
tier = "Standard_v2"
}
autoscale_configuration {
min_capacity = var.capacity
max_capacity = var.capacity
}
gateway_ip_configuration {
name = "gateway-ipcfg"
subnet_id = var.subnet_id
}
frontend_port {
name = "frontend-port"
port = 80
}
frontend_ip_configuration {
name = "frontend-ip"
public_ip_address_id = azurerm_public_ip.gateway.id
}
backend_address_pool {
name = "default-backend"
}
backend_http_settings {
name = "default-http"
cookie_based_affinity = "Disabled"
port = var.backend_port
protocol = "Http"
request_timeout = 30
}
http_listener {
name = "http-listener"
frontend_ip_configuration_name = "frontend-ip"
frontend_port_name = "frontend-port"
protocol = "Http"
}
request_routing_rule {
name = "http-rule"
rule_type = "Basic"
http_listener_name = "http-listener"
backend_address_pool_name = "default-backend"
backend_http_settings_name = "default-http"
}
}
output "application_gateway_id" {
value = azurerm_application_gateway.this.id
description = "Application Gateway resource ID"
}
output "public_ip" {
value = azurerm_public_ip.gateway.ip_address
description = "Public IP assigned to the Application Gateway"
}

View File

@ -0,0 +1,40 @@
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "publisher" {
description = "Image publisher"
type = string
default = "Canonical"
}
variable "offer" {
description = "Image offer"
type = string
default = "0001-com-ubuntu-server-focal"
}
variable "sku" {
description = "Image SKU"
type = string
default = "20_04-lts"
}
data "azurerm_platform_image" "ubuntu" {
location = var.location
publisher = var.publisher
offer = var.offer
sku = var.sku
}
output "image" {
value = {
publisher = data.azurerm_platform_image.ubuntu.publisher
offer = data.azurerm_platform_image.ubuntu.offer
sku = data.azurerm_platform_image.ubuntu.sku
version = data.azurerm_platform_image.ubuntu.version
}
description = "Latest platform image metadata"
}

View File

@ -0,0 +1,104 @@
variable "resource_group_name" {
description = "Resource group for the VM"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "vm_name" {
description = "Virtual machine name"
type = string
default = "vm"
}
variable "subnet_id" {
description = "Subnet ID to attach the VM"
type = string
}
variable "admin_username" {
description = "Admin username for the VM"
type = string
default = "azureuser"
}
variable "ssh_public_key" {
description = "Public SSH key for login"
type = string
}
variable "vm_size" {
description = "Azure VM size"
type = string
default = "Standard_B2s"
}
variable "source_image" {
description = "Platform image definition"
type = object({
publisher = string
offer = string
sku = string
version = string
})
default = {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-focal"
sku = "20_04-lts"
version = "latest"
}
}
resource "azurerm_network_interface" "vm" {
name = "${var.vm_name}-nic"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "ipconfig1"
subnet_id = var.subnet_id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "vm" {
name = var.vm_name
resource_group_name = var.resource_group_name
location = var.location
size = var.vm_size
admin_username = var.admin_username
network_interface_ids = [
azurerm_network_interface.vm.id
]
admin_ssh_key {
username = var.admin_username
public_key = var.ssh_public_key
}
os_disk {
name = "${var.vm_name}-osdisk"
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = var.source_image.publisher
offer = var.source_image.offer
sku = var.source_image.sku
version = var.source_image.version
}
}
output "vm_id" {
value = azurerm_linux_virtual_machine.vm.id
description = "Virtual machine resource ID"
}
output "nic_id" {
value = azurerm_network_interface.vm.id
description = "Network interface ID"
}

View File

@ -0,0 +1,31 @@
variable "scope" {
description = "Scope for the role assignment"
type = string
}
variable "principal_id" {
description = "Object ID of the principal to assign"
type = string
}
variable "role_definition_name" {
description = "Built-in role name"
type = string
default = "Contributor"
}
data "azurerm_role_definition" "selected" {
name = var.role_definition_name
scope = var.scope
}
resource "azurerm_role_assignment" "assignment" {
scope = var.scope
role_definition_id = data.azurerm_role_definition.selected.id
principal_id = var.principal_id
}
output "role_definition" {
value = data.azurerm_role_definition.selected.name
description = "Role assigned to the principal"
}

View File

@ -0,0 +1,27 @@
variable "algorithm" {
description = "Algorithm for the SSH key"
type = string
default = "RSA"
}
variable "rsa_bits" {
description = "RSA bits for the key when algorithm is RSA"
type = number
default = 4096
}
resource "tls_private_key" "ssh" {
algorithm = var.algorithm
rsa_bits = var.algorithm == "RSA" ? var.rsa_bits : null
}
output "private_key_pem" {
value = tls_private_key.ssh.private_key_pem
sensitive = true
description = "Generated private key"
}
output "public_key_openssh" {
value = tls_private_key.ssh.public_key_openssh
description = "Generated public key"
}

View File

@ -0,0 +1,45 @@
variable "resource_group_name" {
description = "Resource group to bootstrap"
type = string
default = "landingzone-rg"
}
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "log_analytics_workspace_name" {
description = "Log Analytics workspace name"
type = string
default = "landingzone-law"
}
resource "azurerm_resource_group" "this" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_log_analytics_workspace" "logs" {
name = var.log_analytics_workspace_name
location = var.location
resource_group_name = azurerm_resource_group.this.name
sku = "PerGB2018"
retention_in_days = 30
}
output "resource_group_id" {
value = azurerm_resource_group.this.id
description = "Landing zone resource group ID"
}
output "log_analytics_workspace_id" {
value = azurerm_log_analytics_workspace.logs.id
description = "Log Analytics workspace ID"
}
output "resource_group_name" {
value = azurerm_resource_group.this.name
description = "Landing zone resource group name"
}

View File

@ -0,0 +1,58 @@
variable "resource_group_name" {
description = "Resource group for Event Hubs"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "namespace_name" {
description = "Event Hubs namespace name"
type = string
}
variable "eventhub_name" {
description = "Event Hub name"
type = string
default = "events"
}
variable "partition_count" {
description = "Number of partitions"
type = number
default = 2
}
variable "message_retention" {
description = "Message retention in days"
type = number
default = 1
}
resource "azurerm_eventhub_namespace" "ns" {
name = var.namespace_name
location = var.location
resource_group_name = var.resource_group_name
sku = "Standard"
capacity = 1
}
resource "azurerm_eventhub" "hub" {
name = var.eventhub_name
namespace_name = azurerm_eventhub_namespace.ns.name
resource_group_name = var.resource_group_name
partition_count = var.partition_count
message_retention = var.message_retention
}
output "namespace_id" {
value = azurerm_eventhub_namespace.ns.id
description = "Event Hubs namespace ID"
}
output "eventhub_id" {
value = azurerm_eventhub.hub.id
description = "Event Hub ID"
}

View File

@ -0,0 +1,101 @@
variable "resource_group_name" {
description = "Resource group for the load balancer"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "name" {
description = "Load balancer name"
type = string
default = "nlb"
}
variable "protocol" {
description = "Frontend protocol"
type = string
default = "Tcp"
}
variable "frontend_port" {
description = "Frontend port"
type = number
default = 80
}
variable "backend_port" {
description = "Backend port"
type = number
default = 80
}
variable "backend_pool_backend_ids" {
description = "List of backend NIC IDs or IP configurations"
type = list(string)
default = []
}
resource "azurerm_public_ip" "lb" {
name = "${var.name}-pip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_lb" "this" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
sku = "Standard"
frontend_ip_configuration {
name = "public"
public_ip_address_id = azurerm_public_ip.lb.id
}
}
resource "azurerm_lb_backend_address_pool" "pool" {
name = "backendpool"
loadbalancer_id = azurerm_lb.this.id
}
resource "azurerm_lb_probe" "tcp" {
name = "tcp-probe"
resource_group_name = var.resource_group_name
loadbalancer_id = azurerm_lb.this.id
protocol = var.protocol
port = var.backend_port
}
resource "azurerm_lb_rule" "lb_rule" {
name = "lb-rule"
resource_group_name = var.resource_group_name
loadbalancer_id = azurerm_lb.this.id
protocol = var.protocol
frontend_port = var.frontend_port
backend_port = var.backend_port
frontend_ip_configuration_name = "public"
backend_address_pool_id = azurerm_lb_backend_address_pool.pool.id
probe_id = azurerm_lb_probe.tcp.id
}
resource "azurerm_network_interface_backend_address_pool_association" "attach" {
for_each = toset(var.backend_pool_backend_ids)
network_interface_id = each.value
ip_configuration_name = "ipconfig1"
backend_address_pool_id = azurerm_lb_backend_address_pool.pool.id
}
output "lb_public_ip" {
value = azurerm_public_ip.lb.ip_address
description = "Public IP assigned to the load balancer"
}
output "backend_pool_id" {
value = azurerm_lb_backend_address_pool.pool.id
description = "Backend address pool ID"
}

View File

@ -0,0 +1,95 @@
variable "resource_group_name" {
description = "Resource group for the database"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "server_name" {
description = "PostgreSQL flexible server name"
type = string
}
variable "admin_username" {
description = "Admin username"
type = string
default = "pgadmin"
}
variable "admin_password" {
description = "Admin password"
type = string
sensitive = true
}
variable "version" {
description = "PostgreSQL version"
type = string
default = "14"
}
variable "sku_name" {
description = "SKU name for flexible server"
type = string
default = "GP_Standard_D2ds_v4"
}
variable "storage_mb" {
description = "Storage in MB"
type = number
default = 32768
}
variable "db_name" {
description = "Default database name"
type = string
default = "app"
}
variable "public_network_access_enabled" {
description = "Allow public network access"
type = bool
default = true
}
resource "azurerm_postgresql_flexible_server" "this" {
name = var.server_name
resource_group_name = var.resource_group_name
location = var.location
version = var.version
administrator_login = var.admin_username
administrator_password = var.admin_password
sku_name = var.sku_name
storage_mb = var.storage_mb
zone = 1
backup_retention_days = 7
public_network_access_enabled = var.public_network_access_enabled
}
resource "azurerm_postgresql_flexible_database" "db" {
name = var.db_name
server_id = azurerm_postgresql_flexible_server.this.id
charset = "UTF8"
collation = "en_US.utf8"
}
resource "azurerm_postgresql_flexible_server_firewall_rule" "allow_all" {
count = var.public_network_access_enabled ? 1 : 0
name = "allow-all"
server_id = azurerm_postgresql_flexible_server.this.id
start_ip_address = "0.0.0.0"
end_ip_address = "255.255.255.255"
}
output "server_fqdn" {
value = azurerm_postgresql_flexible_server.this.fqdn
description = "Database server FQDN"
}
output "database_name" {
value = azurerm_postgresql_flexible_database.db.name
description = "Database name created"
}

View File

@ -0,0 +1,48 @@
variable "resource_group_name" {
description = "Resource group for Redis"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "name" {
description = "Redis cache name"
type = string
}
variable "sku_name" {
description = "Redis SKU name"
type = string
default = "Standard"
}
variable "capacity" {
description = "Redis capacity (size family dependent)"
type = number
default = 1
}
resource "azurerm_redis_cache" "this" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
capacity = var.capacity
family = "C"
sku_name = var.sku_name
enable_non_ssl_port = false
minimum_tls_version = "1.2"
}
output "hostname" {
value = azurerm_redis_cache.this.hostname
description = "Redis hostname"
}
output "primary_key" {
value = azurerm_redis_cache.this.primary_access_key
sensitive = true
description = "Redis primary key"
}

View File

@ -0,0 +1,46 @@
variable "resource_group_name" {
description = "Resource group for storage"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "storage_account_name" {
description = "Storage account name"
type = string
}
variable "container_name" {
description = "Blob container name"
type = string
default = "app"
}
resource "azurerm_storage_account" "this" {
name = var.storage_account_name
resource_group_name = var.resource_group_name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2"
allow_blob_public_access = false
}
resource "azurerm_storage_container" "this" {
name = var.container_name
storage_account_name = azurerm_storage_account.this.name
container_access_type = "private"
}
output "storage_account_id" {
value = azurerm_storage_account.this.id
description = "Storage account ID"
}
output "container_name" {
value = azurerm_storage_container.this.name
description = "Blob container name"
}

View File

@ -0,0 +1,69 @@
variable "resource_group_name" {
description = "Resource group for NSG"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "name" {
description = "Network security group name"
type = string
default = "nsg"
}
variable "rules" {
description = "List of security rules"
type = list(object({
name = string
priority = number
direction = string
access = string
protocol = string
source_port_range = string
destination_port_range = string
source_address_prefix = string
destination_address_prefix = string
}))
default = [
{
name = "ssh"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
]
}
resource "azurerm_network_security_group" "this" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
}
resource "azurerm_network_security_rule" "rules" {
for_each = { for rule in var.rules : rule.name => rule }
name = each.value.name
priority = each.value.priority
direction = each.value.direction
access = each.value.access
protocol = each.value.protocol
source_port_range = each.value.source_port_range
destination_port_range = each.value.destination_port_range
source_address_prefix = each.value.source_address_prefix
destination_address_prefix = each.value.destination_address_prefix
resource_group_name = var.resource_group_name
network_security_group_name = azurerm_network_security_group.this.name
}
output "nsg_id" {
value = azurerm_network_security_group.this.id
description = "Network security group ID"
}

View File

@ -0,0 +1,62 @@
variable "resource_group_name" {
description = "Resource group for the virtual network"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "vnet_name" {
description = "Virtual network name"
type = string
default = "main-vnet"
}
variable "address_space" {
description = "Address space for the virtual network"
type = list(string)
default = ["10.10.0.0/16"]
}
variable "subnets" {
description = "Subnets to create inside the VNet"
type = list(object({
name = string
address_prefix = string
service_endpoints = optional(list(string), [])
}))
default = [
{
name = "default"
address_prefix = "10.10.1.0/24"
}
]
}
resource "azurerm_virtual_network" "this" {
name = var.vnet_name
address_space = var.address_space
location = var.location
resource_group_name = var.resource_group_name
}
resource "azurerm_subnet" "this" {
for_each = { for subnet in var.subnets : subnet.name => subnet }
name = each.value.name
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.this.name
address_prefixes = [each.value.address_prefix]
service_endpoints = lookup(each.value, "service_endpoints", [])
}
output "vnet_id" {
value = azurerm_virtual_network.this.id
description = "Virtual network resource ID"
}
output "subnet_ids" {
value = { for name, subnet in azurerm_subnet.this : name => subnet.id }
description = "Map of subnet IDs keyed by name"
}