Skip to content

Commit cb79d17

Browse files
feat: add relay-hybrid-connection module for Azure Relay Hybrid Connections
Adds a new Terraform module to create Azure Relay Hybrid Connections and Authorization Rules. The module is designed to work with an existing relay namespace created by the relay-namespace module.
1 parent db6eca7 commit cb79d17

File tree

6 files changed

+344
-1
lines changed

6 files changed

+344
-1
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# relay-hybrid-connection
2+
3+
Deploy an [Azure Relay Hybrid Connection](https://learn.microsoft.com/en-us/azure/azure-relay/relay-hybrid-connections-protocol) to enable secure, bi-directional communication between on-premises applications and Azure services through an existing Azure Relay namespace.
4+
5+
This module creates:
6+
- Azure Relay Hybrid Connection
7+
- Optional authorization rules with configurable permissions (Listen, Send, Manage)
8+
9+
**Note:** This module requires an existing Azure Relay namespace. Use the `relay-namespace` module to create the namespace first.
10+
11+
## Terraform documentation
12+
For the list of inputs, outputs, resources... check the [terraform module documentation](tfdocs.md).
13+
14+
## Usage
15+
16+
### Basic usage (without authorization rules)
17+
```hcl
18+
module "relay_hybrid_connection" {
19+
source = "../../../dtos-devops-templates/infrastructure/modules/relay-hybrid-connection"
20+
21+
name = "hc-${var.application}-${var.environment}"
22+
relay_namespace_name = module.relay_namespace.name
23+
resource_group_name = var.resource_group_name
24+
}
25+
```
26+
27+
### With authorization rules
28+
```hcl
29+
module "relay_hybrid_connection" {
30+
source = "../../../dtos-devops-templates/infrastructure/modules/relay-hybrid-connection"
31+
32+
name = "hc-${var.application}-${var.environment}"
33+
relay_namespace_name = module.relay_namespace.name
34+
resource_group_name = var.resource_group_name
35+
requires_client_authorization = true
36+
user_metadata = "Application hybrid connection"
37+
38+
authorization_rules = {
39+
"listen-rule" = {
40+
listen = true
41+
send = false
42+
manage = false
43+
}
44+
"send-rule" = {
45+
listen = false
46+
send = true
47+
manage = false
48+
}
49+
"manage-rule" = {
50+
listen = true
51+
send = true
52+
manage = true
53+
}
54+
}
55+
}
56+
```
57+
58+
### Complete example with namespace
59+
```hcl
60+
# Create the relay namespace first
61+
module "relay_namespace" {
62+
source = "../../../dtos-devops-templates/infrastructure/modules/relay-namespace"
63+
64+
name = "relay-${var.application}-${var.environment}"
65+
resource_group_name = var.resource_group_name
66+
location = var.location
67+
log_analytics_workspace_id = data.terraform_remote_state.audit.outputs.log_analytics_workspace_id
68+
69+
tags = var.tags
70+
}
71+
72+
# Create hybrid connection with authorization rules
73+
module "relay_hybrid_connection" {
74+
source = "../../../dtos-devops-templates/infrastructure/modules/relay-hybrid-connection"
75+
76+
name = "hc-${var.application}-${var.environment}"
77+
relay_namespace_name = module.relay_namespace.name
78+
resource_group_name = var.resource_group_name
79+
80+
authorization_rules = {
81+
"app-listener" = {
82+
listen = true
83+
}
84+
"app-sender" = {
85+
send = true
86+
}
87+
}
88+
}
89+
```
90+
91+
## Naming constraints
92+
93+
The Azure Relay Hybrid Connection name must follow these rules:
94+
95+
| Constraint | Requirement |
96+
|------------|-------------|
97+
| Length | 1-260 characters |
98+
| Start | Must start with a letter or number |
99+
| End | Must end with a letter or number |
100+
| Characters | Letters, numbers, hyphens, underscores, and periods |
101+
102+
Authorization rule names follow similar constraints (1-256 characters).
103+
104+
## Authorization rules
105+
106+
Authorization rules support three permission types:
107+
108+
| Permission | Description |
109+
|------------|-------------|
110+
| `listen` | Allows receiving messages from the hybrid connection |
111+
| `send` | Allows sending messages to the hybrid connection |
112+
| `manage` | Allows managing the hybrid connection (requires both `listen` and `send` to be `true`) |
113+
114+
**Note:** When `manage = true`, both `listen` and `send` must also be set to `true`. The module validates this constraint.
115+
116+
## Outputs
117+
118+
| Output | Description |
119+
|--------|-------------|
120+
| `name` | The name of the Hybrid Connection |
121+
| `id` | The resource ID of the Hybrid Connection |
122+
| `authorization_rule_ids` | Map of authorization rule names to their IDs |
123+
| `authorization_rule_primary_keys` | Map of authorization rule names to their primary keys (sensitive) |
124+
| `authorization_rule_secondary_keys` | Map of authorization rule names to their secondary keys (sensitive) |
125+
| `authorization_rule_primary_connection_strings` | Map of authorization rule names to their primary connection strings (sensitive) |
126+
| `authorization_rule_secondary_connection_strings` | Map of authorization rule names to their secondary connection strings (sensitive) |
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* --------------------------------------------------------------------------------------------------
2+
Azure Relay Hybrid Connection
3+
-------------------------------------------------------------------------------------------------- */
4+
resource "azurerm_relay_hybrid_connection" "hybrid_connection" {
5+
name = var.name
6+
relay_namespace_name = var.relay_namespace_name
7+
resource_group_name = var.resource_group_name
8+
requires_client_authorization = var.requires_client_authorization
9+
user_metadata = var.user_metadata
10+
}
11+
12+
/* --------------------------------------------------------------------------------------------------
13+
Azure Relay Hybrid Connection Authorization Rules
14+
-------------------------------------------------------------------------------------------------- */
15+
resource "azurerm_relay_hybrid_connection_authorization_rule" "auth_rule" {
16+
for_each = var.authorization_rules
17+
18+
name = each.key
19+
hybrid_connection_name = azurerm_relay_hybrid_connection.hybrid_connection.name
20+
namespace_name = var.relay_namespace_name
21+
resource_group_name = var.resource_group_name
22+
23+
listen = each.value.listen
24+
send = each.value.send
25+
manage = each.value.manage
26+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
output "id" {
2+
description = "The ID of the Relay Hybrid Connection."
3+
value = azurerm_relay_hybrid_connection.hybrid_connection.id
4+
}
5+
6+
output "name" {
7+
description = "The name of the Relay Hybrid Connection."
8+
value = azurerm_relay_hybrid_connection.hybrid_connection.name
9+
}
10+
11+
output "authorization_rule_ids" {
12+
description = "A map of authorization rule names to their IDs."
13+
value = { for k, v in azurerm_relay_hybrid_connection_authorization_rule.auth_rule : k => v.id }
14+
}
15+
16+
output "authorization_rule_primary_keys" {
17+
description = "A map of authorization rule names to their primary keys."
18+
value = { for k, v in azurerm_relay_hybrid_connection_authorization_rule.auth_rule : k => v.primary_key }
19+
sensitive = true
20+
}
21+
22+
output "authorization_rule_secondary_keys" {
23+
description = "A map of authorization rule names to their secondary keys."
24+
value = { for k, v in azurerm_relay_hybrid_connection_authorization_rule.auth_rule : k => v.secondary_key }
25+
sensitive = true
26+
}
27+
28+
output "authorization_rule_primary_connection_strings" {
29+
description = "A map of authorization rule names to their primary connection strings."
30+
value = { for k, v in azurerm_relay_hybrid_connection_authorization_rule.auth_rule : k => v.primary_connection_string }
31+
sensitive = true
32+
}
33+
34+
output "authorization_rule_secondary_connection_strings" {
35+
description = "A map of authorization rule names to their secondary connection strings."
36+
value = { for k, v in azurerm_relay_hybrid_connection_authorization_rule.auth_rule : k => v.secondary_connection_string }
37+
sensitive = true
38+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Module documentation
2+
3+
## Required Inputs
4+
5+
The following input variables are required:
6+
7+
### <a name="input_name"></a> [name](#input\_name)
8+
9+
Description: The name of the Azure Relay Hybrid Connection.
10+
11+
Type: `string`
12+
13+
### <a name="input_relay_namespace_name"></a> [relay\_namespace\_name](#input\_relay\_namespace\_name)
14+
15+
Description: The name of the Azure Relay namespace in which to create the Hybrid Connection.
16+
17+
Type: `string`
18+
19+
### <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name)
20+
21+
Description: The name of the resource group containing the Azure Relay namespace.
22+
23+
Type: `string`
24+
25+
## Optional Inputs
26+
27+
The following input variables are optional (have default values):
28+
29+
### <a name="input_authorization_rules"></a> [authorization\_rules](#input\_authorization\_rules)
30+
31+
Description: A map of authorization rules to create for the Hybrid Connection.
32+
33+
Type:
34+
35+
```hcl
36+
map(object({
37+
listen = optional(bool, false)
38+
send = optional(bool, false)
39+
manage = optional(bool, false)
40+
}))
41+
```
42+
43+
Default: `{}`
44+
45+
### <a name="input_requires_client_authorization"></a> [requires\_client\_authorization](#input\_requires\_client\_authorization)
46+
47+
Description: Whether client authorization is required for this Hybrid Connection.
48+
49+
Type: `bool`
50+
51+
Default: `true`
52+
53+
### <a name="input_user_metadata"></a> [user\_metadata](#input\_user\_metadata)
54+
55+
Description: User metadata string for the Hybrid Connection.
56+
57+
Type: `string`
58+
59+
Default: `null`
60+
61+
## Outputs
62+
63+
The following outputs are exported:
64+
65+
### <a name="output_authorization_rule_ids"></a> [authorization\_rule\_ids](#output\_authorization\_rule\_ids)
66+
67+
Description: A map of authorization rule names to their IDs.
68+
69+
### <a name="output_authorization_rule_primary_connection_strings"></a> [authorization\_rule\_primary\_connection\_strings](#output\_authorization\_rule\_primary\_connection\_strings)
70+
71+
Description: A map of authorization rule names to their primary connection strings.
72+
73+
### <a name="output_authorization_rule_primary_keys"></a> [authorization\_rule\_primary\_keys](#output\_authorization\_rule\_primary\_keys)
74+
75+
Description: A map of authorization rule names to their primary keys.
76+
77+
### <a name="output_authorization_rule_secondary_connection_strings"></a> [authorization\_rule\_secondary\_connection\_strings](#output\_authorization\_rule\_secondary\_connection\_strings)
78+
79+
Description: A map of authorization rule names to their secondary connection strings.
80+
81+
### <a name="output_authorization_rule_secondary_keys"></a> [authorization\_rule\_secondary\_keys](#output\_authorization\_rule\_secondary\_keys)
82+
83+
Description: A map of authorization rule names to their secondary keys.
84+
85+
### <a name="output_id"></a> [id](#output\_id)
86+
87+
Description: The ID of the Relay Hybrid Connection.
88+
89+
### <a name="output_name"></a> [name](#output\_name)
90+
91+
Description: The name of the Relay Hybrid Connection.
92+
## Resources
93+
94+
The following resources are used by this module:
95+
96+
- [azurerm_relay_hybrid_connection.hybrid_connection](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/relay_hybrid_connection) (resource)
97+
- [azurerm_relay_hybrid_connection_authorization_rule.auth_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/relay_hybrid_connection_authorization_rule) (resource)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
variable "name" {
2+
description = "The name of the Azure Relay Hybrid Connection."
3+
type = string
4+
validation {
5+
condition = can(regex("^[a-zA-Z0-9]([a-zA-Z0-9-._]{0,258}[a-zA-Z0-9])?$", var.name))
6+
error_message = "The hybrid connection name must be 1-260 characters, start and end with an alphanumeric character, and can only contain letters, numbers, hyphens, underscores, and periods."
7+
}
8+
}
9+
10+
variable "relay_namespace_name" {
11+
description = "The name of the Azure Relay namespace in which to create the Hybrid Connection."
12+
type = string
13+
}
14+
15+
variable "resource_group_name" {
16+
description = "The name of the resource group containing the Azure Relay namespace."
17+
type = string
18+
}
19+
20+
variable "requires_client_authorization" {
21+
description = "Whether client authorization is required for this Hybrid Connection."
22+
type = bool
23+
default = true
24+
}
25+
26+
variable "user_metadata" {
27+
description = "User metadata string for the Hybrid Connection."
28+
type = string
29+
default = null
30+
}
31+
32+
variable "authorization_rules" {
33+
description = "A map of authorization rules to create for the Hybrid Connection."
34+
type = map(object({
35+
listen = optional(bool, false)
36+
send = optional(bool, false)
37+
manage = optional(bool, false)
38+
}))
39+
default = {}
40+
41+
validation {
42+
condition = alltrue([
43+
for name, rule in var.authorization_rules :
44+
can(regex("^[a-zA-Z0-9]([a-zA-Z0-9-._]{0,254}[a-zA-Z0-9])?$", name))
45+
])
46+
error_message = "Authorization rule names must be 1-256 characters, start and end with an alphanumeric character, and can only contain letters, numbers, hyphens, underscores, and periods."
47+
}
48+
49+
validation {
50+
condition = alltrue([
51+
for name, rule in var.authorization_rules :
52+
rule.manage == false || (rule.listen == true && rule.send == true)
53+
])
54+
error_message = "When 'manage' is true, both 'listen' and 'send' must also be true."
55+
}
56+
}

infrastructure/modules/relay-namespace/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This module creates:
77
- Optional private endpoint for secure connectivity
88
- Diagnostic settings for monitoring and logging
99

10-
**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.
10+
**Note:** This module only creates the namespace. Hybrid connections and authorization rules should be created separately using the [relay-hybrid-connection](../relay-hybrid-connection/README.md) module to support the pattern of one namespace with many hybrid connections.
1111

1212
## Private DNS Zone
1313

0 commit comments

Comments
 (0)