YouTube Video YouTube Video

Source Code

Welcome to the third episode of Azure Terraformer, where we dive deep into using Terraform on Azure to set up powerful, scalable cloud solutions. Today, we’ll be setting up a basic secrets management with Azure Keyvault. Creating and managing an Azure Key Vault with Terraform is both straightforward and flexible, especially when you utilize an independent resource block structure. In this article, I’ll demonstrate how to set up an Azure Key Vault using the Azurerm provider, with unique resource names generated dynamically to avoid naming conflicts. Additionally, I’ll show how to connect the Key Vault to an existing observability stack, enabling Azure Monitor diagnostics by referencing preconfigured storage accounts and log analytics workspaces. Using this modular setup, you can seamlessly scale and adapt as requirements change, knowing each component remains independently manageable.

Step 1: Create the Resource Group

To start, every Azure resource needs a resource group as its container. By adding a random_string resource to generate a dynamic suffix, we ensure that each resource group name remains unique, which is particularly helpful in shared environments or in CI/CD pipelines where naming conflicts can arise.

resource "random_string" "main" {
  length  = 8
  upper   = false
  special = false
}

resource "azurerm_resource_group" "main" {
  name     = "rg-ep3-${random_string.main.result}"
  location = var.location
}

This configuration defines the resource group with a base name of rg-ep3- appended with an eight-character random string. It provides an isolated scope for all subsequent resources, making it simple to identify which resources belong to this environment.

Step 2: Define the Key Vault

Once the resource group is ready, we define the Azure Key Vault. Using a similar random string suffix as the resource group ensures our Key Vault name is unique across our environment. Key Vault’s role here is straightforward: it securely stores secrets, keys, and certificates. For this example, I’ll configure the Key Vault with the standard SKU and disable purge protection for simplicity.

resource "azurerm_key_vault" "main" {
  name                     = "kv-ep3-${random_string.main.result}"
  location                 = azurerm_resource_group.main.location
  resource_group_name      = azurerm_resource_group.main.name
  tenant_id                = data.azurerm_client_config.current.tenant_id
  purge_protection_enabled = false

  sku_name = "standard"
}

Here, I’ve used the azurerm_client_config data source to fetch the current tenant ID dynamically. This approach provides flexibility, allowing the Key Vault to function correctly within the associated Azure tenant without hardcoding values. By isolating the Key Vault configuration, we retain the freedom to modify its settings without affecting the overall resource group or other resources.

Step 3: Configure Access Policies

For the Key Vault to be fully manageable by Terraform, it needs an access policy that allows the current identity to perform necessary operations. Using the azurerm_client_config data source, I retrieve the identity information, including the tenant ID and object ID, to set up the access policy for managing secrets within the Key Vault.

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault_access_policy" "terraform_user" {
  key_vault_id = azurerm_key_vault.main.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id

  secret_permissions = [
    "Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set"
  ]
}

This access policy provides the necessary permissions for Terraform to manage Key Vault secrets. Using the object_id of the current client identity ensures that Terraform, and only Terraform, has these permissions—helping maintain a secure boundary around the Key Vault.

Step 4: Connect Key Vault to Azure Monitor via Diagnostic Settings

To enable observability for our Key Vault, we’ll set up diagnostic settings that direct logs and metrics to Azure Monitor. For this, I’m leveraging existing observability resources: a log analytics workspace and a storage account. I’ll use data sources to reference these preexisting resources, tying everything together seamlessly.

First, we define the data sources for the existing storage account and log analytics workspace. By extracting the random suffix into a local variable, I keep the naming scheme consistent and avoid hardcoding details unnecessarily.

locals {
  monitor_suffix = "a6ipu10e"
}

data "azurerm_storage_account" "monitor" {
  name                = "st${local.monitor_suffix}"
  resource_group_name = "rg-ep1-${local.monitor_suffix}"
}

data "azurerm_log_analytics_workspace" "monitor" {
  name                = "log-ep1-${local.monitor_suffix}"
  resource_group_name = "rg-ep1-${local.monitor_suffix}"
}

With these references in place, we configure the diagnostic settings for the Key Vault. By specifying categories for logs and metrics, we define exactly which data Azure Monitor will collect, ensuring we capture all relevant activity for our Key Vault.

resource "azurerm_monitor_diagnostic_setting" "activity_logs" {
  name                       = "diag-${random_string.keyvault_monitor.result}"
  target_resource_id         = azurerm_key_vault.main.id
  storage_account_id         = data.azurerm_storage_account.monitor.id
  log_analytics_workspace_id = data.azurerm_log_analytics_workspace.monitor.id

  enabled_log {
    category_group = "audit"
  }
  enabled_log {
    category_group = "allLogs"
  }
  metric {
    category = "AllMetrics"
  }
}

By specifying logs and metrics separately, we maintain control over which types of data are sent to Azure Monitor. This configuration not only makes it easier to troubleshoot and monitor the Key Vault but also keeps observability adaptable to future changes in logging or monitoring requirements.

Conclusion

This Terraform configuration demonstrates a flexible, modular approach to managing Azure Key Vault and its observability settings. Each resource is structured independently, keeping the configuration adaptable as requirements evolve. By utilizing dynamic naming and referencing existing observability resources, this setup avoids naming conflicts and supports streamlined logging and monitoring integration. As the need for secrets management grows, this configuration provides a scalable foundation that remains efficient and manageable, supporting a consistent and secure infrastructure.

Happy Azure Terraforming!