diff --git a/modules/azure-localnet-gateway/.terraform-docs.yml b/modules/azure-localnet-gateway/.terraform-docs.yml new file mode 100644 index 000000000..3a69365ff --- /dev/null +++ b/modules/azure-localnet-gateway/.terraform-docs.yml @@ -0,0 +1,48 @@ +formatter: "markdown" + +version: "" + +header-from: docs/header.md +footer-from: docs/footer.md + +recursive: + enabled: false + path: modules + include-main: true + +sections: + hide: [] + show: [] + +content: "" + +output: + file: "README.md" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/modules/azure-localnet-gateway/README.md b/modules/azure-localnet-gateway/README.md new file mode 100644 index 000000000..f62def968 --- /dev/null +++ b/modules/azure-localnet-gateway/README.md @@ -0,0 +1,88 @@ + +# **Azure Local Network Gateway Terraform Module** + +## Overview + +This module provisions and manages Azure Local Network Gateways for Site-to-Site VPN connections using the [azurerm\_local\_network\_gateway](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway) resource. It is suitable for production, staging, and development environments, y puede integrarse en proyectos Terraform más grandes o usarse de forma independiente. + +## Key Features + +- **Multiple Gateway Support**: Create one or more Azure Local Network Gateways with flexible configuration. +- **Custom Address Spaces**: Define custom address spaces and gateway IPs for each local network. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "localnet_gateway" { + source = "./modules/azure-localnet-gateway" + localnet = [ + { + local_gateway_name = "example-gateway" + location = "westeurope" + resource_group_name = "example-rg" + local_gateway_ip = "203.0.113.1" + local_gateway_address_space = ["10.1.0.0/16"] + tags_from_rg = true + tags = { + environment = "dev" + } + } + ] +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.7.0 | +| [azurerm](#requirement\_azurerm) | 4.58.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.58.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_local_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/resources/local_network_gateway) | resource | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/resource_group) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [localnet](#input\_localnet) | List of local network gateway objects |
list(object({
local_gateway_name = string
location = string
resource_group_name = string
local_gateway_ip = string
local_gateway_address_space = list(string)
tags_from_rg = optional(bool)
tags = optional(map(string))
}))
| `[]` | no | + +## Outputs + +No outputs. + +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples): + +- [basic\_localnet](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/basic\_localnet) - Basic local network gateway example. +- [multiple\_address\_spaces](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/multiple\_address\_spaces) - Example with multiple address spaces. +- [with\_tags\_from\_rg](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/with\_tags\_from\_rg) - Example inheriting tags from the resource group. + +## Remote resources + +- **Azure Local Network Gateway**: [azurerm\_local\_network\_gateway documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). + \ No newline at end of file diff --git a/modules/azure-localnet-gateway/_examples/basic_localnet/example.tf b/modules/azure-localnet-gateway/_examples/basic_localnet/example.tf new file mode 100644 index 000000000..474c3870a --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/basic_localnet/example.tf @@ -0,0 +1,12 @@ +module "localnet_gateway" { + source = "../../" + localnet = [{ + local_gateway_name = "example-local-gw" + location = "westeurope" + resource_group_name = "example-rg" + local_gateway_ip = "203.0.113.1" + local_gateway_address_space = ["10.1.0.0/16"] + tags_from_rg = false + tags = { environment = "dev" } + }] +} diff --git a/modules/azure-localnet-gateway/_examples/basic_localnet/example.yaml b/modules/azure-localnet-gateway/_examples/basic_localnet/example.yaml new file mode 100644 index 000000000..6e973afeb --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/basic_localnet/example.yaml @@ -0,0 +1,10 @@ +localnet: + - local_gateway_name: example-local-gw + location: westeurope + resource_group_name: example-rg + local_gateway_ip: 203.0.113.1 + local_gateway_address_space: + - 10.1.0.0/16 + tags_from_rg: false + tags: + environment: dev diff --git a/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.tf b/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.tf new file mode 100644 index 000000000..d142b1358 --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.tf @@ -0,0 +1,12 @@ +module "localnet_gateway" { + source = "../../" + localnet = [{ + local_gateway_name = "multi-space-gw" + location = "westeurope" + resource_group_name = "example-rg" + local_gateway_ip = "203.0.113.2" + local_gateway_address_space = ["10.1.0.0/16", "10.2.0.0/16"] + tags_from_rg = false + tags = { environment = "test" } + }] +} diff --git a/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.yaml b/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.yaml new file mode 100644 index 000000000..f5575e07c --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/multiple_address_spaces/example.yaml @@ -0,0 +1,11 @@ +localnet: + - local_gateway_name: multi-space-gw + location: westeurope + resource_group_name: example-rg + local_gateway_ip: 203.0.113.2 + local_gateway_address_space: + - 10.1.0.0/16 + - 10.2.0.0/16 + tags_from_rg: false + tags: + environment: test diff --git a/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.tf b/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.tf new file mode 100644 index 000000000..a9a04d4df --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.tf @@ -0,0 +1,12 @@ +module "localnet_gateway" { + source = "../../" + localnet = [{ + local_gateway_name = "tagged-gw" + location = "westeurope" + resource_group_name = "example-rg" + local_gateway_ip = "203.0.113.3" + local_gateway_address_space = ["10.3.0.0/16"] + tags_from_rg = true + tags = { custom = "yes" } + }] +} diff --git a/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.yaml b/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.yaml new file mode 100644 index 000000000..5401add82 --- /dev/null +++ b/modules/azure-localnet-gateway/_examples/with_tags_from_rg/example.yaml @@ -0,0 +1,10 @@ +localnet: + - local_gateway_name: tagged-gw + location: westeurope + resource_group_name: example-rg + local_gateway_ip: 203.0.113.3 + local_gateway_address_space: + - 10.3.0.0/16 + tags_from_rg: true + tags: + custom: "yes" diff --git a/modules/azure-localnet-gateway/data.tf b/modules/azure-localnet-gateway/data.tf new file mode 100644 index 000000000..5a4e55297 --- /dev/null +++ b/modules/azure-localnet-gateway/data.tf @@ -0,0 +1,7 @@ +## DATA SOURCES SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network +data "azurerm_resource_group" "this" { + for_each = { for idx, s in var.localnet : idx => s } + name = each.value.resource_group_name +} diff --git a/modules/azure-localnet-gateway/docs/footer.md b/modules/azure-localnet-gateway/docs/footer.md new file mode 100644 index 000000000..b4e31edc1 --- /dev/null +++ b/modules/azure-localnet-gateway/docs/footer.md @@ -0,0 +1,16 @@ +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples): + +- [basic_localnet](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/basic_localnet) - Basic local network gateway example. +- [multiple_address_spaces](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/multiple_address_spaces) - Example with multiple address spaces. +- [with_tags_from_rg](https://github.com/prefapp/tfm/tree/main/modules/azure-localnet-gateway/_examples/with_tags_from_rg) - Example inheriting tags from the resource group. + +## Remote resources + +- **Azure Local Network Gateway**: [azurerm_local_network_gateway documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). diff --git a/modules/azure-localnet-gateway/docs/header.md b/modules/azure-localnet-gateway/docs/header.md new file mode 100644 index 000000000..0f2997113 --- /dev/null +++ b/modules/azure-localnet-gateway/docs/header.md @@ -0,0 +1,35 @@ +# **Azure Local Network Gateway Terraform Module** + +## Overview + +This module provisions and manages Azure Local Network Gateways for Site-to-Site VPN connections using the [azurerm_local_network_gateway](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway) resource. It is suitable for production, staging, and development environments, y puede integrarse en proyectos Terraform más grandes o usarse de forma independiente. + +## Key Features + +- **Multiple Gateway Support**: Create one or more Azure Local Network Gateways with flexible configuration. +- **Custom Address Spaces**: Define custom address spaces and gateway IPs for each local network. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "localnet_gateway" { + source = "./modules/azure-localnet-gateway" + localnet = [ + { + local_gateway_name = "example-gateway" + location = "westeurope" + resource_group_name = "example-rg" + local_gateway_ip = "203.0.113.1" + local_gateway_address_space = ["10.1.0.0/16"] + tags_from_rg = true + tags = { + environment = "dev" + } + } + ] +} +``` diff --git a/modules/azure-localnet-gateway/locals.tf b/modules/azure-localnet-gateway/locals.tf new file mode 100644 index 000000000..9d87d5e2f --- /dev/null +++ b/modules/azure-localnet-gateway/locals.tf @@ -0,0 +1,12 @@ +## LOCALS SECTION + +locals { + # Handle tags based on whether to use resource group tags or module-defined tags for each local network gateway (key = idx) + tags = { for idx, s in var.localnet : + idx => ( + coalesce(s.tags_from_rg, false) + ? merge(lookup(data.azurerm_resource_group.this, idx, null) != null ? data.azurerm_resource_group.this[idx].tags : {}, try(s.tags, {})) + : try(s.tags, {}) + ) + } +} diff --git a/modules/azure-localnet-gateway/main.tf b/modules/azure-localnet-gateway/main.tf new file mode 100644 index 000000000..5832ca34e --- /dev/null +++ b/modules/azure-localnet-gateway/main.tf @@ -0,0 +1,12 @@ +## LOCAL NETWORK GATEWAY SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway +resource "azurerm_local_network_gateway" "this" { + for_each = { for idx, s in var.localnet : idx => s } + name = each.value.local_gateway_name + location = each.value.location + resource_group_name = each.value.resource_group_name + gateway_address = each.value.local_gateway_ip + address_space = each.value.local_gateway_address_space + tags = local.tags[each.key] +} diff --git a/modules/azure-localnet-gateway/variables.tf b/modules/azure-localnet-gateway/variables.tf new file mode 100644 index 000000000..8bcf9ad16 --- /dev/null +++ b/modules/azure-localnet-gateway/variables.tf @@ -0,0 +1,15 @@ +## VARIABLES SECTION + +variable "localnet" { + description = "List of local network gateway objects" + type = list(object({ + local_gateway_name = string + location = string + resource_group_name = string + local_gateway_ip = string + local_gateway_address_space = list(string) + tags_from_rg = optional(bool) + tags = optional(map(string)) + })) + default = [] +} diff --git a/modules/azure-localnet-gateway/versions.tf b/modules/azure-localnet-gateway/versions.tf new file mode 100644 index 000000000..64c91805b --- /dev/null +++ b/modules/azure-localnet-gateway/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.7.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.58.0" + } + } +} diff --git a/modules/azure-vnet-gateway-connection/.terraform-docs.yml b/modules/azure-vnet-gateway-connection/.terraform-docs.yml new file mode 100644 index 000000000..3a69365ff --- /dev/null +++ b/modules/azure-vnet-gateway-connection/.terraform-docs.yml @@ -0,0 +1,48 @@ +formatter: "markdown" + +version: "" + +header-from: docs/header.md +footer-from: docs/footer.md + +recursive: + enabled: false + path: modules + include-main: true + +sections: + hide: [] + show: [] + +content: "" + +output: + file: "README.md" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/modules/azure-vnet-gateway-connection/README.md b/modules/azure-vnet-gateway-connection/README.md new file mode 100644 index 000000000..be7ab5d35 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/README.md @@ -0,0 +1,121 @@ + +# **Azure Virtual Network Gateway Connection Terraform Module** + +## Overview + +This module provisions and manages Azure Virtual Network Gateway Connections for Site-to-Site (S2S), VNet-to-VNet, and ExpressRoute VPNs. It supports advanced configuration, including custom IPsec/IKE policies, NAT rules, BGP, and shared key management via Azure Key Vault. + +It is suitable for production, staging, and development environments, and can be integrated into larger Terraform projects or used standalone. + +## Key Features + +- **S2S, VNet-to-VNet, and ExpressRoute Support**: Create connections between Azure VNets, on-premises networks, or ExpressRoute circuits. +- **Custom IPsec/IKE Policies**: Fine-grained control over encryption, integrity, and key exchange settings. +- **NAT Rule Integration**: Attach ingress and egress NAT rules to connections. +- **Key Vault Integration**: Securely manage shared keys using Azure Key Vault. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "vnet_gateway_connection" { + source = "./modules/azure-vnet-gateway-connection" + connection = [{ + name = "example-connection" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vnet-gw" + local_gateway_name = "example-local-gw" + local_gateway_resource_group_name = "example-local-rg" + keyvault_vault_name = "example-kv" + keyvault_vault_rg = "example-kv-rg" + keyvault_secret_name = "vpn-shared-key" + type = "IPsec" + connection_mode = "InitiatorOnly" + connection_protocol = "IKEv2" + enable_bgp = false + express_route_gateway_bypass = false + dpd_timeout_seconds = 30 + routing_weight = 0 + use_policy_based_traffic_selectors = false + ipsec_policy = { + dh_group = "DHGroup14" + ike_encryption = "AES256" + ike_integrity = "SHA256" + ipsec_encryption = "AES256" + ipsec_integrity = "SHA256" + pfs_group = "PFS2" + sa_datasize = 0 + sa_lifetime = 28800 + } + egress_nat_rule_ids = [] + ingress_nat_rule_ids = [] + local_azure_ip_address_enabled = false + tags_from_rg = true + tags = { + environment = "dev" + application = "example-app" + } + }] +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.7.0 | +| [azurerm](#requirement\_azurerm) | 4.58.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.58.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_virtual_network_gateway_connection.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/resources/virtual_network_gateway_connection) | resource | +| [azurerm_key_vault.s2s](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/key_vault) | data source | +| [azurerm_key_vault_secret.s2s](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/key_vault_secret) | data source | +| [azurerm_local_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/local_network_gateway) | data source | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/resource_group) | data source | +| [azurerm_virtual_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/virtual_network_gateway) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [connection](#input\_connection) | List of Site-to-Site VPN connection objects |
list(object({
name = string
location = string
resource_group_name = string
local_gateway_name = string
local_gateway_resource_group_name = string
type = string
gateway_name = string
shared_key = optional(string)
keyvault_secret_name = optional(string)
keyvault_vault_name = optional(string)
keyvault_vault_rg = optional(string)
virtual_network_gateway_id = optional(string)
local_network_gateway_id = optional(string)
connection_protocol = optional(string)
routing_weight = optional(number)
authorization_key = optional(string)
express_route_circuit_id = optional(string)
peer_virtual_network_gateway_id = optional(string)
use_policy_based_traffic_selectors = optional(bool)
express_route_gateway_bypass = optional(bool)
dpd_timeout_seconds = optional(number)
connection_mode = optional(string)
tags_from_rg = optional(bool)
egress_nat_rule_ids = optional(list(string))
ingress_nat_rule_ids = optional(list(string))
local_azure_ip_address_enabled = optional(bool)
tags = optional(map(string))
ipsec_policy = optional(object({
dh_group = string
ike_encryption = string
ike_integrity = string
ipsec_encryption = string
ipsec_integrity = string
pfs_group = string
sa_lifetime = number
sa_datasize = number
}))
}))
| `[]` | no | + +## Outputs + +No outputs. + +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples): + +- [s2s\_basic](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/s2s\_basic) - Basic Site-to-Site connection example. +- [with\_nat\_rules](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/with\_nat\_rules) - Example with ingress/egress NAT rules. +- [with\_keyvault](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/with\_keyvault) - Example using Azure Key Vault for shared key management. + +## Remote resources + +- **Azure Virtual Network Gateway Connection**: [azurerm\_virtual\_network\_gateway\_connection documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway_connection) +- **Azure Key Vault Secret**: [azurerm\_key\_vault\_secret documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). + \ No newline at end of file diff --git a/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.tf b/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.tf new file mode 100644 index 000000000..92c2f1f36 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.tf @@ -0,0 +1,40 @@ +module "vnet_gateway_connection" { + source = "../../" + connection = [{ + name = "example-connection" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vnet-gw" + local_gateway_name = "example-local-gw" + local_gateway_resource_group_name = "example-local-rg" + keyvault_vault_name = "example-kv" + keyvault_vault_rg = "example-kv-rg" + keyvault_secret_name = "vpn-shared-key" + type = "IPsec" + connection_mode = "InitiatorOnly" + connection_protocol = "IKEv2" + enable_bgp = false + express_route_gateway_bypass = false + dpd_timeout_seconds = 30 + routing_weight = 0 + use_policy_based_traffic_selectors = false + ipsec_policy = { + dh_group = "DHGroup14" + ike_encryption = "AES256" + ike_integrity = "SHA256" + ipsec_encryption = "AES256" + ipsec_integrity = "SHA256" + pfs_group = "PFS2" + sa_datasize = 0 + sa_lifetime = 28800 + } + egress_nat_rule_ids = [] + ingress_nat_rule_ids = [] + local_azure_ip_address_enabled = false + tags_from_rg = true + tags = { + environment = "dev" + application = "example-app" + } + }] +} diff --git a/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.yaml b/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.yaml new file mode 100644 index 000000000..a52958dad --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/s2s_basic/example.yaml @@ -0,0 +1,34 @@ +connection: + - name: example-connection + location: westeurope + resource_group_name: example-rg + gateway_name: example-vnet-gw + local_gateway_name: example-local-gw + local_gateway_resource_group_name: example-local-rg + keyvault_vault_name: example-kv + keyvault_vault_rg: example-kv-rg + keyvault_secret_name: vpn-shared-key + type: IPsec + connection_mode: InitiatorOnly + connection_protocol: IKEv2 + enable_bgp: false + express_route_gateway_bypass: false + dpd_timeout_seconds: 30 + routing_weight: 0 + use_policy_based_traffic_selectors: false + ipsec_policy: + dh_group: DHGroup14 + ike_encryption: AES256 + ike_integrity: SHA256 + ipsec_encryption: AES256 + ipsec_integrity: SHA256 + pfs_group: PFS2 + sa_datasize: 0 + sa_lifetime: 28800 + egress_nat_rule_ids: [] + ingress_nat_rule_ids: [] + local_azure_ip_address_enabled: false + tags_from_rg: true + tags: + environment: dev + application: example-app diff --git a/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.tf b/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.tf new file mode 100644 index 000000000..bf739db15 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.tf @@ -0,0 +1,40 @@ +module "vnet_gateway_connection" { + source = "../../" + connection = [{ + name = "keyvault-connection" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vnet-gw" + local_gateway_name = "example-local-gw" + local_gateway_resource_group_name = "example-local-rg" + keyvault_vault_name = "example-kv" + keyvault_vault_rg = "example-kv-rg" + keyvault_secret_name = "vpn-shared-key" + type = "IPsec" + connection_mode = "InitiatorOnly" + connection_protocol = "IKEv2" + enable_bgp = false + express_route_gateway_bypass = false + dpd_timeout_seconds = 30 + routing_weight = 0 + use_policy_based_traffic_selectors = false + ipsec_policy = { + dh_group = "DHGroup14" + ike_encryption = "AES256" + ike_integrity = "SHA256" + ipsec_encryption = "AES256" + ipsec_integrity = "SHA256" + pfs_group = "PFS2" + sa_datasize = 0 + sa_lifetime = 28800 + } + egress_nat_rule_ids = [] + ingress_nat_rule_ids = [] + local_azure_ip_address_enabled = false + tags_from_rg = true + tags = { + environment = "prod" + application = "keyvault-app" + } + }] +} diff --git a/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.yaml b/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.yaml new file mode 100644 index 000000000..abe5f4694 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/with_keyvault_shared_key/example.yaml @@ -0,0 +1,34 @@ +connection: + - name: keyvault-connection + location: westeurope + resource_group_name: example-rg + gateway_name: example-vnet-gw + local_gateway_name: example-local-gw + local_gateway_resource_group_name: example-local-rg + keyvault_vault_name: example-kv + keyvault_vault_rg: example-kv-rg + keyvault_secret_name: vpn-shared-key + type: IPsec + connection_mode: InitiatorOnly + connection_protocol: IKEv2 + enable_bgp: false + express_route_gateway_bypass: false + dpd_timeout_seconds: 30 + routing_weight: 0 + use_policy_based_traffic_selectors: false + ipsec_policy: + dh_group: DHGroup14 + ike_encryption: AES256 + ike_integrity: SHA256 + ipsec_encryption: AES256 + ipsec_integrity: SHA256 + pfs_group: PFS2 + sa_datasize: 0 + sa_lifetime: 28800 + egress_nat_rule_ids: [] + ingress_nat_rule_ids: [] + local_azure_ip_address_enabled: false + tags_from_rg: true + tags: + environment: prod + application: keyvault-app diff --git a/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.tf b/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.tf new file mode 100644 index 000000000..003d456d7 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.tf @@ -0,0 +1,40 @@ +module "vnet_gateway_connection" { + source = "../../" + connection = [{ + name = "nat-connection" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vnet-gw" + local_gateway_name = "example-local-gw" + local_gateway_resource_group_name = "example-local-rg" + keyvault_vault_name = "example-kv" + keyvault_vault_rg = "example-kv-rg" + keyvault_secret_name = "vpn-shared-key" + type = "IPsec" + connection_mode = "InitiatorOnly" + connection_protocol = "IKEv2" + enable_bgp = false + express_route_gateway_bypass = false + dpd_timeout_seconds = 30 + routing_weight = 0 + use_policy_based_traffic_selectors = false + ipsec_policy = { + dh_group = "DHGroup14" + ike_encryption = "AES256" + ike_integrity = "SHA256" + ipsec_encryption = "AES256" + ipsec_integrity = "SHA256" + pfs_group = "PFS2" + sa_datasize = 0 + sa_lifetime = 28800 + } + egress_nat_rule_ids = ["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/virtualNetworkGateways/example-vnet-gw/natRules/egress_nat"] + ingress_nat_rule_ids = ["/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/virtualNetworkGateways/example-vnet-gw/natRules/ingress_nat"] + local_azure_ip_address_enabled = false + tags_from_rg = false + tags = { + environment = "test" + application = "nat-app" + } + }] +} diff --git a/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.yaml b/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.yaml new file mode 100644 index 000000000..7b372f0dd --- /dev/null +++ b/modules/azure-vnet-gateway-connection/_examples/with_nat_rules/example.yaml @@ -0,0 +1,36 @@ +connection: + - name: nat-connection + location: westeurope + resource_group_name: example-rg + gateway_name: example-vnet-gw + local_gateway_name: example-local-gw + local_gateway_resource_group_name: example-local-rg + keyvault_vault_name: example-kv + keyvault_vault_rg: example-kv-rg + keyvault_secret_name: vpn-shared-key + type: IPsec + connection_mode: InitiatorOnly + connection_protocol: IKEv2 + enable_bgp: false + express_route_gateway_bypass: false + dpd_timeout_seconds: 30 + routing_weight: 0 + use_policy_based_traffic_selectors: false + ipsec_policy: + dh_group: DHGroup14 + ike_encryption: AES256 + ike_integrity: SHA256 + ipsec_encryption: AES256 + ipsec_integrity: SHA256 + pfs_group: PFS2 + sa_datasize: 0 + sa_lifetime: 28800 + egress_nat_rule_ids: + - /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/virtualNetworkGateways/example-vnet-gw/natRules/egress_nat + ingress_nat_rule_ids: + - /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/virtualNetworkGateways/example-vnet-gw/natRules/ingress_nat + local_azure_ip_address_enabled: false + tags_from_rg: false + tags: + environment: test + application: nat-app diff --git a/modules/azure-vnet-gateway-connection/data.tf b/modules/azure-vnet-gateway-connection/data.tf new file mode 100644 index 000000000..cc555cd97 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/data.tf @@ -0,0 +1,35 @@ +## DATA SOURCES SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group +data "azurerm_local_network_gateway" "this" { + for_each = { for idx, s in var.connection : idx => s } + name = each.value.local_gateway_name + resource_group_name = each.value.local_gateway_resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network_gateway +data "azurerm_resource_group" "this" { + for_each = { for idx, s in var.connection : idx => s } + name = each.value.resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network_gateway +data "azurerm_virtual_network_gateway" "this" { + for_each = { for idx, s in var.connection : idx => s } + name = each.value.gateway_name + resource_group_name = each.value.resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret +data "azurerm_key_vault_secret" "s2s" { + for_each = { for idx, s in var.connection : idx => s if try(s.keyvault_secret_name, null) != null && try(s.keyvault_vault_name, null) != null && try(s.keyvault_vault_rg, null) != null } + name = each.value.keyvault_secret_name + key_vault_id = data.azurerm_key_vault.s2s[each.key].id +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault +data "azurerm_key_vault" "s2s" { + for_each = { for idx, s in var.connection : idx => s if try(s.keyvault_vault_name, null) != null && try(s.keyvault_vault_rg, null) != null } + name = each.value.keyvault_vault_name + resource_group_name = each.value.keyvault_vault_rg +} diff --git a/modules/azure-vnet-gateway-connection/docs/footer.md b/modules/azure-vnet-gateway-connection/docs/footer.md new file mode 100644 index 000000000..ae03a3fd1 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/docs/footer.md @@ -0,0 +1,17 @@ +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples): + +- [s2s_basic](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/s2s_basic) - Basic Site-to-Site connection example. +- [with_nat_rules](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/with_nat_rules) - Example with ingress/egress NAT rules. +- [with_keyvault](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway-connection/_examples/with_keyvault) - Example using Azure Key Vault for shared key management. + +## Remote resources + +- **Azure Virtual Network Gateway Connection**: [azurerm_virtual_network_gateway_connection documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway_connection) +- **Azure Key Vault Secret**: [azurerm_key_vault_secret documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). diff --git a/modules/azure-vnet-gateway-connection/docs/header.md b/modules/azure-vnet-gateway-connection/docs/header.md new file mode 100644 index 000000000..49162221f --- /dev/null +++ b/modules/azure-vnet-gateway-connection/docs/header.md @@ -0,0 +1,63 @@ +# **Azure Virtual Network Gateway Connection Terraform Module** + +## Overview + +This module provisions and manages Azure Virtual Network Gateway Connections for Site-to-Site (S2S), VNet-to-VNet, and ExpressRoute VPNs. It supports advanced configuration, including custom IPsec/IKE policies, NAT rules, BGP, and shared key management via Azure Key Vault. + +It is suitable for production, staging, and development environments, and can be integrated into larger Terraform projects or used standalone. + +## Key Features + +- **S2S, VNet-to-VNet, and ExpressRoute Support**: Create connections between Azure VNets, on-premises networks, or ExpressRoute circuits. +- **Custom IPsec/IKE Policies**: Fine-grained control over encryption, integrity, and key exchange settings. +- **NAT Rule Integration**: Attach ingress and egress NAT rules to connections. +- **Key Vault Integration**: Securely manage shared keys using Azure Key Vault. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "vnet_gateway_connection" { + source = "./modules/azure-vnet-gateway-connection" + connection = [{ + name = "example-connection" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vnet-gw" + local_gateway_name = "example-local-gw" + local_gateway_resource_group_name = "example-local-rg" + keyvault_vault_name = "example-kv" + keyvault_vault_rg = "example-kv-rg" + keyvault_secret_name = "vpn-shared-key" + type = "IPsec" + connection_mode = "InitiatorOnly" + connection_protocol = "IKEv2" + enable_bgp = false + express_route_gateway_bypass = false + dpd_timeout_seconds = 30 + routing_weight = 0 + use_policy_based_traffic_selectors = false + ipsec_policy = { + dh_group = "DHGroup14" + ike_encryption = "AES256" + ike_integrity = "SHA256" + ipsec_encryption = "AES256" + ipsec_integrity = "SHA256" + pfs_group = "PFS2" + sa_datasize = 0 + sa_lifetime = 28800 + } + egress_nat_rule_ids = [] + ingress_nat_rule_ids = [] + local_azure_ip_address_enabled = false + tags_from_rg = true + tags = { + environment = "dev" + application = "example-app" + } + }] +} +``` diff --git a/modules/azure-vnet-gateway-connection/locals.tf b/modules/azure-vnet-gateway-connection/locals.tf new file mode 100644 index 000000000..4540baa34 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/locals.tf @@ -0,0 +1,12 @@ +## LOCALS SECTION + +locals { + # Handle tags based on whether to use resource group tags or module-defined tags for each connection (key = idx) + tags = { for idx, s in var.connection : + idx => ( + coalesce(s.tags_from_rg, false) + ? merge(try(data.azurerm_resource_group.this[idx].tags, {}), try(s.tags, {})) + : try(s.tags, {}) + ) + } +} diff --git a/modules/azure-vnet-gateway-connection/main.tf b/modules/azure-vnet-gateway-connection/main.tf new file mode 100644 index 000000000..628e22256 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/main.tf @@ -0,0 +1,51 @@ +## VPN CONNECTION SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway_connection +resource "azurerm_virtual_network_gateway_connection" "this" { + for_each = { for idx, s in var.connection : idx => s } + name = each.value.name + location = each.value.location + resource_group_name = each.value.resource_group_name + egress_nat_rule_ids = try(each.value.egress_nat_rule_ids, null) + ingress_nat_rule_ids = try(each.value.ingress_nat_rule_ids, null) + local_azure_ip_address_enabled = try(each.value.local_azure_ip_address_enabled, null) + tags = local.tags[each.key] + type = each.value.type + virtual_network_gateway_id = ( + try(each.value.virtual_network_gateway_id, null) != null ? each.value.virtual_network_gateway_id : data.azurerm_virtual_network_gateway.this[each.key].id + ) + local_network_gateway_id = ( + try(each.value.local_network_gateway_id, null) != null ? each.value.local_network_gateway_id : data.azurerm_local_network_gateway.this[each.key].id + ) + shared_key = ( + try(each.value.shared_key, null) != null ? each.value.shared_key : ( + try(data.azurerm_key_vault_secret.s2s[each.key].value, null) != null ? data.azurerm_key_vault_secret.s2s[each.key].value : null + ) + ) + enable_bgp = try(each.value.enable_bgp, null) + connection_protocol = try(each.value.connection_protocol, null) + routing_weight = try(each.value.routing_weight, null) + authorization_key = try(each.value.authorization_key, null) + express_route_circuit_id = try(each.value.express_route_circuit_id, null) + peer_virtual_network_gateway_id = try(each.value.peer_virtual_network_gateway_id, null) + use_policy_based_traffic_selectors = try(each.value.use_policy_based_traffic_selectors, null) + express_route_gateway_bypass = try(each.value.express_route_gateway_bypass, null) + dpd_timeout_seconds = try(each.value.dpd_timeout_seconds, null) + connection_mode = try(each.value.connection_mode, null) + dynamic "ipsec_policy" { + for_each = try(each.value.ipsec_policy != null, false) ? [each.value.ipsec_policy] : [] + content { + dh_group = ipsec_policy.value.dh_group + ike_encryption = ipsec_policy.value.ike_encryption + ike_integrity = ipsec_policy.value.ike_integrity + ipsec_encryption = ipsec_policy.value.ipsec_encryption + ipsec_integrity = ipsec_policy.value.ipsec_integrity + pfs_group = ipsec_policy.value.pfs_group + sa_lifetime = ipsec_policy.value.sa_lifetime + sa_datasize = ipsec_policy.value.sa_datasize + } + } + lifecycle { + ignore_changes = [shared_key] + } +} diff --git a/modules/azure-vnet-gateway-connection/variables.tf b/modules/azure-vnet-gateway-connection/variables.tf new file mode 100644 index 000000000..aae452cc0 --- /dev/null +++ b/modules/azure-vnet-gateway-connection/variables.tf @@ -0,0 +1,47 @@ +## VARIABLES SECTION + +variable "connection" { + description = "List of Site-to-Site VPN connection objects" + type = list(object({ + name = string + location = string + resource_group_name = string + local_gateway_name = string + local_gateway_resource_group_name = string + type = string + gateway_name = string + shared_key = optional(string) + keyvault_secret_name = optional(string) + keyvault_vault_name = optional(string) + keyvault_vault_rg = optional(string) + virtual_network_gateway_id = optional(string) + local_network_gateway_id = optional(string) + connection_protocol = optional(string) + routing_weight = optional(number) + authorization_key = optional(string) + express_route_circuit_id = optional(string) + peer_virtual_network_gateway_id = optional(string) + use_policy_based_traffic_selectors = optional(bool) + express_route_gateway_bypass = optional(bool) + dpd_timeout_seconds = optional(number) + connection_mode = optional(string) + tags_from_rg = optional(bool) + egress_nat_rule_ids = optional(list(string)) + ingress_nat_rule_ids = optional(list(string)) + local_azure_ip_address_enabled = optional(bool) + tags = optional(map(string)) + ipsec_policy = optional(object({ + dh_group = string + ike_encryption = string + ike_integrity = string + ipsec_encryption = string + ipsec_integrity = string + pfs_group = string + sa_lifetime = number + sa_datasize = number + })) + })) + default = [] +} + + diff --git a/modules/azure-vnet-gateway-connection/versions.tf b/modules/azure-vnet-gateway-connection/versions.tf new file mode 100644 index 000000000..64c91805b --- /dev/null +++ b/modules/azure-vnet-gateway-connection/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.7.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.58.0" + } + } +} diff --git a/modules/azure-vnet-gateway/.terraform-docs.yml b/modules/azure-vnet-gateway/.terraform-docs.yml new file mode 100644 index 000000000..3a69365ff --- /dev/null +++ b/modules/azure-vnet-gateway/.terraform-docs.yml @@ -0,0 +1,48 @@ +formatter: "markdown" + +version: "" + +header-from: docs/header.md +footer-from: docs/footer.md + +recursive: + enabled: false + path: modules + include-main: true + +sections: + hide: [] + show: [] + +content: "" + +output: + file: "README.md" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/modules/azure-vnet-gateway/README.md b/modules/azure-vnet-gateway/README.md new file mode 100644 index 000000000..a0f4126be --- /dev/null +++ b/modules/azure-vnet-gateway/README.md @@ -0,0 +1,99 @@ + +# **Azure Virtual Network Gateway Terraform Module** + +## Overview + +This module provisions and manages an Azure Virtual Network Gateway for VPN connectivity, supporting both Route-based and Policy-based configurations. It is suitable for production, staging, and development environments, and can be integrated into larger Terraform projects or used standalone. + +## Key Features + +- **Flexible Gateway Deployment**: Supports Route-based and Policy-based VPN gateways, active-active mode, and multiple SKUs. +- **Custom IP Configuration**: Allows custom public IP, subnet, and private IP allocation. +- **Advanced VPN Client Support**: Configure VPN client address spaces, protocols, and AAD integration for P2S. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "vnet_gateway" { + source = "./modules/azure-vnet-gateway" + vpn = { + vnet_name = "my-vnet" + gateway_subnet_name = "GatewaySubnet" + location = "westeurope" + resource_group_name = "my-rg" + gateway_name = "my-vpn-gw" + ip_name = "my-vpn-ip" + public_ip_name = "my-vpn-public-ip" + ip_allocation_method = "Dynamic" + type = "Vpn" + vpn_type = "RouteBased" + active_active = false + enable_bgp = false + sku = "VpnGw1" + # ...other optional fields... + } +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.7.0 | +| [azurerm](#requirement\_azurerm) | 4.58.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.58.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_virtual_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/resources/virtual_network_gateway) | resource | +| [azurerm_virtual_network_gateway_nat_rule.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/resources/virtual_network_gateway_nat_rule) | resource | +| [azurerm_public_ip.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/public_ip) | data source | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/resource_group) | data source | +| [azurerm_subnet.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/subnet) | data source | +| [azurerm_virtual_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.58.0/docs/data-sources/virtual_network_gateway) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [nat\_rules](#input\_nat\_rules) | List of NAT rules for the VPN gateway |
list(object({
name = string
mode = string
type = string
ip_configuration_id = optional(string)
external_mapping_address_space = string
internal_mapping_address_space = string
}))
| `[]` | no | +| [tags](#input\_tags) | Tags to apply to resources | `map(string)` | `{}` | no | +| [tags\_from\_rg](#input\_tags\_from\_rg) | Use resource group tags as base for module tags | `bool` | `false` | no | +| [vpn](#input\_vpn) | VPN Gateway configuration object (includes P2S config) |
object({
vnet_name = string
gateway_subnet_name = string
location = string
resource_group_name = string
gateway_name = string
ip_name = string
public_ip_name = string
public_ip_id = optional(string)
ip_allocation_method = string
gateway_subnet_id = optional(string)
type = string
vpn_type = string
active_active = bool
enable_bgp = bool
sku = string
generation = optional(string)
default_local_network_gateway_id = optional(string)
edge_zone = optional(string)
private_ip_address_enabled = optional(bool)
bgp_route_translation_for_nat_enabled = optional(bool)
dns_forwarding_enabled = optional(bool)
ip_sec_replay_protection_enabled = optional(bool)
remote_vnet_traffic_enabled = optional(bool)
virtual_wan_traffic_enabled = optional(bool)

# ip_configuration block fields
private_ip_address_allocation = optional(string)

# custom_route block
custom_route_address_prefixes = optional(list(string), [])

# vpn_client_configuration block
vpn_client_address_space = optional(list(string), [])
vpn_client_protocols = optional(list(string), [])
vpn_client_aad_tenant = optional(string)
vpn_client_aad_audience = optional(string)
vpn_client_aad_issuer = optional(string)
root_certificates = optional(list(object({
name = string
public_cert = optional(string)
public_cert_data = optional(string)
})), [])
revoked_certificates = optional(list(object({
name = string
thumbprint = string
})), [])
vpn_auth_types = optional(list(string), [])

# bgp_settings block
bgp_settings = optional(object({
asn = optional(number)
peer_weight = optional(number)
peering_addresses = optional(list(object({
ip_configuration_name = optional(string)
apipa_addresses = optional(list(string))
})), [])
}))

# timeouts block
timeouts = optional(object({
create = optional(string)
read = optional(string)
update = optional(string)
delete = optional(string)
}))
})
| n/a | yes | + +## Outputs + +No outputs. + +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples): + +- [basic\_route\_based](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/basic\_route\_based) - Basic RouteBased gateway example. +- [active\_active\_bgp](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/active\_active\_bgp) - Active-Active gateway with BGP enabled. +- [vpn\_client\_aad](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/vpn\_client\_aad) - Gateway with VPN Client and Azure AD authentication. + +## Remote resources + +- **Azure Virtual Network Gateway**: [azurerm\_virtual\_network\_gateway documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). + \ No newline at end of file diff --git a/modules/azure-vnet-gateway/_examples/active_active_bgp/example.tf b/modules/azure-vnet-gateway/_examples/active_active_bgp/example.tf new file mode 100644 index 000000000..35f82a9bc --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/active_active_bgp/example.tf @@ -0,0 +1,20 @@ +module "vnet_gateway" { + source = "../../" + vpn = { + vnet_name = "example-vnet" + gateway_subnet_name = "GatewaySubnet" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vpn-gw" + ip_name = "example-vpn-ip" + public_ip_name = "example-vpn-public-ip" + ip_allocation_method = "Dynamic" + type = "Vpn" + vpn_type = "RouteBased" + active_active = true + enable_bgp = true + sku = "VpnGw2" + bgp_route_translation_for_nat_enabled = true + tags = { environment = "prod" } + } +} diff --git a/modules/azure-vnet-gateway/_examples/active_active_bgp/example.yaml b/modules/azure-vnet-gateway/_examples/active_active_bgp/example.yaml new file mode 100644 index 000000000..c085af599 --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/active_active_bgp/example.yaml @@ -0,0 +1,17 @@ +vpn: + vnet_name: example-vnet + gateway_subnet_name: GatewaySubnet + location: westeurope + resource_group_name: example-rg + gateway_name: example-vpn-gw + ip_name: example-vpn-ip + public_ip_name: example-vpn-public-ip + ip_allocation_method: Dynamic + type: Vpn + vpn_type: RouteBased + active_active: true + enable_bgp: true + sku: VpnGw2 + bgp_route_translation_for_nat_enabled: true + tags: + environment: prod diff --git a/modules/azure-vnet-gateway/_examples/basic_route_based/example.tf b/modules/azure-vnet-gateway/_examples/basic_route_based/example.tf new file mode 100644 index 000000000..c12d46377 --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/basic_route_based/example.tf @@ -0,0 +1,19 @@ +module "vnet_gateway" { + source = "../../" + vpn = { + vnet_name = "example-vnet" + gateway_subnet_name = "GatewaySubnet" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vpn-gw" + ip_name = "example-vpn-ip" + public_ip_name = "example-vpn-public-ip" + ip_allocation_method = "Dynamic" + type = "Vpn" + vpn_type = "RouteBased" + active_active = false + enable_bgp = false + sku = "VpnGw1" + tags = { environment = "dev" } + } +} diff --git a/modules/azure-vnet-gateway/_examples/basic_route_based/example.yaml b/modules/azure-vnet-gateway/_examples/basic_route_based/example.yaml new file mode 100644 index 000000000..f8b8eead6 --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/basic_route_based/example.yaml @@ -0,0 +1,16 @@ +vpn: + vnet_name: example-vnet + gateway_subnet_name: GatewaySubnet + location: westeurope + resource_group_name: example-rg + gateway_name: example-vpn-gw + ip_name: example-vpn-ip + public_ip_name: example-vpn-public-ip + ip_allocation_method: Dynamic + type: Vpn + vpn_type: RouteBased + active_active: false + enable_bgp: false + sku: VpnGw1 + tags: + environment: dev diff --git a/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.tf b/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.tf new file mode 100644 index 000000000..2e8e1feab --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.tf @@ -0,0 +1,22 @@ +module "vnet_gateway" { + source = "../../" + vpn = { + vnet_name = "example-vnet" + gateway_subnet_name = "GatewaySubnet" + location = "westeurope" + resource_group_name = "example-rg" + gateway_name = "example-vpn-gw" + ip_name = "example-vpn-ip" + public_ip_name = "example-vpn-public-ip" + ip_allocation_method = "Dynamic" + type = "Vpn" + vpn_type = "RouteBased" + active_active = false + enable_bgp = false + sku = "VpnGw1" + vpn_client_address_space = ["10.10.0.0/24"] + vpn_client_protocols = ["IkeV2", "OpenVPN"] + vpn_client_aad_tenant = "https://login.microsoftonline.com/" + tags = { environment = "test" } + } +} diff --git a/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.yaml b/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.yaml new file mode 100644 index 000000000..e66fab766 --- /dev/null +++ b/modules/azure-vnet-gateway/_examples/vpn_client_aad/example.yaml @@ -0,0 +1,22 @@ +vpn: + vnet_name: example-vnet + gateway_subnet_name: GatewaySubnet + location: westeurope + resource_group_name: example-rg + gateway_name: example-vpn-gw + ip_name: example-vpn-ip + public_ip_name: example-vpn-public-ip + ip_allocation_method: Dynamic + type: Vpn + vpn_type: RouteBased + active_active: false + enable_bgp: false + sku: VpnGw1 + vpn_client_address_space: + - 10.10.0.0/24 + vpn_client_protocols: + - IkeV2 + - OpenVPN + vpn_client_aad_tenant: https://login.microsoftonline.com/ + tags: + environment: test diff --git a/modules/azure-vnet-gateway/data.tf b/modules/azure-vnet-gateway/data.tf new file mode 100644 index 000000000..be11ff191 --- /dev/null +++ b/modules/azure-vnet-gateway/data.tf @@ -0,0 +1,25 @@ +## DATA SOURCES SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group +data "azurerm_resource_group" "this" { + name = var.vpn.resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet +data "azurerm_subnet" "this" { + name = var.vpn.gateway_subnet_name + virtual_network_name = var.vpn.vnet_name + resource_group_name = var.vpn.resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/public_ip +data "azurerm_public_ip" "this" { + name = var.vpn.public_ip_name + resource_group_name = var.vpn.resource_group_name +} + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network_gateway +data "azurerm_virtual_network_gateway" "this" { + name = var.vpn.gateway_name + resource_group_name = var.vpn.resource_group_name +} diff --git a/modules/azure-vnet-gateway/docs/footer.md b/modules/azure-vnet-gateway/docs/footer.md new file mode 100644 index 000000000..f550568b2 --- /dev/null +++ b/modules/azure-vnet-gateway/docs/footer.md @@ -0,0 +1,16 @@ +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples): + +- [basic_route_based](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/basic_route_based) - Basic RouteBased gateway example. +- [active_active_bgp](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/active_active_bgp) - Active-Active gateway with BGP enabled. +- [vpn_client_aad](https://github.com/prefapp/tfm/tree/main/modules/azure-vnet-gateway/_examples/vpn_client_aad) - Gateway with VPN Client and Azure AD authentication. + +## Remote resources + +- **Azure Virtual Network Gateway**: [azurerm_virtual_network_gateway documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway) +- **Terraform Azure Provider**: [Terraform Provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +## Support + +For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues). diff --git a/modules/azure-vnet-gateway/docs/header.md b/modules/azure-vnet-gateway/docs/header.md new file mode 100644 index 000000000..24e2ba402 --- /dev/null +++ b/modules/azure-vnet-gateway/docs/header.md @@ -0,0 +1,39 @@ +# **Azure Virtual Network Gateway Terraform Module** + +## Overview + +This module provisions and manages an Azure Virtual Network Gateway for VPN connectivity, supporting both Route-based and Policy-based configurations. It is suitable for production, staging, and development environments, and can be integrated into larger Terraform projects or used standalone. + +## Key Features + +- **Flexible Gateway Deployment**: Supports Route-based and Policy-based VPN gateways, active-active mode, and multiple SKUs. +- **Custom IP Configuration**: Allows custom public IP, subnet, and private IP allocation. +- **Advanced VPN Client Support**: Configure VPN client address spaces, protocols, and AAD integration for P2S. +- **Tag Inheritance and Customization**: Inherit tags from the resource group or specify custom tags for all resources. +- **Extensible and Modular**: Designed for easy extension and integration with other Azure network modules. + +## Basic Usage + +See the main README and the `_examples/` directory for usage examples. + +```hcl +module "vnet_gateway" { + source = "./modules/azure-vnet-gateway" + vpn = { + vnet_name = "my-vnet" + gateway_subnet_name = "GatewaySubnet" + location = "westeurope" + resource_group_name = "my-rg" + gateway_name = "my-vpn-gw" + ip_name = "my-vpn-ip" + public_ip_name = "my-vpn-public-ip" + ip_allocation_method = "Dynamic" + type = "Vpn" + vpn_type = "RouteBased" + active_active = false + enable_bgp = false + sku = "VpnGw1" + # ...other optional fields... + } +} +``` diff --git a/modules/azure-vnet-gateway/locals.tf b/modules/azure-vnet-gateway/locals.tf new file mode 100644 index 000000000..87520c493 --- /dev/null +++ b/modules/azure-vnet-gateway/locals.tf @@ -0,0 +1,6 @@ +## LOCALS SECTION + +locals { + # Handle tags based on whether to use resource group tags or module-defined tags + tags = var.tags_from_rg ? merge(data.azurerm_resource_group.this.tags, var.tags) : var.tags +} diff --git a/modules/azure-vnet-gateway/main.tf b/modules/azure-vnet-gateway/main.tf new file mode 100644 index 000000000..c59cac56b --- /dev/null +++ b/modules/azure-vnet-gateway/main.tf @@ -0,0 +1,88 @@ +## VPN SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway +resource "azurerm_virtual_network_gateway" "this" { + name = var.vpn.gateway_name + location = var.vpn.location + resource_group_name = var.vpn.resource_group_name + type = var.vpn.type + vpn_type = var.vpn.vpn_type + sku = var.vpn.sku + tags = local.tags + active_active = var.vpn.active_active + enable_bgp = var.vpn.enable_bgp + generation = var.vpn.generation + default_local_network_gateway_id = var.vpn.default_local_network_gateway_id + edge_zone = var.vpn.edge_zone + private_ip_address_enabled = var.vpn.private_ip_address_enabled + bgp_route_translation_for_nat_enabled = var.vpn.bgp_route_translation_for_nat_enabled + dns_forwarding_enabled = var.vpn.dns_forwarding_enabled + ip_sec_replay_protection_enabled = var.vpn.ip_sec_replay_protection_enabled + remote_vnet_traffic_enabled = var.vpn.remote_vnet_traffic_enabled + virtual_wan_traffic_enabled = var.vpn.virtual_wan_traffic_enabled + + ip_configuration { + name = var.vpn.ip_name + subnet_id = data.azurerm_subnet.this.id + public_ip_address_id = data.azurerm_public_ip.this.id + private_ip_address_allocation = var.vpn.private_ip_address_allocation + } + + custom_route { + address_prefixes = var.vpn.custom_route_address_prefixes + } + + dynamic "vpn_client_configuration" { + for_each = length(var.vpn.vpn_client_address_space) > 0 ? [1] : [] + content { + address_space = var.vpn.vpn_client_address_space + vpn_client_protocols = var.vpn.vpn_client_protocols + aad_tenant = var.vpn.vpn_client_aad_tenant + aad_audience = var.vpn.vpn_client_aad_audience + aad_issuer = var.vpn.vpn_client_aad_issuer + dynamic "root_certificate" { + for_each = var.vpn.root_certificates + content { + name = root_certificate.value.name + public_cert_data = coalesce( + root_certificate.value.public_cert_data, + root_certificate.value.public_cert + ) + } + } + dynamic "revoked_certificate" { + for_each = var.vpn.revoked_certificates + content { + name = revoked_certificate.value.name + thumbprint = revoked_certificate.value.thumbprint + } + } + vpn_auth_types = var.vpn.vpn_auth_types + } + } + + dynamic "bgp_settings" { + for_each = var.vpn.bgp_settings != null ? [1] : [] + content { + asn = var.vpn.bgp_settings.asn + peer_weight = var.vpn.bgp_settings.peer_weight + dynamic "peering_addresses" { + for_each = try(var.vpn.bgp_settings.peering_addresses, []) + content { + ip_configuration_name = peering_addresses.value.ip_configuration_name + apipa_addresses = peering_addresses.value.apipa_addresses + } + } + } + } + + dynamic "timeouts" { + for_each = var.vpn.timeouts != null ? [1] : [] + content { + create = var.vpn.timeouts.create + read = var.vpn.timeouts.read + update = var.vpn.timeouts.update + delete = var.vpn.timeouts.delete + } + } +} diff --git a/modules/azure-vnet-gateway/variables.tf b/modules/azure-vnet-gateway/variables.tf new file mode 100644 index 000000000..c338a9198 --- /dev/null +++ b/modules/azure-vnet-gateway/variables.tf @@ -0,0 +1,97 @@ +## VARIABLES SECTION + +variable "vpn" { + description = "VPN Gateway configuration object (includes P2S config)" + type = object({ + vnet_name = string + gateway_subnet_name = string + location = string + resource_group_name = string + gateway_name = string + ip_name = string + public_ip_name = string + public_ip_id = optional(string) + ip_allocation_method = string + gateway_subnet_id = optional(string) + type = string + vpn_type = string + active_active = bool + enable_bgp = bool + sku = string + generation = optional(string) + default_local_network_gateway_id = optional(string) + edge_zone = optional(string) + private_ip_address_enabled = optional(bool) + bgp_route_translation_for_nat_enabled = optional(bool) + dns_forwarding_enabled = optional(bool) + ip_sec_replay_protection_enabled = optional(bool) + remote_vnet_traffic_enabled = optional(bool) + virtual_wan_traffic_enabled = optional(bool) + + # ip_configuration block fields + private_ip_address_allocation = optional(string) + + # custom_route block + custom_route_address_prefixes = optional(list(string), []) + + # vpn_client_configuration block + vpn_client_address_space = optional(list(string), []) + vpn_client_protocols = optional(list(string), []) + vpn_client_aad_tenant = optional(string) + vpn_client_aad_audience = optional(string) + vpn_client_aad_issuer = optional(string) + root_certificates = optional(list(object({ + name = string + public_cert = optional(string) + public_cert_data = optional(string) + })), []) + revoked_certificates = optional(list(object({ + name = string + thumbprint = string + })), []) + vpn_auth_types = optional(list(string), []) + + # bgp_settings block + bgp_settings = optional(object({ + asn = optional(number) + peer_weight = optional(number) + peering_addresses = optional(list(object({ + ip_configuration_name = optional(string) + apipa_addresses = optional(list(string)) + })), []) + })) + + # timeouts block + timeouts = optional(object({ + create = optional(string) + read = optional(string) + update = optional(string) + delete = optional(string) + })) + }) +} + +variable "nat_rules" { + description = "List of NAT rules for the VPN gateway" + type = list(object({ + name = string + mode = string + type = string + ip_configuration_id = optional(string) + external_mapping_address_space = string + internal_mapping_address_space = string + })) + default = [] +} + +variable "tags_from_rg" { + description = "Use resource group tags as base for module tags" + type = bool + default = false +} + +variable "tags" { + description = "Tags to apply to resources" + type = map(string) + default = {} +} diff --git a/modules/azure-vnet-gateway/versions.tf b/modules/azure-vnet-gateway/versions.tf new file mode 100644 index 000000000..64c91805b --- /dev/null +++ b/modules/azure-vnet-gateway/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.7.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.58.0" + } + } +} diff --git a/modules/azure-vnet-gateway/vpn_nat_rule.tf b/modules/azure-vnet-gateway/vpn_nat_rule.tf new file mode 100644 index 000000000..5cb323944 --- /dev/null +++ b/modules/azure-vnet-gateway/vpn_nat_rule.tf @@ -0,0 +1,23 @@ +## VPN NAT RULE SECTION + +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway_nat_rule +resource "azurerm_virtual_network_gateway_nat_rule" "this" { + for_each = { for idx, rule in var.nat_rules : idx => rule } + name = each.value.name + resource_group_name = var.vpn.resource_group_name + virtual_network_gateway_id = azurerm_virtual_network_gateway.this.id + mode = each.value.mode + type = each.value.type + ip_configuration_id = coalesce( + try(each.value.ip_configuration_id, null), + data.azurerm_virtual_network_gateway.this.ip_configuration[0].id + ) + + external_mapping { + address_space = each.value.external_mapping_address_space + } + + internal_mapping { + address_space = each.value.internal_mapping_address_space + } +}