diff --git a/terraform/azure/examples/mysql-db/main.tf b/terraform/azure/examples/mysql-db/main.tf new file mode 100644 index 0000000..1699393 --- /dev/null +++ b/terraform/azure/examples/mysql-db/main.tf @@ -0,0 +1,78 @@ + + +provider "azurerm" { + features {} +} + +module "mysql_db" { +source = "../modules/mysql-db" + +# Add all required variables for the module +vnet_name = "my-vnet" +vnet_address_space = ["10.0.0.0/16"] +location = "Central India" +resource_group_name = "sample-resource-group" +subnet_name = "test-subnet" +subnet_address_prefixes = ["10.0.1.0/24", "10.0.2.0/24"] +nsg_name = "my-nsg" + +inbound_rules = [ + { + name = "allow_ssh" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } +] + +outbound_rules = [ + { + name = "allow_all" + priority = 100 + direction = "Outbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "*" + source_address_prefix = "*" + destination_address_prefix = "*" + } +] + + subnet_service_endpoints = ["Microsoft.Storage"] + subnet_delegation_name = "test-delegation" + subnet_service_delegation_name = "Microsoft.DBforMySQL/flexibleServers" + subnet_service_delegation_actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"] + private_dns_zone_name = "test.mysql.database.azure.com" + private_dns_zone_link_name = "sampleVnetZone.com" + mysql_server_name = "samplesqlserver02" + mysql_admin_login = "mysqladmin" + mysql_admin_password = "Password@123" + mysql_backup_retention_days = 7 + mysql_sku_name = "B_Standard_B1s" + mysql_zone = "2" + mysql_database_name = "sample-mysql-db" + mysql_database_charset = "utf8" + mysql_database_collation = "utf8_general_ci" + mysql_private_endpoint_name = "myPrivateEndpoint" + mysql_private_endpoint_connection_name = "myPrivateConnection" + environment = "dev" + mysql_firewall_rules = [ + { + name = "AllowAllWindowsAzureIps" + start_ip_address = "0.0.0.0" + end_ip_address = "0.0.0.0" + }, + { + name = "AllowMyIP" + start_ip_address = "123.456.789.0" + end_ip_address = "123.456.789.0" + } + ] +} + diff --git a/terraform/azure/examples/mysql-db/provider.tf b/terraform/azure/examples/mysql-db/provider.tf new file mode 100644 index 0000000..eae504a --- /dev/null +++ b/terraform/azure/examples/mysql-db/provider.tf @@ -0,0 +1,20 @@ + + +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~>1.5.0" + } + } +} + +provider "azurerm" { + features {} + + client_id = " " + client_secret = " " + tenant_id = " " + subscription_id = " " + skip_provider_registration = true +} \ No newline at end of file diff --git a/terraform/azure/modules/mysql-db/README.md b/terraform/azure/modules/mysql-db/README.md new file mode 100644 index 0000000..751df20 --- /dev/null +++ b/terraform/azure/modules/mysql-db/README.md @@ -0,0 +1,87 @@ +# Terraform Module: Azure MySQL Flexible Server + +This Terraform module creates an Azure MySQL Flexible Server along with a MySQL database and optional firewall rules. + +## Module Usage + +To use this module, create a new Terraform configuration file and include the module: + +```hcl +provider "azurerm" { + features {} +} + +module "azure_sql_db_flexible" { + source = "./terraform-azure-sql-db-flexible" + + resource_group_name = "sample-resource-group" + location = "Central India" + virtual_network_name = "my-vnet" + address_space = ["10.0.0.0/16"] + subnet_name = "my-subnet" + subnet_address_prefixes = ["10.0.2.0/24"] + subnet_service_endpoints = ["Microsoft.Storage"] + subnet_delegation_name = "test-delegation" + subnet_service_delegation_name = "Microsoft.DBforMySQL/flexibleServers" + subnet_service_delegation_actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"] + private_dns_zone_name = "test.mysql.database.azure.com" + private_dns_zone_link_name = "sampleVnetZone.com" + mysql_server_name = "sample-mysql-server" + mysql_admin_login = "mysqladmin" + mysql_admin_password = "Password@123" + mysql_backup_retention_days = 7 + mysql_sku_name = "B_Standard_B1s" + mysql_zone = "2" + mysql_database_name = "sample-mysql-db" + mysql_database_charset = "utf8" + mysql_database_collation = "utf8_general_ci" + mysql_firewall_rules = [ + { + name = "AllowAllWindowsAzureIps" + start_ip_address = "0.0.0.0" + end_ip_address = "0.0.0.0" + }, + { + name = "AllowMyIP" + start_ip_address = "123.456.789.0" + end_ip_address = "123.456.789.0" + } + ] +} +``` + + +## Inputs + +| Name | Description | Type | Default | Required | +|------------------------|----------------------------------------------|------------|---------|----------| +| `resource_group_name` | Name of the Azure Resource Group. | `string` | n/a | Yes | +| `vnet_name` | Name of the Azure Virtual Network. | `string` | n/a | Yes | +| `address_space` | Address space for the VNet. | `list(string)` |n/a | Yes | +| `location` | Azure region where resources will be created.| `string` | n/a | Yes | +| `subnet_names` | List of subnet names. | `list(string)` | n/a | Yes | +| `subnet_address_prefixes` | List of subnet address prefixes. | `list(string)` | n/a | Yes | +| `subnet_service_endpoints`| The service endpoints for the Azure subnet.| `list(string)` | n/a |Yes | +| `subnet_delegation_name` | The name of the subnet delegation. | `string` | n/a | yes | +| `subnet_service_delegation_name` | The service delegation name for the subnet. | `string` | n/a | yes | +| `subnet_service_delegation_actions` | The actions allowed for the subnet service delegation. | `list(string)` | n/a | yes | +| `private_dns_zone_name` | The name of the Azure private DNS zone. | `string` | n/a | yes | +| `private_dns_zone_link_name` | The name of the virtual network link to private DNS zone. | `string` | n/a | yes | +| `mysql_server_name` | The name of the MySQL Server. | `string` | n/a | yes | +| `mysql_admin_login` | The administrator login name for the MySQL server. | `string` | n/a | yes | +| `mysql_admin_password` | The password associated with the MySQL administrator login. | `string` | n/a | yes | +| `mysql_backup_retention_days` | The backup retention days for the MySQL server. | `number` | 7 | yes | +| `mysql_sku_name` | The SKU name for the MySQL server. | `string` | "GP_Standard_D2ds_v4" | yes | +| `mysql_zone` | The availability zone for the MySQL server. | `string` | "2" | yes | +| `mysql_database_name` | The name of the MySQL database. | `string` | n/a | yes | +| `mysql_database_charset` | The charset for the MySQL database. | `string` | "utf8" | yes | +| `mysql_database_collation` | The collation for the MySQL database. | `string` | "utf8_general_ci" | yes | + + +## Outputs + +| Name | Description | +|-------------|---------------------------------------------------| +| `mysql_server_name` | The name of the MySQL server. | +| `mysql_server_fully_qualified_domain_name` | The fully qualified domain name of the MySQL server. | +| `mysql_database_name` | The name of the MySQL database. | diff --git a/terraform/azure/modules/mysql-db/main.tf b/terraform/azure/modules/mysql-db/main.tf new file mode 100644 index 0000000..09a5ce4 --- /dev/null +++ b/terraform/azure/modules/mysql-db/main.tf @@ -0,0 +1,78 @@ + + +provider "azurerm" { + features {} +} + +# Module for network +module "network" { + source = "../vnet" + vnet_name = var.vnet_name + address_space = var.vnet_address_space + location = var.location + resource_group_name = var.resource_group_name + subnet_names = var.subnet_names + subnet_address_prefixes = var.subnet_address_prefixes + nsg_name = var.nsg_name + inbound_rules = var.inbound_rules + outbound_rules = var.outbound_rules + environment = var.environment +} + +resource "azurerm_private_dns_zone" "domain" { + name = var.private_dns_zone_name + resource_group_name = var.resource_group_name +} + +resource "azurerm_private_dns_zone_virtual_network_link" "vlink" { + name = var.private_dns_zone_link_name + private_dns_zone_name = azurerm_private_dns_zone.domain.name + virtual_network_id = module.network.vnet_id + resource_group_name = var.resource_group_name +} + +resource "azurerm_mysql_flexible_server" "sqlserver" { + name = var.mysql_server_name + resource_group_name = var.resource_group_name + location = var.location + administrator_login = var.mysql_admin_login + administrator_password = var.mysql_admin_password + backup_retention_days = var.mysql_backup_retention_days + delegated_subnet_id = module.network.subnet_ids[0] # Using the first subnet ID + private_dns_zone_id = azurerm_private_dns_zone.domain.id + sku_name = var.mysql_sku_name + zone = var.mysql_zone + + depends_on = [azurerm_private_dns_zone_virtual_network_link.vlink] +} + +resource "azurerm_mysql_flexible_database" "sqldb" { + name = var.mysql_database_name + resource_group_name = var.resource_group_name + server_name = azurerm_mysql_flexible_server.sqlserver.name + charset = var.mysql_database_charset + collation = var.mysql_database_collation +} + +resource "azurerm_mysql_flexible_server_firewall_rule" "firewall" { + name = var.mysql_firewall_rule_name + resource_group_name = var.resource_group_name + server_name = azurerm_mysql_flexible_server.sqlserver.name + start_ip_address = var.mysql_firewall_start_ip + end_ip_address = var.mysql_firewall_end_ip +} + +# Private Endpoint +resource "azurerm_private_endpoint" "mysql_private_endpoint" { + name = var.mysql_private_endpoint_name + location = var.location + resource_group_name = var.resource_group_name + subnet_id = module.network.subnet_ids[0] # Using the first subnet ID + + private_service_connection { + name = var.mysql_private_endpoint_connection_name + private_connection_resource_id = azurerm_mysql_flexible_server.sqlserver.id + subresource_names = ["mysqlserver"] + is_manual_connection = false + } +} diff --git a/terraform/azure/modules/mysql-db/outputs.tf b/terraform/azure/modules/mysql-db/outputs.tf new file mode 100644 index 0000000..38b1a88 --- /dev/null +++ b/terraform/azure/modules/mysql-db/outputs.tf @@ -0,0 +1,9 @@ + + +output "mysql_server_fqdn" { + value = azurerm_mysql_flexible_server.sqlserver.fqdn +} + +output "mysql_database_id" { + value = azurerm_mysql_flexible_database.sqldb.id +} diff --git a/terraform/azure/modules/mysql-db/variables.tf b/terraform/azure/modules/mysql-db/variables.tf new file mode 100644 index 0000000..3e209e7 --- /dev/null +++ b/terraform/azure/modules/mysql-db/variables.tf @@ -0,0 +1,222 @@ + +# Network module variables +variable "vnet_name" { + description = "Name of the Azure Virtual Network" + default = "my-vnet" + type = string +} + +variable "vnet_address_space" { + description = "Address space for the Azure Virtual Network" + default = ["10.0.0.0/16"] + type = list(string) +} + +variable "location" { + description = "Azure region where the resources will be created" + default = "Central India" + type = string +} + +variable "resource_group_name" { + description = "Name of the Azure Resource Group" + default = "sample-resource-group" + type = string +} + +variable "subnet_names" { + description = "Names of the subnets" + default = ["testsubnet"] + type = list(string) +} + +variable "subnet_address_prefixes" { + description = "Address prefixes for the subnets" + default = ["10.0.1.0/24"] + type = list(string) +} + +variable "nsg_name" { + description = "Name of the Network Security Group" + default = "my-nsg" + type = string +} + +variable "inbound_rules" { + description = "A map of inbound security rules" + default = { + rule1 = { + name = "inbound_rule1" + priority = 100 + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "1.2.3.4" + destination_address_prefix = "10.0.1.0/24" + } + } + type = map(object({ + name = string + priority = number + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) +} + +variable "outbound_rules" { + description = "A map of outbound security rules" + default = { + rule1 = { + name = "outbound_rule1" + priority = 100 + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "10.0.1.0/24" + destination_address_prefix = "5.6.7.8" + } + } + type = map(object({ + name = string + priority = number + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) +} + +variable "subnet_service_endpoints" { + description = "Service endpoints for the subnet." + default = ["Microsoft.Storage"] + type = list(string) +} + +variable "subnet_delegation_name" { + description = "Name of the subnet delegation." + default = "test-delegation" + type = string +} + +variable "subnet_service_delegation_name" { + description = "Service delegation name for the subnet." + default = "Microsoft.DBforMySQL/flexibleServers" + type = string +} + +variable "subnet_service_delegation_actions" { + description = "Actions allowed for the subnet service delegation." + default = ["Microsoft.Network/virtualNetworks/subnets/join/action"] + type = list(string) +} + +# Mysql-db module variables +variable "private_dns_zone_name" { + description = "The name of the private DNS zone." + default = "test.mysql.database.azure.com" + type = string +} + +variable "private_dns_zone_link_name" { + description = "The name of the virtual network link to the private DNS zone." + default = "sampleVnetZone.com" + type = string +} + +variable "mysql_server_name" { + description = "The name of the MySQL flexible server." + default = "samplesqlserver02" + type = string +} + +variable "mysql_admin_login" { + description = "Administrator login for the MySQL server." + default = "mysqladmin" + type = string +} + +variable "mysql_admin_password" { + description = "Administrator password for the MySQL server." + default = "Password@123" + type = string +} + +variable "mysql_backup_retention_days" { + description = "Backup retention days for the MySQL server." + default = 7 + type = number +} + +variable "mysql_sku_name" { + description = "SKU name for the MySQL server." + default = "B_Standard_B1s" + type = string +} + +variable "mysql_zone" { + description = "Availability zone for the MySQL server." + default = "2" + type = string +} + +variable "mysql_database_name" { + description = "The name of the MySQL database." + default = "sample-mysql-db" + type = string +} + +variable "mysql_database_charset" { + description = "Character set for the MySQL database." + default = "utf8" + type = string +} + +variable "mysql_database_collation" { + description = "Collation for the MySQL database." + default = "utf8_general_ci" + type = string +} + +variable "mysql_firewall_rule_name" { + description = "Name of the firewall rule for the MySQL server." + default = "AllowMyIP" + type = string +} + +variable "mysql_firewall_start_ip" { + description = "Start IP address for the MySQL firewall rule." + default = "192.168.1.1" + type = string +} + +variable "mysql_firewall_end_ip" { + description = "End IP address for the MySQL firewall rule." + default = "192.168.1.10" + type = string +} + +variable "mysql_private_endpoint_name" { + description = "Name of the private endpoint for MySQL server." + default = "myPrivateEndpoint" + type = string +} + +variable "mysql_private_endpoint_connection_name" { + description = "Name of the private endpoint connection." + default = "myPrivateConnection" + type = string +} + +variable "environment" { + description = "Environment tag value" + default = "dev" + type = string +} diff --git a/terraform/azure/modules/vnet/vnet.tf b/terraform/azure/modules/vnet/vnet.tf index eb664b2..b510163 100644 --- a/terraform/azure/modules/vnet/vnet.tf +++ b/terraform/azure/modules/vnet/vnet.tf @@ -1,3 +1,4 @@ + #To create resource group resource "azurerm_resource_group" "resourcegroup" { name = var.resource_group_name @@ -10,15 +11,14 @@ resource "azurerm_resource_group" "resourcegroup" { } #To create virtual network -resource "azurerm_virtual_network" "Vnet" { +resource "azurerm_virtual_network" "vnet" { name = var.vnet_name address_space = var.address_space location = var.location - resource_group_name = azurerm_resource_group.resourcegroup.name - + resource_group_name = var.resource_group_name tags = { Name = var.vnet_name - Environment = "${local.environment}" + Environment = var.environment } } @@ -26,24 +26,30 @@ resource "azurerm_virtual_network" "Vnet" { resource "azurerm_subnet" "subnets" { count = length(var.subnet_names) name = var.subnet_names[count.index] - resource_group_name = azurerm_resource_group.resourcegroup.name - virtual_network_name = azurerm_virtual_network.Vnet.name + resource_group_name = var.resource_group_name + virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = [var.subnet_address_prefixes[count.index]] + + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.DBforMySQL/flexibleServers" + } + } } #To create network security group resource "azurerm_network_security_group" "default_nsg" { name = var.nsg_name location = var.location - resource_group_name = azurerm_resource_group.resourcegroup.name + resource_group_name = var.resource_group_name tags = { Name = var.nsg_name - Environment = "${local.environment}" + Environment = var.environment } } -#To add inbound rules resource "azurerm_network_security_rule" "inbound" { for_each = var.inbound_rules @@ -51,16 +57,15 @@ resource "azurerm_network_security_rule" "inbound" { priority = each.value.priority direction = "Inbound" access = each.value.access - protocol = each.value.protocol + protocol = title(each.value.protocol) # Ensure protocol is in title case 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 = azurerm_resource_group.resourcegroup.name + resource_group_name = var.resource_group_name network_security_group_name = azurerm_network_security_group.default_nsg.name } -#To add outbound rules resource "azurerm_network_security_rule" "outbound" { for_each = var.outbound_rules @@ -68,12 +73,12 @@ resource "azurerm_network_security_rule" "outbound" { priority = each.value.priority direction = "Outbound" access = each.value.access - protocol = each.value.protocol + protocol = title(each.value.protocol) # Ensure protocol is in title case 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 = azurerm_resource_group.resourcegroup.name + resource_group_name = var.resource_group_name network_security_group_name = azurerm_network_security_group.default_nsg.name } @@ -83,4 +88,3 @@ resource "azurerm_subnet_network_security_group_association" "nsg_association" { subnet_id = azurerm_subnet.subnets[count.index].id network_security_group_id = azurerm_network_security_group.default_nsg.id } -