Managing Azure Event Grid with Terraform
Learn how to set up and manage Azure Event Grid using Terraform, including topics, subscriptions, and event handling
Managing Azure Event Grid with Terraform
Azure Event Grid is a fully managed event routing service. This guide demonstrates how to set up and manage Azure Event Grid using Terraform.
Video Tutorial
Learn more about managing Azure Event Grid 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 event-driven architecture
Project Structure
terraform-azure-eventgrid/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── eventgrid/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── policies/
└── security.json
Event Grid Configuration
Create modules/eventgrid/main.tf
:
# System Topic
resource "azurerm_eventgrid_system_topic" "storage" {
name = "${var.project_name}-storage-events"
location = var.location
resource_group_name = var.resource_group_name
source_arm_resource_id = azurerm_storage_account.main.id
topic_type = "Microsoft.Storage.StorageAccounts"
identity {
type = "SystemAssigned"
}
tags = var.tags
}
# Custom Topic
resource "azurerm_eventgrid_topic" "main" {
name = "${var.project_name}-topic"
location = var.location
resource_group_name = var.resource_group_name
input_schema = "EventGridSchema"
public_network_access_enabled = false
identity {
type = "SystemAssigned"
}
tags = var.tags
}
# Domain
resource "azurerm_eventgrid_domain" "main" {
name = "${var.project_name}-domain"
location = var.location
resource_group_name = var.resource_group_name
input_schema = "EventGridSchema"
public_network_access_enabled = false
identity {
type = "SystemAssigned"
}
tags = var.tags
}
# Domain Topic
resource "azurerm_eventgrid_domain_topic" "main" {
name = "orders"
domain_name = azurerm_eventgrid_domain.main.name
resource_group_name = var.resource_group_name
}
# Event Subscription (to Function)
resource "azurerm_eventgrid_event_subscription" "function" {
name = "${var.project_name}-function-sub"
scope = azurerm_eventgrid_topic.main.id
included_event_types = ["OrderCreated", "OrderUpdated"]
azure_function_endpoint {
function_id = "${var.function_app_id}/functions/ProcessOrder"
max_events_per_batch = 1
preferred_batch_size_in_kilobytes = 64
}
advanced_filter {
string_begins_with {
key = "Subject"
values = ["orders/high-priority"]
}
}
retry_policy {
max_delivery_attempts = 30
event_time_to_live = 1440
}
dead_letter_identity {
type = "SystemAssigned"
}
storage_blob_dead_letter_destination {
storage_account_id = azurerm_storage_account.dlq.id
storage_container_name = "deadletter"
storage_blob_container_sas_url = data.azurerm_storage_account_blob_container_sas.dlq.sas
}
}
# Event Subscription (to Service Bus)
resource "azurerm_eventgrid_event_subscription" "servicebus" {
name = "${var.project_name}-servicebus-sub"
scope = azurerm_eventgrid_topic.main.id
included_event_types = ["OrderCancelled"]
service_bus_topic_endpoint_id = azurerm_servicebus_topic.main.id
advanced_filter {
string_in {
key = "Data.reason"
values = ["OutOfStock", "CustomerRequest"]
}
}
delivery_property {
header_name = "OrderId"
type = "Dynamic"
source_field = "data.orderId"
}
}
# Event Subscription (to Event Hub)
resource "azurerm_eventgrid_event_subscription" "eventhub" {
name = "${var.project_name}-eventhub-sub"
scope = azurerm_eventgrid_topic.main.id
included_event_types = ["OrderShipped"]
eventhub_endpoint_id = azurerm_eventhub.main.id
advanced_filter {
number_greater_than {
key = "Data.amount"
value = 1000
}
}
}
# Event Subscription (to Storage Queue)
resource "azurerm_eventgrid_event_subscription" "queue" {
name = "${var.project_name}-queue-sub"
scope = azurerm_eventgrid_topic.main.id
included_event_types = ["OrderReturned"]
storage_queue_endpoint {
storage_account_id = azurerm_storage_account.main.id
queue_name = "returns"
}
}
Network Configuration
- 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 = "eventgrid-subnet"
address_prefix = "10.0.1.0/24"
service_endpoints = ["Microsoft.EventGrid"]
}
tags = var.tags
}
resource "azurerm_private_endpoint" "eventgrid" {
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_eventgrid_topic.main.id
is_manual_connection = false
subresource_names = ["topic"]
}
private_dns_zone_group {
name = "default"
private_dns_zone_ids = [azurerm_private_dns_zone.eventgrid.id]
}
}
resource "azurerm_private_dns_zone" "eventgrid" {
name = "privatelink.eventgrid.azure.net"
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "eventgrid" {
name = "${var.project_name}-vnet-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.eventgrid.name
virtual_network_id = azurerm_virtual_network.main.id
}
Security Configuration
- Role Assignments
resource "azurerm_role_assignment" "eventgrid_publisher" {
scope = azurerm_eventgrid_topic.main.id
role_definition_name = "EventGrid Data Sender"
principal_id = var.publisher_principal_id
}
resource "azurerm_role_assignment" "eventgrid_subscriber" {
scope = azurerm_eventgrid_topic.main.id
role_definition_name = "EventGrid Data Receiver"
principal_id = var.subscriber_principal_id
}
- IP Rules
resource "azurerm_eventgrid_topic_inbound_ip_rule" "main" {
eventgrid_topic_name = azurerm_eventgrid_topic.main.name
resource_group_name = var.resource_group_name
ip_mask = var.allowed_ip_range
action = "Allow"
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "eventgrid" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_eventgrid_topic.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "DeliveryFailures"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "eventgrid" {
name = "${var.project_name}-delivery-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_eventgrid_topic.main.id]
description = "Alert when event delivery fails"
criteria {
metric_namespace = "Microsoft.EventGrid/topics"
metric_name = "UnmatchedEventCount"
aggregation = "Total"
operator = "GreaterThan"
threshold = 10
}
action {
action_group_id = var.action_group_id
}
}
Advanced Features
- Input Mapping
resource "azurerm_eventgrid_event_subscription" "mapping" {
name = "${var.project_name}-mapping-sub"
scope = azurerm_eventgrid_topic.main.id
input_mapping_fields {
topic = "subject"
event_type = "eventType"
event_time = "eventTime"
data_version = "dataVersion"
}
input_mapping_default_values {
data_version = "1.0"
subject = "DefaultSubject"
}
}
- Batching
resource "azurerm_eventgrid_event_subscription" "batch" {
name = "${var.project_name}-batch-sub"
scope = azurerm_eventgrid_topic.main.id
webhook_endpoint {
url = "https://example.com/api/events"
max_events_per_batch = 10
preferred_batch_size_in_kilobytes = 64
}
}
Best Practices
-
Performance
- Use appropriate endpoints
- Configure batching
- Implement retry policies
- Monitor delivery rates
-
Security
- Enable private endpoints
- Use RBAC
- Implement IP rules
- Enable authentication
-
Reliability
- Configure dead-lettering
- Set retry policies
- Monitor failures
- Use filtering
-
Cost Optimization
- Clean up subscriptions
- Use appropriate endpoints
Conclusion
You’ve learned how to set up and manage Azure Event Grid using Terraform. This setup provides:
- Event routing
- Security and filtering
- Monitoring and alerts
- Dead-letter handling
Remember to:
- Monitor delivery rates
- Review security settings
- Handle dead-letters
- Update access controls