Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions infrastructure/modules/relay-namespace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# relay-namespace

Deploy an [Azure Relay namespace](https://learn.microsoft.com/en-us/azure/azure-relay/relay-what-is-it) to enable secure hybrid connections between on-premises resources and Azure services. Azure Relay facilitates communication without requiring firewall changes or intrusive changes to corporate network infrastructure.

This module creates:
- Azure Relay namespace
- Optional private endpoint for secure connectivity
- Diagnostic settings for monitoring and logging

**Note:** This module only creates the namespace. Hybrid connections and authorization rules should be created separately using dedicated modules to support the pattern of one namespace with many hybrid connections.

## Private DNS Zone

Azure Relay uses the same private DNS zone as Service Bus: `privatelink.servicebus.windows.net`. Ensure this DNS zone is configured when enabling private endpoints.

## Terraform documentation
For the list of inputs, outputs, resources... check the [terraform module documentation](tfdocs.md).

## Usage

### Basic usage (without private endpoint)
```hcl
module "relay_namespace" {
source = "../../../dtos-devops-templates/infrastructure/modules/relay-namespace"

name = "relay-${var.application}-${var.environment}"
resource_group_name = var.resource_group_name
location = var.location

log_analytics_workspace_id = data.terraform_remote_state.audit.outputs.log_analytics_workspace_id

tags = var.tags
}
```

### With private endpoint
```hcl
module "relay_namespace" {
source = "../../../dtos-devops-templates/infrastructure/modules/relay-namespace"

name = "relay-${var.application}-${var.environment}"
resource_group_name = var.resource_group_name
location = var.location

log_analytics_workspace_id = data.terraform_remote_state.audit.outputs.log_analytics_workspace_id

private_endpoint_properties = {
private_endpoint_enabled = true
private_endpoint_subnet_id = module.private_endpoint_subnet.id
private_endpoint_resource_group_name = var.network_resource_group_name
private_dns_zone_ids_relay = [data.azurerm_private_dns_zone.servicebus.id]
}

tags = var.tags
}
```

## Naming constraints

The Azure Relay namespace name must follow these rules:

| Constraint | Requirement |
|------------|-------------|
| Length | 6-50 characters |
| Start | Must start with a letter |
| End | Must end with a letter or number |
| Characters | Letters, numbers, and hyphens only |
| Uniqueness | Globally unique (creates `<name>.servicebus.windows.net`) |

## Outputs

| Output | Description |
|--------|-------------|
| `name` | The name of the Relay namespace |
| `id` | The resource ID of the Relay namespace |
| `primary_connection_string` | Primary connection string (sensitive) |
| `secondary_connection_string` | Secondary connection string (sensitive) |
| `primary_key` | Primary access key (sensitive) |
| `secondary_key` | Secondary access key (sensitive) |
52 changes: 52 additions & 0 deletions infrastructure/modules/relay-namespace/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* --------------------------------------------------------------------------------------------------
Azure Relay Namespace
-------------------------------------------------------------------------------------------------- */
resource "azurerm_relay_namespace" "relay" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
sku_name = var.sku_name

tags = var.tags
}

/* --------------------------------------------------------------------------------------------------
Private Endpoint Configuration for Azure Relay Namespace
-------------------------------------------------------------------------------------------------- */
module "private_endpoint_relay" {
count = var.private_endpoint_properties.private_endpoint_enabled ? 1 : 0

source = "../private-endpoint"

name = "${var.name}-azure-relay-pep"
resource_group_name = var.private_endpoint_properties.private_endpoint_resource_group_name
location = var.location
subnet_id = var.private_endpoint_properties.private_endpoint_subnet_id

private_dns_zone_group = {
name = "${var.name}-azure-relay-pep-zone-group"
private_dns_zone_ids = var.private_endpoint_properties.private_dns_zone_ids_relay
}

private_service_connection = {
name = "${var.name}-relay-pep-connection"
private_connection_resource_id = azurerm_relay_namespace.relay.id
subresource_names = ["namespace"]
is_manual_connection = var.private_endpoint_properties.private_service_connection_is_manual
}

tags = var.tags
}

/* --------------------------------------------------------------------------------------------------
Diagnostic Settings
-------------------------------------------------------------------------------------------------- */
module "diagnostic-settings" {
source = "../diagnostic-settings"

name = "${var.name}-diagnostic-setting"
target_resource_id = azurerm_relay_namespace.relay.id
log_analytics_workspace_id = var.log_analytics_workspace_id
enabled_log = var.monitor_diagnostic_setting_relay_enabled_logs
enabled_metric = var.monitor_diagnostic_setting_relay_metrics
}
33 changes: 33 additions & 0 deletions infrastructure/modules/relay-namespace/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
output "name" {
description = "The name of the Relay namespace."
value = azurerm_relay_namespace.relay.name
}

output "id" {
description = "The ID of the Relay namespace."
value = azurerm_relay_namespace.relay.id
}

output "primary_connection_string" {
description = "The primary connection string for the Relay namespace."
value = azurerm_relay_namespace.relay.primary_connection_string
sensitive = true
}

output "secondary_connection_string" {
description = "The secondary connection string for the Relay namespace."
value = azurerm_relay_namespace.relay.secondary_connection_string
sensitive = true
}

output "primary_key" {
description = "The primary access key for the Relay namespace."
value = azurerm_relay_namespace.relay.primary_key
sensitive = true
}

output "secondary_key" {
description = "The secondary access key for the Relay namespace."
value = azurerm_relay_namespace.relay.secondary_key
sensitive = true
}
140 changes: 140 additions & 0 deletions infrastructure/modules/relay-namespace/tfdocs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Module documentation

## Required Inputs

The following input variables are required:

### <a name="input_location"></a> [location](#input\_location)

Description: The location/region where the Relay namespace is created.

Type: `string`

### <a name="input_log_analytics_workspace_id"></a> [log\_analytics\_workspace\_id](#input\_log\_analytics\_workspace\_id)

Description: ID of the Log Analytics workspace to send resource logging to via diagnostic settings.

Type: `string`

### <a name="input_name"></a> [name](#input\_name)

Description: The name of the Azure Relay namespace.

Type: `string`

### <a name="input_private_endpoint_properties"></a> [private\_endpoint\_properties](#input\_private\_endpoint\_properties)

Description: Consolidated properties for the Azure Relay Private Endpoint.

Type:

```hcl
object({
private_dns_zone_ids_relay = optional(list(string), [])
private_endpoint_enabled = optional(bool, false)
private_endpoint_subnet_id = optional(string, "")
private_endpoint_resource_group_name = optional(string, "")
private_service_connection_is_manual = optional(bool, false)
})
```

### <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name)

Description: The name of the resource group in which to create the Relay namespace.

Type: `string`

## Optional Inputs

The following input variables are optional (have default values):

### <a name="input_monitor_diagnostic_setting_relay_enabled_logs"></a> [monitor\_diagnostic\_setting\_relay\_enabled\_logs](#input\_monitor\_diagnostic\_setting\_relay\_enabled\_logs)

Description: Controls what logs will be enabled for the Relay namespace.

Type: `list(string)`

Default:

```json
[
"HybridConnectionsEvent"
]
```

### <a name="input_monitor_diagnostic_setting_relay_metrics"></a> [monitor\_diagnostic\_setting\_relay\_metrics](#input\_monitor\_diagnostic\_setting\_relay\_metrics)

Description: Controls what metrics will be enabled for the Relay namespace.

Type: `list(string)`

Default:

```json
[
"AllMetrics"
]
```

### <a name="input_sku_name"></a> [sku\_name](#input\_sku\_name)

Description: The SKU for the Relay namespace. Only 'Standard' is supported.

Type: `string`

Default: `"Standard"`

### <a name="input_tags"></a> [tags](#input\_tags)

Description: A mapping of tags to assign to the resource.

Type: `map(string)`

Default: `{}`
## Modules

The following Modules are called:

### <a name="module_diagnostic-settings"></a> [diagnostic-settings](#module\_diagnostic-settings)

Source: ../diagnostic-settings

Version:

### <a name="module_private_endpoint_relay"></a> [private\_endpoint\_relay](#module\_private\_endpoint\_relay)

Source: ../private-endpoint

Version:
## Outputs

The following outputs are exported:

### <a name="output_id"></a> [id](#output\_id)

Description: The ID of the Relay namespace.

### <a name="output_name"></a> [name](#output\_name)

Description: The name of the Relay namespace.

### <a name="output_primary_connection_string"></a> [primary\_connection\_string](#output\_primary\_connection\_string)

Description: The primary connection string for the Relay namespace.

### <a name="output_primary_key"></a> [primary\_key](#output\_primary\_key)

Description: The primary access key for the Relay namespace.

### <a name="output_secondary_connection_string"></a> [secondary\_connection\_string](#output\_secondary\_connection\_string)

Description: The secondary connection string for the Relay namespace.

### <a name="output_secondary_key"></a> [secondary\_key](#output\_secondary\_key)

Description: The secondary access key for the Relay namespace.
## Resources

The following resources are used by this module:

- [azurerm_relay_namespace.relay](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/relay_namespace) (resource)
75 changes: 75 additions & 0 deletions infrastructure/modules/relay-namespace/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
variable "name" {
description = "The name of the Azure Relay namespace."
type = string
validation {
condition = can(regex("^[a-zA-Z][a-zA-Z0-9-]{4,48}[a-zA-Z0-9]$", var.name))
error_message = "The Relay namespace name must be 6-50 characters, start with a letter, end with alphanumeric, and contain only letters, numbers, and hyphens."
}
}

variable "resource_group_name" {
description = "The name of the resource group in which to create the Relay namespace."
type = string
}

variable "location" {
description = "The location/region where the Relay namespace is created."
type = string
}

variable "sku_name" {
description = "The SKU for the Relay namespace. Only 'Standard' is supported."
type = string
default = "Standard"

validation {
condition = var.sku_name == "Standard"
error_message = "Azure Relay namespace only supports 'Standard' SKU."
}
}

variable "log_analytics_workspace_id" {
type = string
description = "ID of the Log Analytics workspace to send resource logging to via diagnostic settings."
}

variable "monitor_diagnostic_setting_relay_enabled_logs" {
type = list(string)
description = "Controls what logs will be enabled for the Relay namespace."
default = ["HybridConnectionsEvent"]
}

variable "monitor_diagnostic_setting_relay_metrics" {
type = list(string)
description = "Controls what metrics will be enabled for the Relay namespace."
default = ["AllMetrics"]
}

variable "private_endpoint_properties" {
description = "Consolidated properties for the Azure Relay Private Endpoint."
type = object({
private_dns_zone_ids_relay = optional(list(string), [])
private_endpoint_enabled = optional(bool, false)
private_endpoint_subnet_id = optional(string, "")
private_endpoint_resource_group_name = optional(string, "")
private_service_connection_is_manual = optional(bool, false)
})

validation {
condition = (
can(var.private_endpoint_properties == null) ||
can(var.private_endpoint_properties.private_endpoint_enabled == false) ||
can((length(var.private_endpoint_properties.private_dns_zone_ids_relay) > 0 &&
length(var.private_endpoint_properties.private_endpoint_subnet_id) > 0
)
)
)
error_message = "Both private_dns_zone_ids_relay and private_endpoint_subnet_id must be provided if private_endpoint_enabled is true."
}
}

variable "tags" {
description = "A mapping of tags to assign to the resource."
type = map(string)
default = {}
}
Loading