TerraformPilot

Terraform

Azure Service Bus with Terraform - Queues and Topics

Deploy Azure Service Bus with Terraform. Queues, topics, subscriptions, dead-letter queues, private endpoints, and message filtering rules.

LLuca Berton1 min read

Quick Answer

#
resource "azurerm_servicebus_namespace" "main" {
  name                = "myapp-servicebus"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  sku                 = "Standard"
}
 
resource "azurerm_servicebus_queue" "orders" {
  name         = "orders"
  namespace_id = azurerm_servicebus_namespace.main.id
}

Production Namespace

#
resource "azurerm_servicebus_namespace" "main" {
  name                         = "${var.project}-${var.environment}-sb"
  location                     = azurerm_resource_group.main.location
  resource_group_name          = azurerm_resource_group.main.name
  sku                          = "Premium"
  capacity                     = 1           # Messaging units (Premium only)
  premium_messaging_partitions = 1
  minimum_tls_version          = "1.2"
  public_network_access_enabled = false
 
  identity {
    type = "SystemAssigned"
  }
 
  tags = { Environment = var.environment }
}

Queues

#
resource "azurerm_servicebus_queue" "orders" {
  name         = "orders"
  namespace_id = azurerm_servicebus_namespace.main.id
 
  max_delivery_count           = 10
  lock_duration                = "PT1M"       # 1 minute
  default_message_ttl          = "P14D"       # 14 days
  dead_lettering_on_message_expiration = true
  requires_duplicate_detection = true
  duplicate_detection_history_time_window = "PT10M"
  max_size_in_megabytes        = 5120
  enable_partitioning          = false        # Cannot enable with Premium
}
 
# Dead-letter queue is automatic — access via $DeadLetterQueue suffix

Topics and Subscriptions

#
resource "azurerm_servicebus_topic" "events" {
  name         = "events"
  namespace_id = azurerm_servicebus_namespace.main.id
 
  default_message_ttl          = "P7D"
  max_size_in_megabytes        = 5120
  requires_duplicate_detection = true
  support_ordering             = true
}
 
# Subscription: receives all events
resource "azurerm_servicebus_subscription" "all_events" {
  name               = "all-events"
  topic_id           = azurerm_servicebus_topic.events.id
  max_delivery_count = 10
  lock_duration      = "PT1M"
  default_message_ttl = "P7D"
  dead_lettering_on_message_expiration = true
}
 
# Subscription: only order events (with filter)
resource "azurerm_servicebus_subscription" "order_events" {
  name               = "order-events"
  topic_id           = azurerm_servicebus_topic.events.id
  max_delivery_count = 10
}
 
resource "azurerm_servicebus_subscription_rule" "order_filter" {
  name            = "order-filter"
  subscription_id = azurerm_servicebus_subscription.order_events.id
  filter_type     = "CorrelationFilter"
 
  correlation_filter {
    content_type = "application/json"
    label        = "order"
    properties = {
      "eventType" = "OrderCreated"
    }
  }
}
 
# SQL filter example
resource "azurerm_servicebus_subscription_rule" "high_priority" {
  name            = "high-priority"
  subscription_id = azurerm_servicebus_subscription.order_events.id
  filter_type     = "SqlFilter"
  sql_filter      = "priority > 3 AND region = 'us-east'"
}

Authorization Rules

#
# Namespace-level shared access policy
resource "azurerm_servicebus_namespace_authorization_rule" "app" {
  name         = "app-policy"
  namespace_id = azurerm_servicebus_namespace.main.id
  listen       = true
  send         = true
  manage       = false
}
 
# Queue-level policy
resource "azurerm_servicebus_queue_authorization_rule" "sender" {
  name     = "sender-policy"
  queue_id = azurerm_servicebus_queue.orders.id
  listen   = false
  send     = true
  manage   = false
}
 
output "connection_string" {
  value     = azurerm_servicebus_namespace_authorization_rule.app.primary_connection_string
  sensitive = true
}

Private Endpoint

#
resource "azurerm_private_endpoint" "servicebus" {
  name                = "${var.project}-sb-pe"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  subnet_id           = azurerm_subnet.private_endpoints.id
 
  private_service_connection {
    name                           = "${var.project}-sb-psc"
    private_connection_resource_id = azurerm_servicebus_namespace.main.id
    is_manual_connection           = false
    subresource_names              = ["namespace"]
  }
}

SKU Comparison

#
FeatureBasicStandardPremium
Queues
Topics/Subscriptions
Message size256 KB256 KB100 MB
Private endpoints
VNet integration
Dedicated resources
#

Conclusion

#

Use queues for point-to-point messaging and topics for pub/sub fan-out. Premium SKU is required for private endpoints and VNet integration. Always enable dead-lettering and duplicate detection. Use correlation filters for efficient message routing and SQL filters for complex conditions.

#Terraform#Azure#Service Bus#Messaging#Infrastructure as Code

Share this article