Terraform
Deploy the Microsoft Cloud Adoption Framework enterprise-scale module
Microsoft's Cloud Adoption Framework (CAF) for Azure is a collection of documentation, tools, and best practices that guide organizations through cloud adoption. The framework sets up landing zones, which are pre-configured environments where you can host your workloads. These landing zones implement best practices in governance, networking, and identity management that allow you to securely scale your workloads. There are two strategies to implement the Cloud Adoption Framework in your organization:
- Start with enterprise scale to deploy fully integrated landing zones with governance, security, networking, and more.
- Start small and expand to deploy landing zones that have the basic landing zones considerations, these include compute, storage, networking and database decisions. You can supplement these landing zones with governance and management layers in the future.
Each strategy includes a corresponding Terraform module to help you deploy resources according to the strategy guidelines. Every organization is unique, so you must consider different trade-offs of each approach when you deploy landing zones.
In this tutorial, you will use the caf-enterprise-scale Terraform module to:
- deploy the core and demo landing zones. The core landing zones manage and organize user workloads to provide the services and governance that the CAF recommends. The demo landing zones represent sample landing zones that your infrastructure team would deploy to give downstream teams access to infrastructure for their workloads.
- deploy a custom landing zone. This simulates a workflow you can use to deploy landing additional, CAF-compliant infrastructure for teams within your organization.
- add logging and security with the management submodule.
- create subnets, DNS zones, and policies with the connectivity module.
In the process, you will review the module configuration to help you tailor the module to your organization's priorities and enable sustainable scale.
Prerequisites
This tutorial assumes that you are familiar with the standard Terraform workflow. If you are new to Terraform, complete the Get Started tutorials first.
For this tutorial, you will need:
- the Terraform 1.0.4+ CLI installed locally.
- an Azure account with one or more Subscriptions.
- a configured Azure CLI.
Note
Some of the infrastructure in this tutorial may not qualify for the Azure free tier. Destroy the infrastructure at the end of the tutorial to avoid unnecessary charges. We are not responsible for any charges that you incur.
Clone the example repository
In your terminal, clone the example repository.
$ git clone https://github.com/hashicorp-education/learn-terraform-microsoft-caf-enterprise-scale
Navigate to the cloned repository.
$ cd learn-terraform-microsoft-caf-enterprise-scale
Explore the configuration
This repository contains the configuration to deploy the core and demo landing zones according to the Cloud Adoption Framework guidance for the enterprise scale strategy. The module will deploy the demo landing zones in the Landing Zones management group that are part of the core landing zones.
Here, you will find the following files:
- the - terraform.tffile defines the provider versions this configuration uses. The module requires an- azurermprovider version- 2.77.0or greater.
- the - .terraform.lock.hclfile ensures that Terraform uses the same provider versions for each run.
- the - providers.tffile defines the three Azure providers this configuration uses. This configuration supports multi-subscription workloads, so that different teams can manage each submodule. If you do not provide a subscription ID (as a Terraform variable) for management or connectivity, the management and connectivity Azure providers default to the current subscription.
- the - main.tffile configures the- caf-enterprise-scalemodule. This configuration deploys the core and demo landing zones in the current subscription and the- default_location. The- default_locationdefaults to- useast, as defined by- terraform.tfvars.example.
- the - client.tffile contains data sources that retrieve your current subscription ID.
- the - variables.tffile declares the configuration's input variables. Each variable has a description and a default value.
- the - terraform.tfvars.examplefile defines values for the variables declared in the- variables.tffile.
- the - locals.tffile converts the input variables to local values. Assigning input variables to local values enables you to modify the values before you use them throughout the configuration.- Take note of the - subscription_id_managementand- subscription_id_connectivitylocal values.- locals.tf - locals { ## ... subscription_id_management = coalesce(var.subscription_id_management, data.azurerm_client_config.current.subscription_id) subscription_id_connectivity = coalesce(var.subscription_id_connectivity, local.subscription_id_management) }- This configuration supports multi-subscription workloads, but uses the - coalesce()Terraform function to default to your account's default subscription ID if you do not set the- subscription_id_managementand- subscription_id_connectivityinput variables.
Deploy enterprise-scale resources
The caf-enterprise-scale Terraform module provides an opinionated way to deploy and manage the core platform capabilities defined in the enterprise-scale landing zone architecture documentation. The module creates the core resources, which include management groups, policies, and roles, that make it easier to organize and manage your other landing zone. In addition, the module includes three submodules; each one creates management group(s) with policies scoped the resources they manage: 
- The management submodule adds a central Log Analytics workspace and Automation Account and enables Azure Security Center.
- The connectivity submodule creates guidelines for networks by defining common policies. In addition, this submodule creates an Azure Firewall and configures subnets and DNS zones.
- The identity submodule creates policies to manage compliance and security.
The core landing zones create management groups for Decommissioned, Landing zones, Platform, and Sandboxes. The CAF recommends these landing zones to manage and organize your workloads. You can also configure the module to provision Online, Corp, and SAP demo landing zones. These landing zones represent ones that your organization may set up to migrate your workloads to Azure.
Deploy the core and demo enterprise scale landing zones.
First, rename the terraform.tfvars.example to terraform.tfvars.
mv terraform.tfvars.example terraform.tfvars
Then, in terraform.tfvars, replace the security contact email address with your email address.
terraform.tfvars
security_contact_email_address = "security.contact@replace_me"
Next, initialize the Terraform configuration.
$ terraform init
Initializing modules...
Downloading Azure/caf-enterprise-scale/azurerm 1.0.0 for enterprise_scale...
- enterprise_scale in .terraform/modules/enterprise_scale
- enterprise_scale.connectivity_resources in .terraform/modules/enterprise_scale/modules/connectivity
- enterprise_scale.identity_resources in .terraform/modules/enterprise_scale/modules/identity
- enterprise_scale.management_group_archetypes in .terraform/modules/enterprise_scale/modules/archetypes
- enterprise_scale.management_resources in .terraform/modules/enterprise_scale/modules/management
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Reusing previous version of hashicorp/time from the dependency lock file
- Installing hashicorp/azurerm v2.79.1...
- Installed hashicorp/azurerm v2.79.1 (signed by HashiCorp)
- Installing hashicorp/time v0.7.2...
- Installed hashicorp/time v0.7.2 (signed by HashiCorp)
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Finally, apply the configuration. It may take a while for Terraform to generate the execution plan — the caf-enterprise-scale module provisions 187 resources. Once prompted, respond yes to confirm.
Tip
 Deploying the core enterprise scale resources takes an average of 30 minutes. Review the caf-enterprise-scale module while you wait for Terraform to finish provisioning these resources.
$ terraform apply
## ...
Plan: 187 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Enter a value: yes
## ...
Apply complete! Resources: 187 added, 0 changed, 0 destroyed.
Review the configuration by reading the next section while you wait.
Review caf-enterprise-scale module
The current main.tf configuration deploys the core and demo landing zones by setting the following module arguments to true. The local.deploy_*_landing_zones are set to true in the terraform.tfvars file.
main.tf
module "enterprise_scale" {
  source  = "Azure/caf-enterprise-scale/azurerm"
  version = "~> 1.0.0"
  ## ...
  # Control deployment of the core landing zone hierarchy.
  deploy_core_landing_zones   = true
  deploy_corp_landing_zones   = local.deploy_corp_landing_zones
  deploy_online_landing_zones = local.deploy_online_landing_zones
  deploy_sap_landing_zones    = local.deploy_sap_landing_zones
}
In this section, you will review the caf-enterprise-scale module configuration to understand how the module arguments modify the architecture that the module provisions. 
When Terraform initializes the configuration, it downloads the providers and modules used into the .terraform directory. For this configuration, Terraform stores a copy of the caf-enterprise-scale module in the .terraform/modules directory. 
$ ls -la .terraform/modules/
total 8
drwxr-xr-x   4 dos  staff   128B Oct  8 12:25 ./
drwxr-xr-x   4 dos  staff   128B Oct  7 20:24 ../
drwxr-xr-x  35 dos  staff   1.1K Oct  7 20:24 enterprise_scale/
-rw-r--r--   1 dos  staff   1.3K Oct  7 23:31 modules.json
Terraform stores the module under the module name as the name defined in the main.tf file (enterprise_scale) and not the module source (caf-enterprise-scale). 
main.tf
module "enterprise_scale" {
  source  = "Azure/caf-enterprise-scale/azurerm"
    ## ...
}
This module uses local values and submodules to manipulate the input variables into data structures. The submodule configuration is in the modules directory, and the rest of the configuration primarily consists of two types of files: 
- The locals.*.tffiles parse and manipulate the variables.
- The respective resources.*tffiles use the local values to configure resources.
For example, the locals.management_groups.tf file creates the local values that resources.management_groups.tf consumes.
Review core and demo landing zones
The caf-enterprise-scale module uses a similar pattern for each of the landing zones you can provision. Review the configuration for the core landing zones; the deploy_core_landing_zones argument in the configuration toggles the core landing zones deployment.
Run the following command to find references of  deploy_core_landing_zones in the .terraform/modules/enterprise_scale directory. It only searches files that end in .tf.
$ grep --include=\*.tf -rnw '.terraform/modules/enterprise_scale/' -e 'deploy_core_landing_zones' | grep -v "tests"
.terraform/modules/enterprise_scale//locals.tf:15:  ...
.terraform/modules/enterprise_scale//variables.tf:39:variable ...
.terraform/modules/enterprise_scale//locals.management_groups.tf:265:  ...
.terraform/modules/enterprise_scale//locals.management_groups.tf:266:  ...
.terraform/modules/enterprise_scale//locals.management_groups.tf:267:  ...
.terraform/modules/enterprise_scale//locals.management_groups.tf:270:  ...
Tip
 You can find all instances of deploy_core_landing_zones by searching in the caf-enterprise-scale GitHub repository.
This argument appears in three files:  variables.tf, locals.tf, and locals.management_groups.tf.
- The - .terraform/modules/enterprise_scale/locals.tffile sets the- deploy_core_landing_zoneslocal value to the value of the input variable. Assigning input variables to local values lets you modify the variables before you use them throughout the configuration.
- The - .terraform/modules/enterprise_scale/variables.tffile declares the- deploy_core_landing_zonesinput variable. It sets the default value to- true.- .terraform/module/enterprise_scale/variables.tf - variable "deploy_core_landing_zones" { type = bool description = "If set to true, module will deploy the core Enterprise-scale Management Group hierarchy, including \"out of the box\" policies and roles." default = true }
- The - .terraform/modules/enterprise_scale/locals.management_groups.tffile uses the- local.deploy_core_landing_zonesto determine whether to assign a list of recommended landing zones.- Find - es_core_landing_zones_to_include.- .terraform/modules/enterprise_scale/locals.management_groups.tf - es_core_landing_zones_to_include = local.deploy_core_landing_zones ? local.es_core_landing_zones : null- If - deploy_core_landing_zonesis set to true, it sets- es_core_landing_zones_to_includelocal value to the- es_core_landing_zoneslocal value. Otherwise, it sets the value to- null. This makes the module more dynamic, only provisioning the core landing zones if enabled.
- Find the - es_core_landing_zoneslocal value. This local value interpolates input information including the- root_nameand- root_idto create a data structure that defines customized core management groups for all of the CAF-recommended landing zones.- .terraform/modules/enterprise_scale/locals.management_groups.tf - es_core_landing_zones = { (local.root_id) = { display_name = local.root_name parent_management_group_id = local.root_parent_id subscription_ids = local.es_subscription_ids_map[local.root_id] archetype_config = local.es_archetype_config_map[local.root_id] } "${local.root_id}-decommissioned" = { display_name = "Decommissioned" parent_management_group_id = local.root_id subscription_ids = local.es_subscription_ids_map["${local.root_id}-decommissioned"] archetype_config = local.es_archetype_config_map["${local.root_id}-decommissioned"] } ## … }
- Find the - es_landing_zones_mergelocal value.- .terraform/modules/enterprise_scale/locals.management_groups.tf - es_landing_zones_merge = merge( local.es_core_landing_zones_to_include, local.es_corp_landing_zones_to_include, local.es_online_landing_zones_to_include, local.es_sap_landing_zones_to_include, local.es_demo_landing_zones_to_include, local.custom_landing_zones, )- Notice that this local value uses - mergeto combine the- es_core_landing_zones_to_includelocal value with the other landing zones, including the demo landing zones and- custom_landing_zone.
- Find the - es_landing_zones_maplocal value.- .terraform/modules/enterprise_scale/locals.management_groups.tf - es_landing_zones_map = { for key, value in local.es_landing_zones_merge : "${local.provider_path.management_groups}${key}" => { id = key display_name = value.display_name ## ... } }- This local value iterates through - es_landing_zones_mergeand automatically generates the management groups, populating them with default values.
- Find the - azurerm_management_group_level_*local values.- .terraform/modules/enterprise_scale/locals.management_groups.tf - locals { azurerm_management_group_level_1 = { for key, value in local.es_landing_zones_map : key => value if value.parent_management_group_id == local.root_parent_id } ## ... }- These local values take the landing zones listed in - es_landing_zones_mapand organize them according to their hierarchy.
 
Open resources.management_groups.tf. This file defines and deploys the management groups. The parent_management_group_id argument creates dependencies between different groups.
.terraform/modules/enterprise_scale/resources.management_groups.tf
resource "azurerm_management_group" "level_2" {
  for_each = local.azurerm_management_group_level_2
  name                       = each.value.id
  display_name               = each.value.display_name
  parent_management_group_id = "${local.provider_path.management_groups}${each.value.parent_management_group_id}"
  subscription_ids           = each.value.subscription_ids
  depends_on = [azurerm_management_group.level_1]
}
Since the demo landing zones are merged into es_landing_zones_merge, the module deploys all of the enabled zones, including the demo landing zones, when you apply your configuration.
.terraform/modules/enterprise_scale/locals.management_groups.tf
es_landing_zones_merge = merge(
    local.es_core_landing_zones_to_include,
    local.es_corp_landing_zones_to_include,
    local.es_online_landing_zones_to_include,
    local.es_sap_landing_zones_to_include,
    local.es_demo_landing_zones_to_include,
    local.custom_landing_zones,
  )
The caf-enterprise-module also creates archetypes, which define the Azure Policy and Access control (IAM) settings needed to secure and configure the landing zones. This includes creating guidelines for role-based access control (RBAC) settings, security settings, and common workload configurations. The module uses es_landing_zones_map and the archetypes submodule to create the landing zone archetypes.
.terraform/modules/enterprise_scale/main.tf
module "management_group_archetypes" {
  for_each = local.es_landing_zones_map
  source   = "./modules/archetypes"
  ## ...
}
The ./modules/archetypes submodule creates and assigns the policies and roles for each management group. The locals.*_definitions.tf files contain the definition; the locals.*_assignments.tf files contain the assignment. These files reference the roles and policies defined in their respective directories in ./modules/archetypes/lib.
Tip
 Use grep, GitHub search, or any search alternative to navigate the module configuration and find where the module references a particular local value.
Verify core and demo landing zones
Once Terraform finishes applying your resources, open the Azure Portal's Management group page. Here, you will find the management groups provisioned by the caf-enterprise-scale module.
Click the Expand/Collapse all button to view all the management groups in the Learn Terraform ES management group.

Under Landing Zones, notice there are three management groups (Corp, Online, and SAP), each one mapping to the demo landing zones you defined in the enterprise-scale module.
Deploy custom landing zones
Now that you have deployed the core and demo landing zones, deploy a custom landing zone with the caf-enterprise-scale module. You will follow this workflow to deploy landing zones within your organization. 
Define a new management group with default policies and access control (IAM) settings by adding the following code snippet to the enterprise_scale module in main.tf.
main.tf
module "enterprise_scale" {
  ## ...
  # Define an additional "LearnTerraform" Management Group.
  custom_landing_zones = {
    "${local.root_id}-learn-tf" = {
      display_name               = "LearnTerraform"
      parent_management_group_id = "${local.root_id}-landing-zones"
      subscription_ids           = []
      archetype_config = {
        archetype_id   = "default_empty"
        parameters     = {}
        access_control = {}
      }
    }
  }
}
Next, apply the configuration. Once prompted, respond yes to deploy the custom landing zone. The module automatically nests the custom landing zone in the root parent management group.
$ terraform apply
## ...
Plan: 2 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Enter a value: yes
## ...
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
The module defines custom landing zones using the same patterns as the core and demo landing zones.
Verify custom landing zone
Once the deployment completes, open the Azure Portal's Management group page.
Under Landing Zones, there is a new landing zone named "LearnTerraform".

Select the LearnTerraform landing zone to review its policies and access control (IAM) settings, which follow Microsoft's best practices. The caf-enterprise-scale module codifies these recommendations, helping you easily provision secure and scalable cloud environments. 
Select Access control (IAM) in the left navigation, then Roles. You will find a CustomRole named [TF-CAFES] Network-Subnet-Contributor, a standard role defined by the module.

Deploy management resources
In this section, you will deploy a new management group that will enable logging and security resources, covering all your landing zones.
Add the following code snippet to the enterprise_scale module block in main.tf.
main.tf
module "enterprise_scale" {
  ## ...
  # Configuration settings for management resources.
  # These are used to ensure Azure Policy is correctly configured with the same 
  # settings as the resources deployed by module.enterprise_scale_management.
  # Please refer to file: settings.management.tf
  deploy_management_resources    = true
  configure_management_resources = local.configure_management_resources
  subscription_id_management     = data.azurerm_client_config.management.subscription_id
}
Tip
 Add subscription_id_management = SUBSCRIPTION_ID to your terraform.tfvars file to deploy your management resources in another subscription.
Next, create a new file named settings.management.tf with the following configuration to enable Log Analytics and Security Center in the new landing zone. 
settings.management.tf
locals {
  configure_management_resources = {
    settings = {
      log_analytics = {
        enabled = true
        config = {
          retention_in_days                           = 30
          enable_monitoring_for_arc                   = true
          enable_monitoring_for_vm                    = true
          enable_monitoring_for_vmss                  = true
          enable_solution_for_agent_health_assessment = true
          enable_solution_for_anti_malware            = true
          enable_solution_for_azure_activity          = true
          enable_solution_for_change_tracking         = true
          enable_solution_for_service_map             = true
          enable_solution_for_sql_assessment          = true
          enable_solution_for_updates                 = true
          enable_solution_for_vm_insights             = true
          enable_sentinel                             = true
        }
      }
      security_center = {
        enabled = true
        config = {
          email_security_contact             = local.security_contact_email_address
          enable_defender_for_acr            = true
          enable_defender_for_app_services   = true
          enable_defender_for_arm            = true
          enable_defender_for_dns            = true
          enable_defender_for_key_vault      = true
          enable_defender_for_kubernetes     = true
          enable_defender_for_servers        = true
          enable_defender_for_sql_servers    = true
          enable_defender_for_sql_server_vms = true
          enable_defender_for_storage        = true
        }
      }
    }
    location = null
    tags     = null
    advanced = null
  }
}
This configuration defines a local value that the caf-enterprise-scale modules uses to configure the management resource settings including enabling log analytics and Azure Security Center.
Next, apply the configuration. Once prompted, respond yes to deploy the custom landing zone.
$ terraform apply
## ...
Plan: 45 to add, 1 to change, 31 to destroy.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Enter a value: yes
Apply complete! Resources: 45 added, 1 changed, 31 destroyed.
Review management submodule
The management submodule deploys the management group and subscription organization by setting the following module arguments:
The deploy_management_resources is set to true to enable the submodule.
The configure_management_resources argument customizes the management resources. The settings in settings.management.tf enable log analytics and Azure Security Center.
The subscription_id_management sets the management subscription ID. This is useful if you want to deploy management resources in another subscription. Otherwise, this defaults to your current subscription.
.terraform/modules/enterprise_scale/main.tf
module "enterprise_scale" {
  source  = "Azure/caf-enterprise-scale/azurerm"
  version = "~> 1.0.0"
  ## ...
  deploy_management_resources    = true
  configure_management_resources = local.configure_management_resources
  subscription_id_management     = data.azurerm_client_config.management.subscription_id
}
Like the core resources, review how the caf-enterprise-scale module deploys and customizes the management resources.
First, open resources.management.tf. 
.terraform/modules/enterprise_scale/resources.management.tf
resource "azurerm_resource_group" "management" {
  for_each = local.azurerm_resource_group_management
  provider = azurerm.management
  # Mandatory resource attributes
  name     = each.value.template.name
  location = each.value.template.location
  tags     = each.value.template.tags
}
Notice that this module deploys resource groups defined by the azurerm_resource_group_management resource.
Open locals.management.tf. 
.terraform/modules/enterprise_scale/locals.management.tf
locals {
  es_management_resource_groups = module.management_resources.configuration.azurerm_resource_group
}
locals {
  azurerm_resource_group_management = {
    for resource in local.es_management_resource_groups :
    resource.resource_id => resource
    if resource.managed_by_module
  }
}
The azurerm_resource_group_management local value depends on es_management_resource_groups, which is defined by the module.management_resources submodule.
In .terraform/modules/enterprise_scale/management/outputs.tf, configuration maps to local.module_output. Open .terraform/modules/enterprise_scale/management/locals.tf and find module_output to review how the management submodule defines the resource group configuration and adds logging and Security Center to it.
Verify management resources
After Terraform applies your changes, open the Azure Portal's Management group page.
Under Platform, find and click the subscription in the "Management" management group.

The deploy_management_resources argument enables log analytics and Azure Security Center for this subscription. Verify this subscription has Security Center by clicking Security from the left navigation menu. 

Deploy connectivity resources
Add the following configuration to the enterprise_scale module block in main.tf 
main.tf
module "enterprise_scale" {
  ## ...
  # Configuration settings for connectivity resources.
  # Uses default settings.
  deploy_connectivity_resources = true
  subscription_id_connectivity  = data.azurerm_client_config.connectivity.subscription_id
}
Tip
 Add subscription_id_connectivity = SUBSCRIPTION_ID to your terraform.tfvars file to deploy your connectivity resources in another subscription.
This defines a new management group with default policies and access control (IAM) settings. In addition, it creates a centralized hub so your organization can connect with on-premise resources, secures the network with Azure Firewall, and centrally manages the DNS zones.
Next, apply the configuration. Once prompted, respond yes to deploy the custom landing zone.
Tip
 Deploying the connectivity resources takes an average of 30 minutes. Review connectivity submodule while you wait for Terraform to finish provisioning these resources.
$ terraform apply
## ...
Plan: 111 to add, 0 to change, 26 to destroy.
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Enter a value: yes
Apply complete! Resources: 111 added, 0 changed, 26 destroyed.
Review connectivity submodule
The module deploys the connectivity resources by setting the following module arguments.
The deploy_connectivity_resources is true. This enables the connectivity submodule.
The subscription_id_connectivity sets the management subscription ID. This is useful if you want to deploy management resources in another subscription. Otherwise, this defaults to your current subscription.
.terraform/modules/enterprise_scale/main.tf
module "enterprise_scale" {
  source  = "Azure/caf-enterprise-scale/azurerm"
  version = "~> 1.0.0"
  ## ...
  deploy_connectivity_resources = true
  subscription_id_connectivity  = data.azurerm_client_config.connectivity.subscription_id
}
The module deploys the connectivity resources very similarly to the management resources.
First, open resources.connectivity.tf to find all the connectivity resources this module deploys, including resource groups, virtual network, and subnets.
.terraform/modules/enterprise_scale/resources.connectivity.tf
resource "azurerm_resource_group" "connectivity" {
  for_each = local.azurerm_resource_group_connectivity
  provider = azurerm.connectivity
  # Mandatory resource attributes
  name     = each.value.template.name
  location = each.value.template.location
  tags     = each.value.template.tags
}
The resources in this file reference local values for their definitions. Open locals.connectivity.tf to view these local values.
.terraform/modules/enterprise_scale/locals.connectivity.tf
locals {
  es_connectivity_resource_groups = module.connectivity_resources.configuration.azurerm_resource_group
}
locals {
  azurerm_resource_group_connectivity = {
    for resource in local.es_connectivity_resource_groups :
    resource.resource_id => resource
    if resource.managed_by_module
  }
}
Similarly to the management local values, the connectivity local values are defined in the connectivity submodule. Review the connectivity submodule's outputs.tf and locals.tf files to understand how it parses and creates the downstream local values.
Verify connectivity resources
Once the deployment completes, open the Azure Portal's Subscription page page and select your subscription. Then, click Resource groups on the left navigation menu.
Filter the resource groups on tf-cafes.

You should find a total of four resource groups. The connectivity submodule created the tf-cafes-connectivity-eastus and tf-cafe-dns resource groups for all the resources it provisioned.
The tf-cafes-connectivity-eastus resource group contains a single virtual network named tf-cafes-hub-eastus. The caf-enterprise-scale module pre-configured the virtual network with subnets for GatewaySubnet and AzureFirewallSubnet. The DDos Protection Standard is disabled to save costs for this tutorial. Enable this in production environments.
The tf-cafes-dns resource group creates all the DNS resources. Even though the resource group is in useast (as defined by the `default_location input value), the DNS resources are all global resources. By default, the module creates a private DNS Zone for all services and connects each private DNS zone to the virtual network.
Clean up resources
Before moving on, destroy the infrastructure you created in this tutorial.
Tip
Destroying the enterprise scale resources deployed in this tutorial takes an average of 20 minutes.
$ terraform destroy
## ...
Plan: 0 to add, 0 to change, 287 to destroy.
Do you really want to destroy all resources?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Enter a value: yes
## ...
Destroy complete! Resources: 287 destroyed.
Be sure to respond to the confirmation prompt with yes.
Next steps
Over the course of this tutorial, you used the caf-enterprise-scale module to deploy the core, management, and connectivity resources as defined by the Cloud Adoption Framework. In the process, you reviewed the module configuration to understand how the module operates behind-the-scenes. Now, you are equipped with the skills to better tailor the module to your organization's priorities and set your organization on a path to sustainable scale.
For more information on topics covered in this tutorial, check out the following resources.