diff --git a/examples/private_dns_zones.tfvars b/examples/private_dns_zones.tfvars new file mode 100644 index 00000000..07744f46 --- /dev/null +++ b/examples/private_dns_zones.tfvars @@ -0,0 +1,44 @@ +private_dns_zones = { + storage_account_blob = { + resource_kind = "storage_blob" + resource_group_ref = "rg_test" + vnet_ref = ["vnet_test", "vnet_test2"] + } +} + + + +# pre-requisites +resource_groups = { + rg_test = { + name = "rg-test-dv-ne-01" + location = "northeurope" + } +} + +virtual_networks = { + vnet_test = { + name = "vnet-test-dv-ne-01" + resource_group_ref = "rg_test" + cidr = ["10.0.0.0/16"] + subnets = { + snet_app = { + name = "snet-app" + cidr = ["10.0.0.128/25"] + service_endpoints = ["Microsoft.Storage"] + } + } + } + vnet_test2 = { + name = "vnet-test-dv-ne-02" + resource_group_ref = "rg_test" + cidr = ["10.1.0.0/16"] + subnets = { + snet_app_02 = { + name = "snet-app" + cidr = ["10.1.0.128/25"] + service_endpoints = ["Microsoft.Storage"] + } + } + } +} diff --git a/src/_variables.resources.tf b/src/_variables.resources.tf index e3876f54..51727857 100644 --- a/src/_variables.resources.tf +++ b/src/_variables.resources.tf @@ -15,3 +15,5 @@ variable "public_ips" { default = {} } variable "keyvaults" { default = {} } variable "storage_accounts" { default = {} } + +variable "private_dns_zones" { default = {} } diff --git a/src/keyvault.tf b/src/keyvault.tf index 7a0d8da6..2aa9e48e 100644 --- a/src/keyvault.tf +++ b/src/keyvault.tf @@ -1,5 +1,5 @@ module "keyvaults" { - source = "./modules/_security/keyvault" + source = "./modules/keyvault" for_each = var.keyvaults settings = each.value @@ -8,5 +8,6 @@ module "keyvaults" { virtual_networks = module.virtual_networks resource_groups = module.resource_groups managed_identities = module.managed_identities + private_dns_zones = module.private_dns_zones } } diff --git a/src/modules/_networking/private_dns_zone/_locals.tf b/src/modules/_networking/private_dns_zone/_locals.tf new file mode 100644 index 00000000..53c86680 --- /dev/null +++ b/src/modules/_networking/private_dns_zone/_locals.tf @@ -0,0 +1,29 @@ +locals { + resource_group = var.resources.resource_groups[var.settings.resource_group_ref] + + resource_group_name = local.resource_group.name + location = local.resource_group.location + tags = merge( + var.global_settings.tags, + var.global_settings.inherit_resource_group_tags ? local.resource_group.tags : {}, + try(var.settings.tags, {}) + ) + vnet_ids = { + for vnet in var.settings.vnet_ref : + vnet => { + name = var.resources.virtual_networks[vnet].name + id = var.resources.virtual_networks[vnet].id + } + } +} +locals { + # local object used to map possible private dns zoone names + zone_names = { + "storage_blob" = "privatelink.blob.core.windows.net" + "storage_tables" = "privatelink.table.core.windows.net" + "storage_queues" = "privatelink.queue.core.windows.net" + "storage_files" = "privatelink.file.core.windows.net" + "function_apps" = "privatelink.azurewebsites.net" + "keyvaults" = "privatelink.vaultcore.azure.net" + } +} diff --git a/src/modules/_networking/private_dns_zone/_outputs.tf b/src/modules/_networking/private_dns_zone/_outputs.tf new file mode 100644 index 00000000..0d4f3d12 --- /dev/null +++ b/src/modules/_networking/private_dns_zone/_outputs.tf @@ -0,0 +1,3 @@ +output "id" { + value = azurerm_private_dns_zone.main.id +} diff --git a/src/modules/_networking/private_dns_zone/_variables.tf b/src/modules/_networking/private_dns_zone/_variables.tf new file mode 100644 index 00000000..4ee12d7c --- /dev/null +++ b/src/modules/_networking/private_dns_zone/_variables.tf @@ -0,0 +1,15 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + type = object({ + resource_groups = map(any) + virtual_networks = map(any) + }) + description = "All required resources" +} diff --git a/src/modules/_networking/private_dns_zone/private_dns_vnet_link.tf b/src/modules/_networking/private_dns_zone/private_dns_vnet_link.tf new file mode 100644 index 00000000..08444fe8 --- /dev/null +++ b/src/modules/_networking/private_dns_zone/private_dns_vnet_link.tf @@ -0,0 +1,7 @@ +resource "azurerm_private_dns_zone_virtual_network_link" "main" { + for_each = local.vnet_ids + name = "${each.value.name}-${azurerm_private_dns_zone.main.name}-link" + private_dns_zone_name = azurerm_private_dns_zone.main.name + resource_group_name = azurerm_private_dns_zone.main.resource_group_name + virtual_network_id = each.value.id +} diff --git a/src/modules/_networking/private_dns_zone/private_dns_zone_group.tf b/src/modules/_networking/private_dns_zone/private_dns_zone_group.tf new file mode 100644 index 00000000..69fc0fb5 --- /dev/null +++ b/src/modules/_networking/private_dns_zone/private_dns_zone_group.tf @@ -0,0 +1,5 @@ +resource "azurerm_private_dns_zone" "main" { + name = try(local.zone_names[var.settings.resource_kind], var.settings.name) + resource_group_name = local.resource_group_name + tags = try(local.tags, null) +} diff --git a/src/modules/_security/keyvault/_outputs.tf b/src/modules/_security/keyvault/_outputs.tf deleted file mode 100644 index fda15d89..00000000 --- a/src/modules/_security/keyvault/_outputs.tf +++ /dev/null @@ -1,7 +0,0 @@ -output "id" { - value = azurerm_key_vault.main.id -} - -output "vault_uri" { - value = azurerm_key_vault.main.vault_uri -} diff --git a/src/modules/_security/keyvault/access_policies.tf b/src/modules/_security/keyvault/access_policies.tf deleted file mode 100644 index a12b6381..00000000 --- a/src/modules/_security/keyvault/access_policies.tf +++ /dev/null @@ -1,24 +0,0 @@ -resource "azurerm_key_vault_access_policy" "logged_in_user" { - key_vault_id = azurerm_key_vault.main.id - tenant_id = var.global_settings.tenant_id - object_id = var.global_settings.object_id - - secret_permissions = local.all_secret_permissions - key_permissions = local.all_key_permissions -} - -resource "azurerm_key_vault_access_policy" "managed_identity" { - for_each = { - for access_policy_ref, config in var.settings.access_policies : - access_policy_ref => config - if can(config.managed_identity_ref) - } - key_vault_id = azurerm_key_vault.main.id - tenant_id = var.global_settings.tenant_id - object_id = var.resources.managed_identities[each.value.managed_identity_ref].principal_id - - # this is a bit of a hack to allow `secret_permissions` to be a string when "All" and otherwise a list - # the tfvars allows it, but the module needs us to convert it to list explicitly to get around the type errors - secret_permissions = try(each.value.secret_permissions, null) == "All" ? local.all_secret_permissions : try(tolist(each.value.secret_permissions), []) - key_permissions = try(each.value.key_permissions, null) == "All" ? local.all_key_permissions : try(tolist(each.value.key_permissions), []) -} diff --git a/src/modules/_security/keyvault/_locals.tf b/src/modules/keyvault/_locals.tf similarity index 54% rename from src/modules/_security/keyvault/_locals.tf rename to src/modules/keyvault/_locals.tf index 3d5dc992..6b55ec36 100644 --- a/src/modules/_security/keyvault/_locals.tf +++ b/src/modules/keyvault/_locals.tf @@ -9,47 +9,13 @@ locals { var.resources.virtual_networks[split("/", config.subnet_ref)[0]].subnets[split("/", config.subnet_ref)[1]].id ) ] - + subnet_id = try( + var.resources.virtual_networks[split("/", var.settings.private_endpoint.subnet_ref)[0]].subnets[split("/", var.settings.private_endpoint.subnet_ref)[1]].id, + null + ) tags = merge( var.global_settings.tags, var.global_settings.inherit_resource_group_tags ? local.resource_group.tags : {}, try(var.settings.tags, {}) ) } - - -locals { - all_secret_permissions = [ - "Backup", - "Delete", - "Get", - "List", - "Purge", - "Recover", - "Restore", - "Set", - ] - - all_key_permissions = [ - "Backup", - "Create", - "Decrypt", - "Delete", - "Encrypt", - "Get", - "Import", - "List", - "Purge", - "Recover", - "Restore", - "Sign", - "UnwrapKey", - "Update", - "Verify", - "WrapKey", - "Release", - "Rotate", - "GetRotationPolicy", - "SetRotationPolicy", - ] -} diff --git a/src/modules/keyvault/_outputs.tf b/src/modules/keyvault/_outputs.tf new file mode 100644 index 00000000..6348558b --- /dev/null +++ b/src/modules/keyvault/_outputs.tf @@ -0,0 +1,23 @@ +output "id" { + value = azurerm_key_vault.main.id +} + +output "vault_uri" { + value = azurerm_key_vault.main.vault_uri +} + +output "resource_group_name" { + value = azurerm_key_vault.main.resource_group_name +} + +output "location" { + value = azurerm_key_vault.main.location +} + +output "name" { + value = azurerm_key_vault.main.name +} + +output "resources" { + value = var.resources +} diff --git a/src/modules/_security/keyvault/_variables.tf b/src/modules/keyvault/_variables.tf similarity index 90% rename from src/modules/_security/keyvault/_variables.tf rename to src/modules/keyvault/_variables.tf index 6edf68ec..571a0d89 100644 --- a/src/modules/_security/keyvault/_variables.tf +++ b/src/modules/keyvault/_variables.tf @@ -6,11 +6,13 @@ variable "settings" { description = "All the configuration for this resource" } + variable "resources" { type = object({ resource_groups = map(any) virtual_networks = map(any) managed_identities = map(any) + private_dns_zones = map(any) }) description = "All required resources" } diff --git a/src/modules/keyvault/access_policies.tf b/src/modules/keyvault/access_policies.tf new file mode 100644 index 00000000..75c0f161 --- /dev/null +++ b/src/modules/keyvault/access_policies.tf @@ -0,0 +1,11 @@ +module "initial_policy" { + source = "./keyvault_access_policy" + for_each = try(var.settings.access_policies, {}) + + settings = var.settings + keyvault_id = azurerm_key_vault.main.id + access_policies = each.value + policy_name = each.key + global_settings = var.global_settings + resources = var.resources +} diff --git a/src/modules/_security/keyvault/keyvault.tf b/src/modules/keyvault/keyvault.tf similarity index 100% rename from src/modules/_security/keyvault/keyvault.tf rename to src/modules/keyvault/keyvault.tf diff --git a/src/modules/keyvault/keyvault_access_policy/_locals.tf b/src/modules/keyvault/keyvault_access_policy/_locals.tf new file mode 100644 index 00000000..8f902e38 --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/_locals.tf @@ -0,0 +1,55 @@ +locals { + all_secret_permissions = [ + "Backup", + "Delete", + "Get", + "List", + "Purge", + "Recover", + "Restore", + "Set", + ] + + all_key_permissions = [ + "Backup", + "Create", + "Decrypt", + "Delete", + "Encrypt", + "Get", + "Import", + "List", + "Purge", + "Recover", + "Restore", + "Sign", + "UnwrapKey", + "Update", + "Verify", + "WrapKey", + "Release", + "Rotate", + "GetRotationPolicy", + "SetRotationPolicy", + ] +} + +locals { + effective_key_permissions = ( + var.access_policies.key_permissions == "All" ? + local.all_key_permissions : + tolist(try(var.access_policies.key_permissions, [])) + ) + + effective_secret_permissions = ( + var.access_policies.secret_permissions == "All" ? + local.all_secret_permissions : + tolist(try(var.access_policies.secret_permissions, [])) + ) +} + + +locals { + debug_settings = var.settings + has_logged_in_key = contains(keys(var.settings), "managed_identity") +} diff --git a/src/modules/keyvault/keyvault_access_policy/_outputs.tf b/src/modules/keyvault/keyvault_access_policy/_outputs.tf new file mode 100644 index 00000000..3adbdac8 --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/_outputs.tf @@ -0,0 +1,3 @@ +output "debug" { + value = local.debug_settings +} diff --git a/src/modules/keyvault/keyvault_access_policy/_variables.tf b/src/modules/keyvault/keyvault_access_policy/_variables.tf new file mode 100644 index 00000000..bd4ad120 --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/_variables.tf @@ -0,0 +1,26 @@ +variable "settings" { + description = "All the configuration for this resource" +} + +variable "keyvault_id" { + description = "keyvault id" +} + +variable "access_policies" { + validation { + condition = length(var.access_policies) <= 16 + error_message = "A maximun of 16 access policies can be set." + } +} +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "policy_name" { + description = "The key of the access policy." + type = string +} + +variable "resources" { + description = "All the configuration for this resource" +} diff --git a/src/modules/keyvault/keyvault_access_policy/access_policies.tf b/src/modules/keyvault/keyvault_access_policy/access_policies.tf new file mode 100644 index 00000000..97a2673d --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/access_policies.tf @@ -0,0 +1,23 @@ +module "logged_in_user" { + source = "./access_policy" + count = var.policy_name == "logged_in_user" ? 1 : 0 + keyvault_id = var.keyvault_id == null + tenant_id = var.global_settings.tenant_id + access_policies = try(var.access_policies,null) + object_id = var.global_settings.object_id + key_permissions = local.all_key_permissions + secret_permissions = local.all_secret_permissions +} + + +module "managed_identities" { + source = "./access_policy" + for_each = var.policy_name == "managed_identity" && length(try(var.access_policies.managed_identity_refs, [])) > 0 ? { for idx, ref in try(var.access_policies.managed_identity_refs, []) : idx => ref } : {} + + keyvault_id = var.keyvault_id + access_policies = var.access_policies + tenant_id = var.global_settings.tenant_id + object_id = var.resources.managed_identities[each.value].id + key_permissions = local.effective_key_permissions + secret_permissions = local.effective_secret_permissions +} diff --git a/src/modules/keyvault/keyvault_access_policy/access_policy/_variables.tf b/src/modules/keyvault/keyvault_access_policy/access_policy/_variables.tf new file mode 100644 index 00000000..4a859544 --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/access_policy/_variables.tf @@ -0,0 +1,6 @@ +variable "keyvault_id" {} +variable "tenant_id" {} +variable "object_id" {} +variable "key_permissions" {} +variable "secret_permissions" {} +variable "access_policies" {} diff --git a/src/modules/keyvault/keyvault_access_policy/access_policy/access_policy.tf b/src/modules/keyvault/keyvault_access_policy/access_policy/access_policy.tf new file mode 100644 index 00000000..b962091f --- /dev/null +++ b/src/modules/keyvault/keyvault_access_policy/access_policy/access_policy.tf @@ -0,0 +1,9 @@ +resource "azurerm_key_vault_access_policy" "main" { # Using the policy key in the resource name + key_vault_id = var.keyvault_id + + tenant_id = var.tenant_id + object_id = var.object_id + + key_permissions = var.key_permissions + secret_permissions = var.secret_permissions +} diff --git a/src/modules/keyvault/keyvault_private_endpoint/_locals.tf b/src/modules/keyvault/keyvault_private_endpoint/_locals.tf new file mode 100644 index 00000000..7eef42b0 --- /dev/null +++ b/src/modules/keyvault/keyvault_private_endpoint/_locals.tf @@ -0,0 +1,23 @@ +locals { + subnet_ids = [ + for network_rule_ref, config in try(var.settings.network_rules.subnets, {}) : ( + var.resources.virtual_networks[split("/", config.subnet_ref)[0]].subnets[split("/", config.subnet_ref)[1]].id + ) + ] + subnet_id = try( + var.resources.virtual_networks[split("/", var.settings.private_endpoint.subnet_ref)[0]].subnets[split("/", var.settings.private_endpoint.subnet_ref)[1]].id, + null + ) + tags = merge( + var.global_settings.tags, + var.global_settings.inherit_resource_group_tags ? local.resource_group.tags : {}, + try(var.settings.tags, {}) + ) +} + +locals { + dns_zone_ids = try([ + for zone in var.settings.private_endpoint.dns_zones_ref : + var.resources.private_dns_zones[zone].id + ], []) +} diff --git a/src/modules/keyvault/keyvault_private_endpoint/_variables.tf b/src/modules/keyvault/keyvault_private_endpoint/_variables.tf new file mode 100644 index 00000000..d5fbb872 --- /dev/null +++ b/src/modules/keyvault/keyvault_private_endpoint/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + type = object({ + keyvaults = map(any) + virtual_networks = map(any) + managed_identities = map(any) + private_dns_zones = map(any) + + }) + description = "All required resources" +} diff --git a/src/modules/keyvault/keyvault_private_endpoint/private_endpoint.tf b/src/modules/keyvault/keyvault_private_endpoint/private_endpoint.tf new file mode 100644 index 00000000..23cf3359 --- /dev/null +++ b/src/modules/keyvault/keyvault_private_endpoint/private_endpoint.tf @@ -0,0 +1,26 @@ +resource "azurerm_private_endpoint" "main" { + for_each = { + for key, value in var.resources.keyvaults : + key => value + if try(var.settings.private_endpoint, null) != null + } + name = "pe-${each.value.name}.name}" + resource_group_name = each.value.resource_group_name + location = each.value.location + subnet_id = local.subnet_id + + tags = local.tags + + private_service_connection { + name = "psc-${each.value.name}" + private_connection_resource_id = each.value.id + + is_manual_connection = try(var.settings.private_endpoint.private_service_connection.is_manual_connection, false) + private_connection_resource_alias = try(var.settings.private_endpoint.private_service_connection.private_connection_resource_alias, null) + subresource_names = try(var.settings.private_endpoint.private_service_connection.subresource_names, null) + } + private_dns_zone_group { + name = try(var.settings.private_endpoint.dns_group_name, "default") + private_dns_zone_ids = local.dns_zone_ids + } +} diff --git a/src/modules/keyvault/keyvault_secret/main.tf b/src/modules/keyvault/keyvault_secret/main.tf new file mode 100644 index 00000000..84caee31 --- /dev/null +++ b/src/modules/keyvault/keyvault_secret/main.tf @@ -0,0 +1,20 @@ + +module "keyvault" { + source = "../keyvault" +} + + + +resource "azurerm_key_vault_secret" "main" { + for_each = { + for key, value in try(var.settings.secrets, {}) : + key => value + } + name = each.value.name + value = each.value.value + key_vault_id = module.keyvault.id + + lifecycle { + ignore_changes = [value] + } +} diff --git a/src/networking.tf b/src/networking.tf index 32e893b8..c4b9ff86 100644 --- a/src/networking.tf +++ b/src/networking.tf @@ -59,3 +59,15 @@ module "local_network_gateways" { resource_groups = module.resource_groups } } + +module "private_dns_zones" { + source = "./modules/_networking/private_dns_zone" + for_each = var.private_dns_zones + + global_settings = var.global_settings + settings = each.value + resources = { + resource_groups = module.resource_groups + virtual_networks = module.virtual_networks + } +}