# Enhanced Key Vault Module # Implements Well-Architected Framework best practices for Key Vault variable "resource_group_name" { description = "Name of the resource group" type = string } variable "location" { description = "Azure region" type = string } variable "key_vault_name" { description = "Name of the Key Vault" type = string } variable "environment" { description = "Environment (prod, dev, test, staging)" type = string } variable "enable_rbac" { description = "Enable RBAC authorization (recommended)" type = bool default = true } variable "enable_private_endpoint" { description = "Enable private endpoint" type = bool default = true } variable "private_endpoint_subnet_id" { description = "Subnet ID for private endpoint" type = string default = "" } variable "allowed_subnet_ids" { description = "List of subnet IDs allowed to access Key Vault" type = list(string) default = [] } variable "allowed_ip_ranges" { description = "List of IP ranges allowed to access Key Vault (management)" type = list(string) default = [] } variable "soft_delete_retention_days" { description = "Soft delete retention days" type = number default = 90 } variable "purge_protection_enabled" { description = "Enable purge protection" type = bool default = true } variable "tags" { description = "Tags to apply to Key Vault" type = map(string) default = {} } # Get current client config for RBAC assignments data "azurerm_client_config" "current" {} # Private DNS Zone for Key Vault resource "azurerm_private_dns_zone" "keyvault" { count = var.enable_private_endpoint ? 1 : 0 name = "privatelink.vaultcore.azure.net" resource_group_name = var.resource_group_name tags = var.tags } # Private DNS Zone Virtual Network Link # Note: This requires the virtual network to be in the same resource group or accessible # For production, create the DNS zone link separately or use a shared DNS zone resource "azurerm_private_dns_zone_virtual_network_link" "keyvault" { count = var.enable_private_endpoint && length(var.allowed_subnet_ids) > 0 ? 1 : 0 name = "kv-vnet-link-${replace(var.key_vault_name, "-", "")}" resource_group_name = var.resource_group_name private_dns_zone_name = azurerm_private_dns_zone.keyvault[0].name virtual_network_id = data.azurerm_subnet.main[0].virtual_network_id registration_enabled = false tags = var.tags } # Key Vault resource "azurerm_key_vault" "main" { name = var.key_vault_name location = var.location resource_group_name = var.resource_group_name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = "standard" # Enable RBAC (recommended) enable_rbac_authorization = var.enable_rbac # Soft delete and purge protection soft_delete_retention_days = var.soft_delete_retention_days purge_protection_enabled = var.purge_protection_enabled # Network ACLs (restrict access) network_acls { default_action = "Deny" # Deny by default bypass = "AzureServices" # Allow from specific subnets virtual_network_subnet_ids = var.allowed_subnet_ids # Allow from specific IPs (management) ip_rules = var.allowed_ip_ranges } # Public network access (disable if using private endpoint) public_network_access_enabled = !var.enable_private_endpoint tags = merge(var.tags, { Environment = var.environment Purpose = "Secrets" Security = "High" }) } # Private Endpoint for Key Vault resource "azurerm_private_endpoint" "keyvault" { count = var.enable_private_endpoint && var.private_endpoint_subnet_id != "" ? 1 : 0 name = "${var.key_vault_name}-pe" location = var.location resource_group_name = var.resource_group_name subnet_id = var.private_endpoint_subnet_id private_service_connection { name = "${var.key_vault_name}-psc" private_connection_resource_id = azurerm_key_vault.main.id subresource_names = ["vault"] is_manual_connection = false } private_dns_zone_group { name = "default" private_dns_zone_ids = [azurerm_private_dns_zone.keyvault[0].id] } tags = var.tags } # RBAC Role Assignment (if RBAC enabled) resource "azurerm_role_assignment" "keyvault_administrator" { count = var.enable_rbac ? 1 : 0 scope = azurerm_key_vault.main.id role_definition_name = "Key Vault Administrator" principal_id = data.azurerm_client_config.current.object_id } # Get Virtual Network data (only if subnets are provided) data "azurerm_subnet" "main" { count = length(var.allowed_subnet_ids) > 0 ? 1 : 0 name = split("/", var.allowed_subnet_ids[0])[10] resource_group_name = split("/", var.allowed_subnet_ids[0])[4] virtual_network_name = split("/", var.allowed_subnet_ids[0])[8] } # Outputs output "key_vault_id" { value = azurerm_key_vault.main.id } output "key_vault_name" { value = azurerm_key_vault.main.name } output "key_vault_uri" { value = azurerm_key_vault.main.vault_uri } output "private_endpoint_id" { value = var.enable_private_endpoint && var.private_endpoint_subnet_id != "" ? azurerm_private_endpoint.keyvault[0].id : null }