Managing Azure CDN with Terraform
Learn how to set up and manage Azure CDN using Terraform, including endpoints, rules, and security configurations
Managing Azure CDN with Terraform
Azure Content Delivery Network (CDN) is a distributed network of servers that can efficiently deliver web content to users. This guide demonstrates how to set up and manage Azure CDN using Terraform.
Video Tutorial
Learn more about managing Azure CDN 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 CDN concepts
Project Structure
terraform-azure-cdn/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── cdn/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── rules/
└── routing.json
CDN Configuration
Create modules/cdn/main.tf
:
# CDN Profile
resource "azurerm_cdn_profile" "main" {
name = "${var.project_name}-cdn"
location = var.location
resource_group_name = var.resource_group_name
sku = "Standard_Microsoft"
tags = var.tags
}
# CDN Endpoint
resource "azurerm_cdn_endpoint" "main" {
name = "${var.project_name}-endpoint"
profile_name = azurerm_cdn_profile.main.name
location = var.location
resource_group_name = var.resource_group_name
origin {
name = "primary"
host_name = var.origin_hostname
http_port = 80
https_port = 443
private_link {
request_message = "Request access for CDN"
target_resource_id = var.origin_resource_id
location = var.location
}
}
origin_host_header = var.origin_hostname
is_compression_enabled = true
content_types_to_compress = [
"text/plain",
"text/html",
"text/css",
"text/javascript",
"application/x-javascript",
"application/javascript",
"application/json",
"application/xml"
]
optimization_type = "GeneralWebDelivery"
geo_filter {
relative_path = "/*"
action = "Allow"
country_codes = ["US", "CA", "GB", "DE"]
}
global_delivery_rule {
cache_expiration_action {
behavior = "SetIfMissing"
duration = "7.00:00:00"
}
modify_request_header_action {
action = "Append"
name = "X-CDN-Header"
value = "Managed by Terraform"
}
}
delivery_rule {
name = "EnforceHTTPS"
order = 1
request_scheme_condition {
operator = "Equal"
match_values = ["HTTP"]
}
url_redirect_action {
redirect_type = "Found"
protocol = "Https"
}
}
delivery_rule {
name = "CacheImages"
order = 2
file_extension_condition {
operator = "Equal"
match_values = ["jpg", "jpeg", "png", "gif"]
}
cache_expiration_action {
behavior = "Override"
duration = "30.00:00:00"
}
}
tags = var.tags
}
# Front Door Profile
resource "azurerm_cdn_frontdoor_profile" "main" {
name = "${var.project_name}-fd"
resource_group_name = var.resource_group_name
sku_name = "Premium_AzureFrontDoor"
tags = var.tags
}
# Front Door Endpoint
resource "azurerm_cdn_frontdoor_endpoint" "main" {
name = "${var.project_name}-fd-endpoint"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
enabled = true
}
# Front Door Origin Group
resource "azurerm_cdn_frontdoor_origin_group" "main" {
name = "${var.project_name}-origin-group"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
load_balancing {
sample_size = 4
successful_samples_required = 3
additional_latency_in_ms = 50
}
health_probe {
interval_in_seconds = 100
path = "/health"
protocol = "Https"
request_type = "HEAD"
}
}
# Front Door Origin
resource "azurerm_cdn_frontdoor_origin" "main" {
name = "${var.project_name}-origin"
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.main.id
enabled = true
host_name = var.origin_hostname
http_port = 80
https_port = 443
origin_host_header = var.origin_hostname
priority = 1
weight = 1000
certificate_name_check_enabled = true
private_link {
request_message = "Request access for Front Door"
target_type = "sites"
location = var.location
private_link_target_id = var.origin_resource_id
}
}
# Front Door Route
resource "azurerm_cdn_frontdoor_route" "main" {
name = "${var.project_name}-route"
cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.main.id
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.main.id
cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.main.id]
supported_protocols = ["Http", "Https"]
patterns_to_match = ["/*"]
forwarding_protocol = "HttpsOnly"
link_to_default_domain = true
https_redirect_enabled = true
cache {
query_string_caching_behavior = "IgnoreSpecifiedQueryStrings"
query_strings = ["account", "settings"]
compression_enabled = true
content_types_to_compress = ["text/html", "text/javascript", "text/css"]
}
}
# WAF Policy
resource "azurerm_cdn_frontdoor_firewall_policy" "main" {
name = "${var.project_name}-waf"
resource_group_name = var.resource_group_name
sku_name = azurerm_cdn_frontdoor_profile.main.sku_name
enabled = true
mode = "Prevention"
managed_rule {
type = "DefaultRuleSet"
version = "1.0"
}
managed_rule {
type = "Microsoft_BotManagerRuleSet"
version = "1.0"
}
custom_rule {
name = "BlockIPRange"
enabled = true
priority = 100
type = "MatchRule"
action = "Block"
match_condition {
match_variable = "RemoteAddr"
operator = "IPMatch"
negation_condition = false
match_values = ["192.168.1.0/24", "10.0.0.0/24"]
}
}
}
# Custom Domain
resource "azurerm_cdn_frontdoor_custom_domain" "main" {
name = "${var.project_name}-domain"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
dns_zone_id = var.dns_zone_id
host_name = "www.example.com"
tls {
certificate_type = "ManagedCertificate"
minimum_tls_version = "TLS12"
}
}
Security Configuration
- Role Assignments
resource "azurerm_role_assignment" "cdn_contributor" {
scope = azurerm_cdn_profile.main.id
role_definition_name = "CDN Profile Contributor"
principal_id = var.contributor_principal_id
}
resource "azurerm_role_assignment" "cdn_endpoint_contributor" {
scope = azurerm_cdn_endpoint.main.id
role_definition_name = "CDN Endpoint Contributor"
principal_id = var.contributor_principal_id
}
- Custom Rules
resource "azurerm_cdn_frontdoor_rule_set" "main" {
name = "${var.project_name}-ruleset"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
}
resource "azurerm_cdn_frontdoor_rule" "redirect" {
name = "redirect-rule"
cdn_frontdoor_rule_set_id = azurerm_cdn_frontdoor_rule_set.main.id
order = 1
behavior_on_match = "Continue"
conditions {
url_path_condition {
operator = "BeginsWith"
negate_condition = false
match_values = ["/old-path/"]
}
}
actions {
url_redirect_action {
redirect_type = "Found"
destination_path = "/new-path/"
destination_protocol = "Https"
}
}
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "cdn" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_cdn_profile.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "FrontDoorAccessLog"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "cdn" {
name = "${var.project_name}-latency-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_cdn_profile.main.id]
description = "Alert when latency is high"
criteria {
metric_namespace = "Microsoft.Cdn/profiles"
metric_name = "TotalLatency"
aggregation = "Average"
operator = "GreaterThan"
threshold = 1000
}
action {
action_group_id = var.action_group_id
}
}
Best Practices
-
Performance
- Enable compression
- Configure caching
- Use custom domains
- Implement rules
-
Security
- Enable WAF
- Use HTTPS
- Configure geo-filtering
- Implement access control
-
Cost Optimization
- Choose appropriate SKU
- Monitor bandwidth usage
- Optimize caching
- Use compression
-
Reliability
- Configure health probes
- Implement load balancing
- Use multiple origins
- Monitor availability
Conclusion
You’ve learned how to set up and manage Azure CDN using Terraform. This setup provides:
- Global content delivery
- Performance optimization
- Security and WAF
- Custom domain support
Remember to:
- Monitor performance
- Review security rules
- Update caching policies
- Manage custom domains