Managing Azure Cosmos DB with Terraform
Learn how to set up and manage Azure Cosmos DB using Terraform, including multi-region deployment, consistency levels, and backup configurations
Managing Azure Cosmos DB with Terraform
Azure Cosmos DB is a fully managed NoSQL database service. This guide demonstrates how to set up and manage Azure Cosmos DB using Terraform.
Video Tutorial
Learn more about managing Azure Cosmos DB 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 NoSQL database concepts
Project Structure
terraform-azure-cosmos/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── cosmos/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── policies/
└── backup.json
Cosmos DB Configuration
Create modules/cosmos/main.tf
:
# Cosmos DB Account
resource "azurerm_cosmosdb_account" "main" {
name = "${var.project_name}-cosmos"
resource_group_name = var.resource_group_name
location = var.location
offer_type = "Standard"
kind = "GlobalDocumentDB"
enable_automatic_failover = true
enable_multiple_write_locations = true
consistency_policy {
consistency_level = "BoundedStaleness"
max_interval_in_seconds = 300
max_staleness_prefix = 100000
}
geo_location {
location = var.location
failover_priority = 0
}
geo_location {
location = var.secondary_location
failover_priority = 1
}
backup {
type = "Periodic"
interval_in_minutes = 240
retention_in_hours = 8
storage_redundancy = "Geo"
}
identity {
type = "SystemAssigned"
}
capabilities {
name = "EnableServerless"
}
capabilities {
name = "EnableAggregationPipeline"
}
capabilities {
name = "mongoEnableDocLevelTTL"
}
public_network_access_enabled = false
tags = var.tags
}
# SQL Database
resource "azurerm_cosmosdb_sql_database" "main" {
name = var.database_name
resource_group_name = azurerm_cosmosdb_account.main.resource_group_name
account_name = azurerm_cosmosdb_account.main.name
throughput = var.database_throughput
}
# SQL Container
resource "azurerm_cosmosdb_sql_container" "main" {
name = var.container_name
resource_group_name = azurerm_cosmosdb_account.main.resource_group_name
account_name = azurerm_cosmosdb_account.main.name
database_name = azurerm_cosmosdb_sql_database.main.name
partition_key_path = "/partitionKey"
throughput = var.container_throughput
indexing_policy {
indexing_mode = "consistent"
included_path {
path = "/*"
}
excluded_path {
path = "/\"_etag\"/?"
}
}
unique_key {
paths = ["/id"]
}
conflict_resolution_policy {
mode = "LastWriterWins"
conflict_resolution_path = "/_ts"
}
}
# Autoscale Settings
resource "azurerm_cosmosdb_sql_container" "autoscale" {
name = "${var.container_name}-autoscale"
resource_group_name = azurerm_cosmosdb_account.main.resource_group_name
account_name = azurerm_cosmosdb_account.main.name
database_name = azurerm_cosmosdb_sql_database.main.name
partition_key_path = "/partitionKey"
autoscale_settings {
max_throughput = var.max_throughput
}
}
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 = "cosmos-subnet"
address_prefix = "10.0.1.0/24"
service_endpoints = ["Microsoft.AzureCosmosDB"]
}
tags = var.tags
}
resource "azurerm_private_endpoint" "cosmos" {
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_cosmosdb_account.main.id
is_manual_connection = false
subresource_names = ["Sql"]
}
private_dns_zone_group {
name = "default"
private_dns_zone_ids = [azurerm_private_dns_zone.cosmos.id]
}
}
resource "azurerm_private_dns_zone" "cosmos" {
name = "privatelink.documents.azure.com"
resource_group_name = var.resource_group_name
}
resource "azurerm_private_dns_zone_virtual_network_link" "cosmos" {
name = "${var.project_name}-vnet-link"
resource_group_name = var.resource_group_name
private_dns_zone_name = azurerm_private_dns_zone.cosmos.name
virtual_network_id = azurerm_virtual_network.main.id
}
Security Configuration
- Role Assignments
resource "azurerm_role_assignment" "cosmos_contributor" {
scope = azurerm_cosmosdb_account.main.id
role_definition_name = "Cosmos DB Built-in Data Contributor"
principal_id = var.contributor_principal_id
}
resource "azurerm_role_assignment" "cosmos_reader" {
scope = azurerm_cosmosdb_account.main.id
role_definition_name = "Cosmos DB Built-in Data Reader"
principal_id = var.reader_principal_id
}
- Customer-Managed Keys
resource "azurerm_key_vault_key" "cosmos" {
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_cosmosdb_account_customer_managed_key" "main" {
cosmosdb_account_id = azurerm_cosmosdb_account.main.id
key_vault_id = var.key_vault_id
key_name = azurerm_key_vault_key.cosmos.name
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "cosmos" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_cosmosdb_account.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "DataPlaneRequests"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
log {
category = "QueryRuntimeStatistics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "Requests"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "cosmos" {
name = "${var.project_name}-ru-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_cosmosdb_account.main.id]
description = "Alert when RU consumption is high"
criteria {
metric_namespace = "Microsoft.DocumentDB/databaseAccounts"
metric_name = "NormalizedRUConsumption"
aggregation = "Average"
operator = "GreaterThan"
threshold = 80
}
action {
action_group_id = var.action_group_id
}
}
Advanced Features
- Stored Procedures
resource "azurerm_cosmosdb_sql_stored_procedure" "main" {
name = "spExample"
resource_group_name = azurerm_cosmosdb_account.main.resource_group_name
account_name = azurerm_cosmosdb_account.main.name
database_name = azurerm_cosmosdb_sql_database.main.name
container_name = azurerm_cosmosdb_sql_container.main.name
body = <<BODY
function () {
var context = getContext();
var response = context.getResponse();
response.setBody("Hello, World");
}
BODY
}
- Change Feed
resource "azurerm_cosmosdb_sql_container" "change_feed" {
name = "${var.container_name}-changes"
resource_group_name = azurerm_cosmosdb_account.main.resource_group_name
account_name = azurerm_cosmosdb_account.main.name
database_name = azurerm_cosmosdb_sql_database.main.name
partition_key_path = "/partitionKey"
change_feed_policy {
retention_duration = "P1D"
}
}
Best Practices
-
Performance
- Choose appropriate consistency level
- Design efficient partition keys
- Use indexing policies
- Monitor RU consumption
-
Security
- Enable private endpoints
- Use RBAC
- Enable encryption
- Implement network isolation
-
High Availability
- Enable multi-region writes
- Configure automatic failover
- Use geo-redundant backups
- Monitor health
-
Cost Optimization
- Choose consistency level
- Optimize queries
- Choose appropriate APIs
Conclusion
You’ve learned how to set up and manage Azure Cosmos DB using Terraform. This setup provides:
- Multi-region deployment
- Security and encryption
- Monitoring and alerts
- Backup and disaster recovery
Remember to:
- Monitor RU consumption
- Review security settings
- Maintain backups
- Update access controls