Managing Azure Cache for Redis with Terraform

Learn how to set up and manage Azure Cache for Redis using Terraform, including clustering, persistence, and security configurations

Managing Azure Cache for Redis with Terraform

Azure Cache for Redis is a fully managed, in-memory data store based on Redis. This guide demonstrates how to set up and manage Azure Cache for Redis using Terraform.

Video Tutorial

Learn more about managing Azure Cache for Redis 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 Redis concepts

Project Structure

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

Redis Cache Configuration

Create modules/redis/main.tf:

# Redis Cache
resource "azurerm_redis_cache" "main" {
  name                = "${var.project_name}-redis"
  location            = var.location
  resource_group_name = var.resource_group_name
  capacity            = var.capacity
  family              = "P"
  sku_name            = "Premium"
  enable_non_ssl_port = false
  minimum_tls_version = "1.2"

  redis_configuration {
    enable_authentication           = true
    maxmemory_reserved             = 2
    maxmemory_delta                = 2
    maxmemory_policy               = "volatile-lru"
    maxfragmentationmemory_reserved = 2

    # Premium features
    aof_backup_enabled              = true
    aof_storage_connection_string_0 = azurerm_storage_account.redis.primary_blob_connection_string
    rdb_backup_enabled              = true
    rdb_backup_frequency           = 60
    rdb_backup_max_snapshot_count  = 1
    rdb_storage_connection_string_0 = azurerm_storage_account.redis.primary_blob_connection_string
  }

  patch_schedule {
    day_of_week    = "Sunday"
    start_hour_utc = 2
  }

  identity {
    type = "SystemAssigned"
  }

  public_network_access_enabled = false

  tags = var.tags
}

# Storage Account for Backup
resource "azurerm_storage_account" "redis" {
  name                     = "${var.project_name}redis"
  resource_group_name      = var.resource_group_name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = "GRS"

  min_tls_version         = "TLS1_2"
  enable_https_traffic_only = true

  network_rules {
    default_action = "Deny"
    ip_rules       = var.allowed_ip_ranges
    virtual_network_subnet_ids = [azurerm_subnet.redis.id]
    bypass         = ["AzureServices"]
  }

  identity {
    type = "SystemAssigned"
  }

  tags = var.tags
}

# Redis Enterprise Cluster
resource "azurerm_redis_enterprise_cluster" "main" {
  name                = "${var.project_name}-redis-enterprise"
  resource_group_name = var.resource_group_name
  location            = var.location
  sku_name           = "Enterprise_E10"
  zones              = ["1", "2", "3"]

  minimum_tls_version = "1.2"

  identity {
    type = "SystemAssigned"
  }

  tags = var.tags
}

# Redis Enterprise Database
resource "azurerm_redis_enterprise_database" "main" {
  name                = "default"
  cluster_id          = azurerm_redis_enterprise_cluster.main.id
  client_protocol     = "Encrypted"
  clustering_enabled  = true
  eviction_policy    = "volatile-lru"
  module {
    name    = "RediSearch"
    args    = "PARTITIONS AUTO"
  }
  module {
    name    = "RedisJSON"
  }
}

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           = "redis-subnet"
    address_prefix = "10.0.1.0/24"
    service_endpoints = ["Microsoft.Cache"]
  }

  tags = var.tags
}

resource "azurerm_private_endpoint" "redis" {
  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_redis_cache.main.id
    is_manual_connection          = false
    subresource_names            = ["redisCache"]
  }

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

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

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

Security Configuration

  1. Firewall Rules
resource "azurerm_redis_firewall_rule" "main" {
  for_each = var.firewall_rules

  name                = each.key
  redis_cache_name    = azurerm_redis_cache.main.name
  resource_group_name = var.resource_group_name
  start_ip           = each.value.start_ip
  end_ip             = each.value.end_ip
}
  1. Customer-Managed Keys
resource "azurerm_key_vault_key" "redis" {
  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_redis_cache_customer_managed_key" "main" {
  redis_cache_id   = azurerm_redis_cache.main.id
  key_vault_id     = var.key_vault_id
  key_name         = azurerm_key_vault_key.redis.name
  key_version      = azurerm_key_vault_key.redis.version
}

Monitoring Configuration

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

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

resource "azurerm_monitor_metric_alert" "redis" {
  name                = "${var.project_name}-memory-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_redis_cache.main.id]
  description         = "Alert when memory usage is high"

  criteria {
    metric_namespace = "Microsoft.Cache/redis"
    metric_name      = "usedmemorypercentage"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 80
  }

  action {
    action_group_id = var.action_group_id
  }
}

Advanced Features

  1. Clustering
resource "azurerm_redis_cache" "cluster" {
  # ... other configuration ...

  shard_count = 3
  
  redis_configuration {
    enable_authentication = true
    maxmemory_policy     = "volatile-lru"
    cluster_enabled      = true
  }
}
  1. Geo-Replication
resource "azurerm_redis_cache" "secondary" {
  # ... other configuration ...

  redis_configuration {
    rdb_backup_enabled            = true
    rdb_backup_frequency         = 60
    rdb_backup_max_snapshot_count = 1
    rdb_storage_connection_string = azurerm_storage_account.redis.primary_blob_connection_string
  }
}

resource "azurerm_redis_linked_server" "geo_replication" {
  target_redis_cache_name     = azurerm_redis_cache.secondary.name
  target_redis_cache_location = azurerm_redis_cache.secondary.location
  resource_group_name         = var.resource_group_name
  linked_redis_cache_id      = azurerm_redis_cache.main.id
  server_role                = "Secondary"
}

Best Practices

  1. Performance

    • Choose appropriate size
    • Enable clustering
    • Use connection pooling
    • Monitor memory usage
  2. Security

    • Enable private endpoints
    • Use SSL/TLS
    • Implement firewall rules
    • Enable encryption
  3. High Availability

    • Use Premium tier
    • Enable persistence
    • Configure geo-replication
    • Monitor health
  4. Cost Optimization

    • Use appropriate tier
    • Clean up unused data

Conclusion

You’ve learned how to set up and manage Azure Cache for Redis using Terraform. This setup provides:

  • High availability
  • Security and encryption
  • Monitoring and alerts
  • Backup and persistence

Remember to:

  • Monitor memory usage
  • Review security settings
  • Maintain backups
  • Update access controls