diff --git a/alz/azuredevops/locals.files.tf b/alz/azuredevops/locals.files.tf index 6b68dbf..9ea3ded 100644 --- a/alz/azuredevops/locals.files.tf +++ b/alz/azuredevops/locals.files.tf @@ -84,6 +84,12 @@ locals { } } + architecture_definition_file = local.has_architecture_definition ? { + "lib/architecture_definitions/${local.architecture_definition_name}.alz_architecture_definition.json" = { + content = module.architecture_definition[0].architecture_definition_json + } + } : {} + # Build a map of module files with types that are supported module_files_supported = { for key, value in local.module_files : key => value if value.content != "unsupported_file_type" && !endswith(key, "-cache.json") && !endswith(key, var.bicep_config_file_path) } @@ -96,6 +102,6 @@ locals { module_files_filtered = { for key, value in local.module_files_supported : key => value if !contains(local.excluded_module_files, key) } # Create final maps of all files to be included in the repositories - repository_files = merge(local.cicd_files, local.module_files_filtered, var.use_separate_repository_for_templates ? {} : local.cicd_template_files) + repository_files = merge(local.cicd_files, local.module_files_filtered, var.use_separate_repository_for_templates ? {} : local.cicd_template_files, local.architecture_definition_file) template_repository_files = var.use_separate_repository_for_templates ? local.cicd_template_files : {} } diff --git a/alz/azuredevops/locals.tf b/alz/azuredevops/locals.tf index db03119..287679b 100644 --- a/alz/azuredevops/locals.tf +++ b/alz/azuredevops/locals.tf @@ -123,3 +123,15 @@ locals { } } } + +locals { + slz_architecture_definition_name = "slz" + fsi_architecture_definition_name = "fsi" + slz_template_name = "microsoft_cloud_for_sovereignty" + fsi_template_name = "microsoft_cloud_for_financial_services" + + architecture_definition_name = (var.starter_module_name == local.slz_template_name ? local.slz_architecture_definition_name : + var.starter_module_name == local.fsi_template_name ? local.fsi_architecture_definition_name : "") + + has_architecture_definition = local.architecture_definition_name != "" +} diff --git a/alz/azuredevops/main.tf b/alz/azuredevops/main.tf index 1f58711..320d135 100644 --- a/alz/azuredevops/main.tf +++ b/alz/azuredevops/main.tf @@ -7,12 +7,22 @@ module "resource_names" { resource_names = merge(var.resource_names, local.custom_role_definitions_bicep_names, local.custom_role_definitions_terraform_names) } +module "architecture_definition" { + count = local.has_architecture_definition ? 1 : 0 + source = "../../modules/template_architecture_definition" + starter_module_folder_path = local.starter_module_folder_path + architecture_definition_name = local.architecture_definition_name + enable_alz = var.enable_alz + architecture_definition_path = var.architecture_definition_path +} + module "files" { source = "../../modules/files" starter_module_folder_path = local.starter_module_folder_path additional_files = concat(var.additional_files) configuration_file_path = var.configuration_file_path built_in_configurartion_file_name = var.built_in_configurartion_file_name + additional_folders_path = var.additional_folders_path } module "azure" { diff --git a/alz/azuredevops/variables.hidden.tf b/alz/azuredevops/variables.hidden.tf index a544112..98bbe34 100644 --- a/alz/azuredevops/variables.hidden.tf +++ b/alz/azuredevops/variables.hidden.tf @@ -4,6 +4,12 @@ variable "additional_files" { default = [] } +variable "additional_folders_path" { + description = "Additional folders to upload to the repository. This must be specified as a comma-separated list of absolute paths (e.g. c:\\templates\\Microsoft_Cloud_for_Industry\\Common or /templates/Microsoft_Cloud_for_Industry/Common)" + type = list(string) + default = [] +} + variable "agent_container_image_repository" { description = "The container image repository to use for Azure DevOps Agents" type = string @@ -345,3 +351,15 @@ variable "role_assignments_bicep" { } } } + +variable "architecture_definition_path" { + description = "The path to the architecture definition file to use instead of the default" + type = string + default = "" +} + +variable "enable_alz" { + description = "Enable the ALZ archetypes in the architecture definition" + type = bool + default = false +} diff --git a/alz/github/locals.files.tf b/alz/github/locals.files.tf index 77102e5..6579706 100644 --- a/alz/github/locals.files.tf +++ b/alz/github/locals.files.tf @@ -82,6 +82,12 @@ locals { } } + architecture_definition_file = local.has_architecture_definition ? { + "lib/architecture_definitions/${local.architecture_definition_name}.alz_architecture_definition.json" = { + content = module.architecture_definition[0].architecture_definition_json + } + } : {} + # Build a map of module files with types that are supported module_files_supported = { for key, value in local.module_files : key => value if value.content != "unsupported_file_type" && !endswith(key, "-cache.json") && !endswith(key, var.bicep_config_file_path) } @@ -94,6 +100,6 @@ locals { module_files_filtered = { for key, value in local.module_files_supported : key => value if !contains(local.excluded_module_files, key) } # Create final maps of all files to be included in the repositories - repository_files = merge(local.cicd_files, local.module_files_filtered, var.use_separate_repository_for_templates ? {} : local.cicd_template_files) + repository_files = merge(local.cicd_files, local.module_files_filtered, var.use_separate_repository_for_templates ? {} : local.cicd_template_files, local.architecture_definition_file) template_repository_files = var.use_separate_repository_for_templates ? local.cicd_template_files : {} } diff --git a/alz/github/locals.tf b/alz/github/locals.tf index 50667d4..838ea9b 100644 --- a/alz/github/locals.tf +++ b/alz/github/locals.tf @@ -111,3 +111,15 @@ locals { } } } + +locals { + slz_architecture_definition_name = "slz" + fsi_architecture_definition_name = "fsi" + slz_template_name = "microsoft_cloud_for_sovereignty" + fsi_template_name = "microsoft_cloud_for_financial_services" + + architecture_definition_name = (var.starter_module_name == local.slz_template_name ? local.slz_architecture_definition_name : + var.starter_module_name == local.fsi_template_name ? local.fsi_architecture_definition_name : "") + + has_architecture_definition = local.architecture_definition_name != "" +} diff --git a/alz/github/main.tf b/alz/github/main.tf index 5b82dfa..13b36a9 100644 --- a/alz/github/main.tf +++ b/alz/github/main.tf @@ -7,12 +7,22 @@ module "resource_names" { resource_names = merge(var.resource_names, local.custom_role_definitions_bicep_names, local.custom_role_definitions_terraform_names) } +module "architecture_definition" { + count = local.has_architecture_definition ? 1 : 0 + source = "../../modules/template_architecture_definition" + starter_module_folder_path = local.starter_module_folder_path + architecture_definition_name = local.architecture_definition_name + enable_alz = var.enable_alz + architecture_definition_path = var.architecture_definition_path +} + module "files" { source = "../../modules/files" starter_module_folder_path = local.starter_module_folder_path additional_files = var.additional_files configuration_file_path = var.configuration_file_path built_in_configurartion_file_name = var.built_in_configurartion_file_name + additional_folders_path = var.additional_folders_path } module "azure" { diff --git a/alz/github/variables.hidden.tf b/alz/github/variables.hidden.tf index 11abf1a..e536a44 100644 --- a/alz/github/variables.hidden.tf +++ b/alz/github/variables.hidden.tf @@ -113,6 +113,12 @@ variable "additional_files" { default = [] } +variable "additional_folders_path" { + description = "Additional folders to upload to the repository. This must be specified as a comma-separated list of absolute paths (e.g. c:\\templates\\Microsoft_Cloud_for_Industry\\Common or /templates/Microsoft_Cloud_for_Industry/Common)" + type = list(string) + default = [] +} + variable "storage_account_replication_type" { description = "Controls the redundancy for the storage account" type = string @@ -351,3 +357,15 @@ variable "role_assignments_bicep" { } } } + +variable "architecture_definition_path" { + description = "The path to the architecture definition file to use instead of the default" + type = string + default = "" +} + +variable "enable_alz" { + description = "Enable the ALZ archetypes in the architecture definition" + type = bool + default = false +} diff --git a/alz/local/locals.tf b/alz/local/locals.tf index c835457..9d6529a 100644 --- a/alz/local/locals.tf +++ b/alz/local/locals.tf @@ -57,3 +57,16 @@ locals { } } } + +locals { + slz_architecture_definition_name = "slz" + fsi_architecture_definition_name = "fsi" + slz_template_name = "microsoft_cloud_for_sovereignty" + fsi_template_name = "microsoft_cloud_for_financial_services" + + architecture_definition_name = (var.starter_module_name == local.slz_template_name ? local.slz_architecture_definition_name : + var.starter_module_name == local.fsi_template_name ? local.fsi_architecture_definition_name : "") + architecture_definition_file_destination = "${local.target_directory}/lib/architecture_definitions/${local.architecture_definition_name}.alz_architecture_definition.json" + + has_architecture_definition = local.architecture_definition_name != "" +} diff --git a/alz/local/main.tf b/alz/local/main.tf index af85c44..e430ac1 100644 --- a/alz/local/main.tf +++ b/alz/local/main.tf @@ -7,12 +7,28 @@ module "resource_names" { resource_names = merge(var.resource_names, local.custom_role_definitions_bicep_names, local.custom_role_definitions_terraform_names) } +module "architecture_definition" { + count = local.has_architecture_definition ? 1 : 0 + source = "../../modules/template_architecture_definition" + starter_module_folder_path = local.starter_module_folder_path + architecture_definition_name = local.architecture_definition_name + enable_alz = var.enable_alz + architecture_definition_path = var.architecture_definition_path +} + +resource "local_file" "architecture_definition_file" { + count = local.has_architecture_definition ? 1 : 0 + content = module.architecture_definition[0].architecture_definition_json + filename = local.architecture_definition_file_destination +} + module "files" { source = "../../modules/files" starter_module_folder_path = local.starter_module_folder_path additional_files = var.additional_files configuration_file_path = var.configuration_file_path built_in_configurartion_file_name = var.built_in_configurartion_file_name + additional_folders_path = var.additional_folders_path } module "azure" { diff --git a/alz/local/variables.hidden.tf b/alz/local/variables.hidden.tf index 0a110f9..7cdbe21 100644 --- a/alz/local/variables.hidden.tf +++ b/alz/local/variables.hidden.tf @@ -4,6 +4,12 @@ variable "additional_files" { default = [] } +variable "additional_folders_path" { + description = "Additional folders to upload to the repository. This must be specified as a comma-separated list of absolute paths (e.g. c:\\templates\\Microsoft_Cloud_for_Industry\\Common or /templates/Microsoft_Cloud_for_Industry/Common)" + type = list(string) + default = [] +} + variable "built_in_configurartion_file_name" { description = "The name of the built-in configuration file" type = string @@ -268,3 +274,15 @@ variable "role_assignments_bicep" { } } } + +variable "architecture_definition_path" { + description = "The path to the architecture definition file to use instead of the default" + type = string + default = "" +} + +variable "enable_alz" { + description = "Enable the ALZ archetypes in the architecture definition" + type = bool + default = false +} diff --git a/modules/files/main.tf b/modules/files/main.tf index 457126b..9812a94 100644 --- a/modules/files/main.tf +++ b/modules/files/main.tf @@ -8,10 +8,16 @@ locals { } if(!local.has_configuration_file || file != var.built_in_configurartion_file_name) && !strcontains(file, var.starter_module_folder_path_exclusion) } + additional_folders_files = length(var.additional_folders_path) != 0 ? merge( + [for folder_path in var.additional_folders_path : { for file in fileset(folder_path, "**") : "${basename(folder_path)}/${file}" => { + path = "${folder_path}/${file}" + } + }]...) : {} + final_additional_files = concat(var.additional_files, local.has_configuration_file ? [var.configuration_file_path] : []) additional_repo_files = { for file in local.final_additional_files : basename(file) => { path = file } } - all_repo_files = merge(local.starter_module_files, local.additional_repo_files) + all_repo_files = merge(local.starter_module_files, local.additional_repo_files, local.additional_folders_files) } diff --git a/modules/files/variables.tf b/modules/files/variables.tf index 2aba0aa..43f5f75 100644 --- a/modules/files/variables.tf +++ b/modules/files/variables.tf @@ -26,3 +26,9 @@ variable "built_in_configurartion_file_name" { type = string default = "config.yaml" } + +variable "additional_folders_path" { + description = "Additional folders" + type = list(string) + default = [] +} diff --git a/modules/template_architecture_definition/data.tf b/modules/template_architecture_definition/data.tf new file mode 100644 index 0000000..8acd5ed --- /dev/null +++ b/modules/template_architecture_definition/data.tf @@ -0,0 +1,9 @@ +data "template_file" "populated_architecture_definition_json" { + template = file(local.template_file_path) + vars = local.template_vars +} + +data "local_file" "custom_architecture_definition_json" { + count = local.has_custom_architecture_definition ? 1 : 0 + filename = var.architecture_definition_path +} diff --git a/modules/template_architecture_definition/locals.tf b/modules/template_architecture_definition/locals.tf new file mode 100644 index 0000000..e177a0c --- /dev/null +++ b/modules/template_architecture_definition/locals.tf @@ -0,0 +1,80 @@ +locals { + # Customer has provided a custom architecture definition + has_custom_architecture_definition = var.architecture_definition_path != "" + + # Determine the default prefix and postfix based on the starter module tfvars + starter_module_tfvars = jsondecode(file("${var.starter_module_folder_path}/terraform.tfvars.json")) + default_prefix = local.starter_module_tfvars.default_prefix + default_postfix = local.starter_module_tfvars.default_postfix + + template_file_path = "${var.starter_module_folder_path}/lib/templates/${var.architecture_definition_name}.alz_architecture_definition.json.tftpl" + + slz_architecture_definition_name = "slz" + fsi_architecture_definition_name = "fsi" + + # SLZ archetypes + slz_global = ["\"global\""] + + # FSI archetypes + fsi_root = ["\"fsi_root\""] + + # SLZ/FSI confidential archetypes + confidential = ["\"confidential\""] + + # ALZ archetypes + alz_root = ["\"root\""] + alz_platform = ["\"platform\""] + alz_landing_zone = ["\"landing_zones\""] + alz_decommissioned = ["\"decommissioned\""] + alz_sandboxes = ["\"sandboxes\""] + alz_corp = ["\"corp\""] + alz_online = ["\"online\""] + alz_management = ["\"management\""] + alz_connectivity = ["\"connectivity\""] + alz_identity = ["\"identity\""] + + # management group layered archetypes + root = (var.enable_alz ? + (var.architecture_definition_name == local.slz_architecture_definition_name ? concat(local.slz_global, local.alz_root) : concat(local.fsi_root, local.alz_root)) + : (var.architecture_definition_name == local.fsi_architecture_definition_name ? local.fsi_root : local.slz_global)) + platform = var.enable_alz ? local.alz_platform : [] + landing_zone = var.enable_alz ? local.alz_landing_zone : [] + decommissioned = var.enable_alz ? local.alz_decommissioned : [] + sandboxes = var.enable_alz ? local.alz_sandboxes : [] + corp = var.enable_alz ? local.alz_corp : [] + online = var.enable_alz ? local.alz_online : [] + management = var.enable_alz ? local.alz_management : [] + connectivity = var.enable_alz ? local.alz_connectivity : [] + identity = var.enable_alz ? local.alz_identity : [] + confidential_corp = local.confidential + confidential_online = local.confidential + + template_vars = { + architecture_definition_name = var.architecture_definition_name + root_management_group_id = "${local.default_prefix}${local.default_postfix}" + platform_management_group_id = "${local.default_prefix}-platform${local.default_postfix}" + landing_zone_management_group_id = "${local.default_prefix}-landingzones${local.default_postfix}" + decommissioned_management_group_id = "${local.default_prefix}-decommissioned${local.default_postfix}" + sandbox_management_group_id = "${local.default_prefix}-sandbox${local.default_postfix}" + corp_management_group_id = "${local.default_prefix}-landingzones-corp${local.default_postfix}" + online_management_group_id = "${local.default_prefix}-landingzones-online${local.default_postfix}" + management_management_group_id = "${local.default_prefix}-platform-management${local.default_postfix}" + connectivity_management_group_id = "${local.default_prefix}-platform-connectivity${local.default_postfix}" + identity_management_group_id = "${local.default_prefix}-platform-identity${local.default_postfix}" + confidential_corp_management_group_id = "${local.default_prefix}-landingzones-confidential-corp${local.default_postfix}" + confidential_online_management_group_id = "${local.default_prefix}-landingzones-confidential-online${local.default_postfix}" + + root_archetypes = join(", ", local.root) + platform_archetypes = join(", ", local.platform) + landing_zone_archetypes = join(", ", local.landing_zone) + decommissioned_archetypes = join(", ", local.decommissioned) + sandboxes_archetypes = join(", ", local.sandboxes) + corp_archetypes = join(", ", local.corp) + online_archetypes = join(", ", local.online) + management_archetypes = join(", ", local.management) + connectivity_archetypes = join(", ", local.connectivity) + identity_archetypes = join(", ", local.identity) + confidential_corp_archetypes = join(", ", local.confidential_corp) + confidential_online_archetypes = join(", ", local.confidential_online) + } +} diff --git a/modules/template_architecture_definition/outputs.tf b/modules/template_architecture_definition/outputs.tf new file mode 100644 index 0000000..80877c0 --- /dev/null +++ b/modules/template_architecture_definition/outputs.tf @@ -0,0 +1,3 @@ +output "architecture_definition_json" { + value = local.has_custom_architecture_definition ? data.local_file.custom_architecture_definition_json[0].content : data.template_file.populated_architecture_definition_json.rendered +} diff --git a/modules/template_architecture_definition/terraform.tf b/modules/template_architecture_definition/terraform.tf new file mode 100644 index 0000000..0c59cc4 --- /dev/null +++ b/modules/template_architecture_definition/terraform.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + template = { + source = "hashicorp/template" + version = "~> 2.2" + } + local = { + source = "hashicorp/local" + version = "~> 2.4" + } + } +} diff --git a/modules/template_architecture_definition/variables.tf b/modules/template_architecture_definition/variables.tf new file mode 100644 index 0000000..4667d76 --- /dev/null +++ b/modules/template_architecture_definition/variables.tf @@ -0,0 +1,21 @@ +variable "starter_module_folder_path" { + type = string + description = "Starter module folder path" +} + +variable "architecture_definition_name" { + type = string + description = "Name of the architecture definition" +} + +variable "enable_alz" { + description = "Enable the ALZ archetypes in the architecture definition" + type = bool + default = false +} + +variable "architecture_definition_path" { + description = "Path to the architecture definition file to use instead of the default" + type = string + default = "" +}