Managing Azure Service Bus with Terraform

Learn how to set up and manage Azure Service Bus using Terraform, including topics, subscriptions, and security configurations

Managing Azure Service Bus with Terraform

Azure Service Bus is a fully managed enterprise message broker. This guide demonstrates how to set up and manage Azure Service Bus using Terraform.

Video Tutorial

Learn more about managing Azure Service Bus with Terraform in this comprehensive video tutorial:

Prerequisites

  • Azure CLI configured with appropriate permissions
  • Terraform installed (version 1.0.0 or later)
  • Resource group created
  • Understanding of messaging concepts

Project Structure

terraform-azure-servicebus/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   └── servicebus/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── policies/
    └── security.json

Service Bus Configuration

Create modules/servicebus/main.tf:

# Service Bus Namespace
resource "azurerm_servicebus_namespace" "main" {
  name                = "${var.project_name}-sb"
  location            = var.location
  resource_group_name = var.resource_group_name
  sku                 = "Premium"
  capacity            = var.capacity

  identity {
    type = "SystemAssigned"
  }

  customer_managed_key {
    key_vault_key_id = azurerm_key_vault_key.servicebus.id
    identity_id      = azurerm_user_assigned_identity.servicebus.id
  }

  public_network_access_enabled = false
  minimum_tls_version          = "1.2"
  zone_redundant              = true

  tags = var.tags
}

# Topics
resource "azurerm_servicebus_topic" "main" {
  for_each = var.topics

  name                = each.key
  namespace_id        = azurerm_servicebus_namespace.main.id
  enable_partitioning = true
  max_size_in_megabytes = each.value.max_size_mb
  default_message_ttl   = each.value.message_ttl
  
  enable_batched_operations = true
  requires_duplicate_detection = true
  duplicate_detection_history_time_window = "PT10M"
  
  enable_express = false
  
  status = "Active"
}

# Subscriptions
resource "azurerm_servicebus_subscription" "main" {
  for_each = {
    for sub in local.subscriptions : "${sub.topic_name}.${sub.name}" => sub
  }

  name                = each.value.name
  topic_id            = azurerm_servicebus_topic.main[each.value.topic_name].id
  max_delivery_count  = 10
  
  enable_batched_operations = true
  requires_session         = true
  
  forward_to = each.value.forward_to
  
  dead_lettering_on_message_expiration = true
  
  status = "Active"
}

# Queues
resource "azurerm_servicebus_queue" "main" {
  for_each = var.queues

  name                = each.key
  namespace_id        = azurerm_servicebus_namespace.main.id
  enable_partitioning = true
  max_size_in_megabytes = each.value.max_size_mb
  
  enable_express = false
  
  enable_batched_operations = true
  requires_duplicate_detection = true
  duplicate_detection_history_time_window = "PT10M"
  
  dead_lettering_on_message_expiration = true
  max_delivery_count = 10
  
  requires_session = true
  
  status = "Active"
}

# Rules
resource "azurerm_servicebus_subscription_rule" "main" {
  for_each = {
    for rule in local.rules : "${rule.topic_name}.${rule.subscription_name}.${rule.name}" => rule
  }

  name            = each.value.name
  subscription_id = azurerm_servicebus_subscription.main["${each.value.topic_name}.${each.value.subscription_name}"].id
  filter_type     = "SqlFilter"
  sql_filter      = each.value.sql_filter

  action = each.value.action
}

Network Configuration

  1. Virtual Network Integration
resource "azurerm_virtual_network" "main" {
  name                = "${var.project_name}-vnet"
  location            = var.location
  resource_group_name = var.resource_group_name
  address_space       = ["10.0.0.0/16"]

  subnet {
    name           = "servicebus-subnet"
    address_prefix = "10.0.1.0/24"
    service_endpoints = ["Microsoft.ServiceBus"]
  }

  tags = var.tags
}

resource "azurerm_private_endpoint" "servicebus" {
  name                = "${var.project_name}-pe"
  location            = var.location
  resource_group_name = var.resource_group_name
  subnet_id           = azurerm_virtual_network.main.subnet.*.id[0]

  private_service_connection {
    name                           = "${var.project_name}-psc"
    private_connection_resource_id = azurerm_servicebus_namespace.main.id
    is_manual_connection          = false
    subresource_names            = ["namespace"]
  }

  private_dns_zone_group {
    name                 = "default"
    private_dns_zone_ids = [azurerm_private_dns_zone.servicebus.id]
  }
}

resource "azurerm_private_dns_zone" "servicebus" {
  name                = "privatelink.servicebus.windows.net"
  resource_group_name = var.resource_group_name
}

resource "azurerm_private_dns_zone_virtual_network_link" "servicebus" {
  name                  = "${var.project_name}-vnet-link"
  resource_group_name   = var.resource_group_name
  private_dns_zone_name = azurerm_private_dns_zone.servicebus.name
  virtual_network_id    = azurerm_virtual_network.main.id
}

Security Configuration

  1. Role Assignments
resource "azurerm_role_assignment" "servicebus_sender" {
  scope                = azurerm_servicebus_namespace.main.id
  role_definition_name = "Azure Service Bus Data Sender"
  principal_id         = var.sender_principal_id
}

resource "azurerm_role_assignment" "servicebus_receiver" {
  scope                = azurerm_servicebus_namespace.main.id
  role_definition_name = "Azure Service Bus Data Receiver"
  principal_id         = var.receiver_principal_id
}
  1. Customer-Managed Keys
resource "azurerm_key_vault_key" "servicebus" {
  name         = "${var.project_name}-key"
  key_vault_id = var.key_vault_id
  key_type     = "RSA"
  key_size     = 2048

  key_opts = [
    "decrypt",
    "encrypt",
    "sign",
    "unwrapKey",
    "verify",
    "wrapKey",
  ]
}

resource "azurerm_user_assigned_identity" "servicebus" {
  name                = "${var.project_name}-identity"
  resource_group_name = var.resource_group_name
  location            = var.location
}

resource "azurerm_key_vault_access_policy" "servicebus" {
  key_vault_id = var.key_vault_id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = azurerm_user_assigned_identity.servicebus.principal_id

  key_permissions = [
    "Get",
    "UnwrapKey",
    "WrapKey"
  ]
}

Monitoring Configuration

  1. Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "servicebus" {
  name                       = "${var.project_name}-diag"
  target_resource_id        = azurerm_servicebus_namespace.main.id
  log_analytics_workspace_id = var.log_analytics_workspace_id

  log {
    category = "OperationalLogs"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

resource "azurerm_monitor_metric_alert" "servicebus" {
  name                = "${var.project_name}-messages-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_servicebus_namespace.main.id]
  description         = "Alert when active message count is high"

  criteria {
    metric_namespace = "Microsoft.ServiceBus/namespaces"
    metric_name      = "ActiveMessages"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 1000
  }

  action {
    action_group_id = var.action_group_id
  }
}

Advanced Features

  1. Geo-Disaster Recovery
resource "azurerm_servicebus_namespace_disaster_recovery_config" "main" {
  name                 = "primary"
  primary_namespace_id = azurerm_servicebus_namespace.main.id
  partner_namespace_id = azurerm_servicebus_namespace.secondary.id
}
  1. Auto-Forwarding
resource "azurerm_servicebus_subscription" "forward" {
  name               = "forward-subscription"
  topic_id           = azurerm_servicebus_topic.main["source"].id
  forward_to         = azurerm_servicebus_queue.main["destination"].name
  forward_dead_lettered_messages_to = azurerm_servicebus_queue.main["dlq"].name
}

Best Practices

  1. Performance

    • Enable partitioning
    • Use sessions for ordering
    • Configure batching
    • Monitor message count
  2. Security

    • Enable private endpoints
    • Use RBAC
    • Enable encryption
    • Implement network isolation
  3. High Availability

    • Use Premium tier
    • Enable zone redundancy
    • Configure geo-disaster recovery
    • Monitor health
  4. Cost Optimization

    • Use appropriate tier
    • Clean up unused queues

Conclusion

You’ve learned how to set up and manage Azure Service Bus using Terraform. This setup provides:

  • Enterprise messaging
  • Security and encryption
  • Monitoring and alerts
  • High availability

Remember to:

  • Monitor message counts
  • Review security settings
  • Maintain dead-letter queues
  • Update access controls