Managing Azure API Management with Terraform
Learn how to set up and manage Azure API Management using Terraform, including APIs, policies, and security configurations
Managing Azure API Management with Terraform
Azure API Management (APIM) is a fully managed service that helps organizations publish, secure, transform, maintain, and monitor APIs. This guide demonstrates how to set up and manage APIM using Terraform.
Video Tutorial
Learn more about managing Azure API Management 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 API management concepts
Project Structure
terraform-azure-apim/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── apim/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── policies/
├── global.xml
├── product.xml
└── api.xml
API Management Configuration
Create modules/apim/main.tf
:
# API Management Service
resource "azurerm_api_management" "main" {
name = "${var.project_name}-apim"
location = var.location
resource_group_name = var.resource_group_name
publisher_name = var.publisher_name
publisher_email = var.publisher_email
sku_name = "Premium_1"
zones = ["1", "2", "3"]
identity {
type = "SystemAssigned"
}
hostname_configuration {
proxy {
host_name = "api.${var.domain_name}"
key_vault_id = azurerm_key_vault_certificate.api.id
default_ssl_binding = true
negotiate_client_certificate = false
}
portal {
host_name = "portal.${var.domain_name}"
key_vault_id = azurerm_key_vault_certificate.portal.id
}
developer_portal {
host_name = "developer.${var.domain_name}"
key_vault_id = azurerm_key_vault_certificate.developer.id
}
}
security {
enable_backend_ssl30 = false
enable_backend_tls10 = false
enable_backend_tls11 = false
enable_frontend_ssl30 = false
enable_frontend_tls10 = false
enable_frontend_tls11 = false
enable_http2 = true
}
protocols {
enable_http2 = true
}
sign_in {
enabled = true
}
sign_up {
enabled = true
terms_of_service {
enabled = true
consent_required = true
text = file("${path.module}/terms.html")
}
}
public_network_access_enabled = false
virtual_network_configuration {
subnet_id = azurerm_subnet.apim.id
}
tags = var.tags
}
# Products
resource "azurerm_api_management_product" "main" {
for_each = var.products
product_id = each.key
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
display_name = each.value.display_name
description = each.value.description
subscription_required = true
approval_required = each.value.approval_required
published = true
}
# APIs
resource "azurerm_api_management_api" "main" {
for_each = var.apis
name = each.key
resource_group_name = var.resource_group_name
api_management_name = azurerm_api_management.main.name
revision = "1"
display_name = each.value.display_name
path = each.value.path
protocols = ["https"]
service_url = each.value.backend_url
import {
content_format = "openapi+json"
content_value = file(each.value.swagger_path)
}
subscription_key_parameter_names {
header = "Ocp-Apim-Subscription-Key"
query = "subscription-key"
}
}
# API Policy
resource "azurerm_api_management_api_policy" "main" {
for_each = var.apis
api_name = azurerm_api_management_api.main[each.key].name
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
xml_content = file("${path.module}/policies/api/${each.key}.xml")
}
# Product Policy
resource "azurerm_api_management_product_policy" "main" {
for_each = var.products
product_id = azurerm_api_management_product.main[each.key].product_id
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
xml_content = file("${path.module}/policies/product/${each.key}.xml")
}
# Global Policy
resource "azurerm_api_management_policy" "main" {
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
xml_content = file("${path.module}/policies/global.xml")
}
# Named Values
resource "azurerm_api_management_named_value" "main" {
for_each = var.named_values
name = each.key
resource_group_name = var.resource_group_name
api_management_name = azurerm_api_management.main.name
display_name = each.value.display_name
secret = each.value.secret
value = each.value.secret ? data.azurerm_key_vault_secret.named_values[each.key].value : each.value.value
}
# Logger
resource "azurerm_api_management_logger" "main" {
name = "${var.project_name}-logger"
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
resource_id = azurerm_application_insights.main.id
application_insights {
instrumentation_key = azurerm_application_insights.main.instrumentation_key
}
}
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 = "apim-subnet"
address_prefix = "10.0.1.0/24"
service_endpoints = [
"Microsoft.KeyVault",
"Microsoft.EventHub",
"Microsoft.ServiceBus",
"Microsoft.Sql"
]
}
tags = var.tags
}
resource "azurerm_private_endpoint" "apim" {
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_api_management.main.id
is_manual_connection = false
subresource_names = ["gateway"]
}
private_dns_zone_group {
name = "default"
private_dns_zone_ids = [azurerm_private_dns_zone.apim.id]
}
}
resource "azurerm_private_dns_zone" "apim" {
name = "privatelink.azure-api.net"
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "apim" {
name = "${var.project_name}-vnet-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.apim.name
virtual_network_id = azurerm_virtual_network.main.id
}
Security Configuration
- Role Assignments
resource "azurerm_role_assignment" "apim_contributor" {
scope = azurerm_api_management.main.id
role_definition_name = "API Management Service Contributor"
principal_id = var.contributor_principal_id
}
resource "azurerm_role_assignment" "apim_reader" {
scope = azurerm_api_management.main.id
role_definition_name = "API Management Service Reader Role"
principal_id = var.reader_principal_id
}
- Managed Identity
resource "azurerm_user_assigned_identity" "apim" {
name = "${var.project_name}-identity"
resource_group_name = var.resource_group_name
location = var.location
}
resource "azurerm_key_vault_access_policy" "apim" {
key_vault_id = var.key_vault_id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_user_assigned_identity.apim.principal_id
certificate_permissions = [
"Get",
"List"
]
secret_permissions = [
"Get",
"List"
]
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "apim" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_api_management.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "GatewayLogs"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "apim" {
name = "${var.project_name}-latency-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_api_management.main.id]
description = "Alert when API latency is high"
criteria {
metric_namespace = "Microsoft.ApiManagement/service"
metric_name = "Duration"
aggregation = "Average"
operator = "GreaterThan"
threshold = 1000
}
action {
action_group_id = var.action_group_id
}
}
Advanced Features
- OAuth2 Configuration
resource "azurerm_api_management_authorization_server" "main" {
name = "oauth2"
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
display_name = "OAuth 2.0 Authorization Server"
authorization_endpoint = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/v2.0/authorize"
token_endpoint = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}/oauth2/v2.0/token"
client_registration_endpoint = "https://portal.${var.domain_name}/signup"
grant_types = ["authorization_code", "implicit", "client_credentials"]
authorization_methods = ["GET", "POST"]
client_authentication_method = ["Basic"]
bearer_token_sending_methods = ["authorizationHeader"]
}
- Cache Configuration
resource "azurerm_api_management_cache" "main" {
name = "${var.project_name}-cache"
api_management_name = azurerm_api_management.main.name
resource_group_name = var.resource_group_name
location = var.location
connection_string = azurerm_redis_cache.main.primary_connection_string
description = "API response cache"
use_from_location = var.location
}
Best Practices
-
Performance
- Use caching
- Enable HTTP/2
- Configure rate limiting
- Monitor latency
-
Security
- Enable private endpoints
- Use RBAC
- Implement OAuth2
- Enable TLS 1.2+
-
Monitoring
- Configure logging
- Set up alerts
- Monitor usage
- Track errors
-
Cost Optimization
- Monitor usage
- Use caching
- Optimize policies
Conclusion
You’ve learned how to set up and manage Azure API Management using Terraform. This setup provides:
- API gateway functionality
- Security and policies
- Monitoring and caching
- Developer portal
Remember to:
- Monitor API usage
- Review security settings
- Update policies
- Maintain documentation