diff --git a/README.md b/README.md
index c8d493fc1..b5bf822ec 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,11 @@
# Terraform Module for Cloud Adoption Framework Enterprise-scale
-
-
-> **WARNING**: Please note that the `v0.1.0` release contained a number of changes which may impact your deployment.
-> Please review the [Upgrade from v0.0.8 to v0.1.0][wiki_upgrade_from_v0_0_8_to_v0_1_0] guidance before upgrading to v0.1.0 or later.
-
-
-
[![Build Status](https://dev.azure.com/mscet/CAE-ESTF/_apis/build/status/Tests/E2E?branchName=main)](https://dev.azure.com/mscet/CAE-ESTF/_build/latest?definitionId=26&branchName=main)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/Azure/terraform-azurerm-caf-enterprise-scale?style=flat&logo=github)
+> **NOTE:** The latest `v0.2.0` release adds new functionality to enable deployment of [Management and monitoring][ESLZ-Management] resources into the current Subscription context.
+> Please refer to the [Deploy Management Resources][wiki_deploy_management_resources] page on our Wiki for more information about how to use this.
+
## Documentation
For detailed information about how to use, configure and extend this module, please refer to the documentation on our Wiki:
@@ -19,7 +15,9 @@ For detailed information about how to use, configure and extend this module, ple
- [Getting Started][wiki_getting_started]
- [Module Variables][wiki_module_variables]
- [Archetype Definitions][wiki_archetype_definitions]
+ - [Deploy Management Resources][wiki_deploy_management_resources]
- [Upgrade from v0.0.8 to v0.1.0][wiki_upgrade_from_v0_0_8_to_v0_1_0]
+ - [Upgrade from v0.1.2 to v0.2.0][wiki_upgrade_from_v0_1_2_to_v0_2_0]
- [Examples][wiki_examples]
- [Deploy Default Configuration][wiki_deploy_default_configuration]
- [Deploy Demo Landing Zone Archetypes][wiki_deploy_demo_landing_zone_archetypes]
@@ -35,14 +33,23 @@ For detailed information about how to use, configure and extend this module, ple
## Overview
-The [Terraform Module for Cloud Adoption Framework Enterprise-scale][terraform-registry-caf-enterprise-scale] provides an opinionated approach for delivering the core platform capabilities needed to start building Azure landing zones using Terraform.
-This module deploys the foundations of the [Cloud Adoption Framework enterprise-scale landing zone architecture][ESLZ-Architecture], with a focus on the central resource hierarchy and governance:
+The [Terraform Module for Cloud Adoption Framework Enterprise-scale][terraform-registry-caf-enterprise-scale] provides an opinionated approach for delivering Azure landing zones using Terraform.
+Depending on the selected options, this module is able to deploy different groups of resources as needed.
+
+This is currently split logically into the following capabilities:
-![Enterprise-scale Landing Zone Architecture][TFAES-Overview]
+- Core resources
+- Management resources
-## Resources
+The following sections outline the different resource types deployed and managed by this module, depending on the configuration options specified.
-The following resource types are deployed and managed by this module:
+### Core resources
+
+The core capability of this module deploys the foundations of the [Cloud Adoption Framework enterprise-scale landing zone architecture][ESLZ-Architecture], with a focus on the central resource hierarchy and governance:
+
+![Enterprise-scale Core Landing Zones Architecture][TFAES-Overview]
+
+The following resource types are deployed and managed by this module when using the core capabilities:
| | Azure Resource | Terraform Resource |
| --- | -------------- | ------------------ |
@@ -56,19 +63,39 @@ The following resource types are deployed and managed by this module:
The exact number of resources created depends on the module configuration, but you can expect upwards of `100` resources to be created by this module for a default installation based on the example below.
+> **NOTE:** None of these resources are deployed at the Subscription scope, however Terraform still requires a Subscription to establish an authenticated session with Azure.
+
+### Management resources
+
+From release `v0.2.0` onwards, the module includes new functionality to enable deployment of [Management and monitoring][ESLZ-Management] resources into the current Subscription context.
+This brings the benefit of being able to manage the full lifecycle of these resources using Terraform, with native integration into the corresponding Policy Assignments to ensure full policy compliance.
+
+![Enterprise-scale Management Landing Zone Architecture][TFAES-Management]
+
+The following resource types are deployed and managed by this module when the Management resources capabilities are enabled:
+
+| | Azure Resource | Terraform Resource |
+| --- | -------------- | ------------------ |
+| Resource Groups | [`Microsoft.Resources/resourceGroups`][arm_resource_group] | [`azurerm_resource_group`][azurerm_resource_group] |
+| Log Analytics Workspace | [`Microsoft.OperationalInsights/workspaces`][arm_log_analytics_workspace] | [`azurerm_log_analytics_workspace`][azurerm_log_analytics_workspace] |
+| Log Analytics Solutions | [`Microsoft.OperationsManagement/solutions`][arm_log_analytics_solution] | [`azurerm_log_analytics_solution`][azurerm_log_analytics_solution] |
+| Automation Account | [`Microsoft.Automation/automationAccounts`][arm_automation_account] | [`azurerm_automation_account`][azurerm_automation_account] |
+| Log Analytics Linked Service | [`Microsoft.OperationalInsights/workspaces /linkedServices`][arm_log_analytics_linked_service] | [`azurerm_log_analytics_linked_service`][azurerm_log_analytics_linked_service] |
+
+Please refer to the [Deploy Management Resources][wiki_deploy_management_resources] page on our Wiki for more information about how to use this capability.
+
## Terraform versions
-This module has been tested using Terraform `0.13.2` onwards.
-It is also tested against the AzureRM Provider `2.34.0` onwards. In some cases, individual versions of the AzureRM provider may cause errors.
+This module has been tested using Terraform `0.13.2` and AzureRM Provider `2.41.0` as a baseline, and various versions to up the most recent at the time of release.
+In some cases, individual versions of the AzureRM provider may cause errors.
If this happens, we advise upgrading to the latest version and checking our [troubleshooting][wiki_troubleshooting] guide before [raising an issue](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/issues).
-This module has some known issues with the pre-release Terraform `0.15.x` versions which we plan to resolve in a future release.
## Usage
As a basic starting point, we recommend starting with the following configuration in your root module.
-> **NOTE**: For production use we highly recommend using the Terraform Registry and pinning to the latest stable version, as per the example below.
+> **NOTE:** For production use we highly recommend using the Terraform Registry and pinning to the latest stable version, as per the example below.
> Pinning to the `main` branch in GitHub will give you the latest updates quicker, but increases the likelihood of unplanned changes to your environment and unforeseen issues.
**File: `main.tf`**
@@ -81,7 +108,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = ">= 2.46.1"
+ version = ">= 2.41.0"
}
}
}
@@ -114,7 +141,7 @@ variable "root_name" {
module "enterprise_scale" {
source = "Azure/caf-enterprise-scale/azurerm"
- version = "0.1.2"
+ version = "0.2.0"
root_parent_id = data.azurerm_client_config.current.tenant_id
root_id = var.root_id
@@ -138,7 +165,8 @@ module "enterprise_scale" {
[//]: # (INSERT IMAGE REFERENCES BELOW)
[//]: # (*****************************)
-[TFAES-Overview]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/media/terraform-caf-enterprise-scale-overview.png "Diagram showing the Cloud Adoption Framework Enterprise-scale Landing Zone architecture deployed by this module."
+[TFAES-Overview]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/media/terraform-caf-enterprise-scale-overview.png "Diagram showing the core Cloud Adoption Framework Enterprise-scale Landing Zone architecture deployed by this module."
+[TFAES-Management]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/media/terraform-caf-enterprise-scale-management.png "Diagram showing the Management resources for Cloud Adoption Framework Enterprise-scale Landing Zone architecture deployed by this module."
[//]: # (************************)
[//]: # (INSERT LINK LABELS BELOW)
@@ -146,6 +174,7 @@ module "enterprise_scale" {
[terraform-registry-caf-enterprise-scale]: https://registry.terraform.io/modules/Azure/caf-enterprise-scale/azurerm/latest "Terraform Registry: Terraform Module for Cloud Adoption Framework Enterprise-scale"
[ESLZ-Architecture]: https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/enterprise-scale/architecture
+[ESLZ-Management]: https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/enterprise-scale/management-and-monitoring
[arm_management_group]: https://docs.microsoft.com/en-us/azure/templates/microsoft.management/managementgroups
[arm_management_group_subscriptions]: https://docs.microsoft.com/en-us/azure/templates/microsoft.management/managementgroups/subscriptions
@@ -154,17 +183,27 @@ module "enterprise_scale" {
[arm_policy_set_definition]: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/policysetdefinitions
[arm_role_assignment]: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments
[arm_role_definition]: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roledefinitions
-
-[azurerm_management_group]: https://www.terraform.io/docs/providers/azurerm/r/management_group.html
-[azurerm_policy_assignment]: https://www.terraform.io/docs/providers/azurerm/r/policy_assignment.html
-[azurerm_policy_definition]: https://www.terraform.io/docs/providers/azurerm/r/policy_definition.html
-[azurerm_policy_set_definition]: https://www.terraform.io/docs/providers/azurerm/r/policy_set_definition.html
-[azurerm_role_assignment]: https://www.terraform.io/docs/providers/azurerm/r/role_assignment.html
-[azurerm_role_definition]: https://www.terraform.io/docs/providers/azurerm/r/role_definition.html
-
-[TFAES-LICENSE]: https://github.com/Azure/terraform-azurerm-enterprise-scale/blob/main/LICENSE
+[arm_resource_group]: https://docs.microsoft.com/en-us/azure/templates/microsoft.resources/resourcegroups
+[arm_log_analytics_workspace]: https://docs.microsoft.com/en-us/azure/templates/microsoft.operationalinsights/workspaces
+[arm_log_analytics_solution]: https://docs.microsoft.com/en-us/azure/templates/microsoft.operationsmanagement/solutions
+[arm_automation_account]: https://docs.microsoft.com/en-us/azure/templates/microsoft.automation/automationaccounts
+[arm_log_analytics_linked_service]: https://docs.microsoft.com/en-us/azure/templates/microsoft.operationalinsights/workspaces/linkedservices
+
+[azurerm_management_group]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/management_group
+[azurerm_policy_assignment]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/policy_assignment
+[azurerm_policy_definition]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/policy_definition
+[azurerm_policy_set_definition]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/policy_set_definition
+[azurerm_role_assignment]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment
+[azurerm_role_definition]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition
+[azurerm_resource_group]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group
+[azurerm_log_analytics_workspace]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_workspace
+[azurerm_log_analytics_solution]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_solution
+[azurerm_automation_account]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/automation_account
+[azurerm_log_analytics_linked_service]: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_linked_service
+
+[TFAES-LICENSE]: https://github.com/Azure/terraform-azurerm-enterprise-scale/blob/main/LICENSE
[TFAES-CONTRIBUTING]: https://github.com/Azure/terraform-azurerm-enterprise-scale/blob/main/CONTRIBUTING
-[TFAES-Library]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/terraform-azurerm-caf-enterprise-scale-archetypes/lib
+[TFAES-Library]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/terraform-azurerm-caf-enterprise-scale-archetypes/lib
[wiki_home]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Home "Wiki - Home"
[wiki_user_guide]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/User-Guide "Wiki - User Guide"
@@ -172,6 +211,8 @@ module "enterprise_scale" {
[wiki_module_variables]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Module-Variables "Wiki - Module Variables"
[wiki_archetype_definitions]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions "Wiki - Archetype Definitions"
[wiki_upgrade_from_v0_0_8_to_v0_1_0]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v0.0.8-to-v0.1.0 "Wiki - Upgrade from v0.0.8 to v0.1.0"
+[wiki_upgrade_from_v0_1_2_to_v0_2_0]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v0.1.2-to-v0.2.0 "Wiki - Upgrade from v0.1.2 to v0.2.0"
+[wiki_deploy_management_resources]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Deploy-Management-Resources "Wiki - Deploy Management Resources"
[wiki_examples]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Examples "Wiki - Examples"
[wiki_deploy_default_configuration]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Default-Configuration "Wiki - Deploy Default Configuration"
[wiki_deploy_demo_landing_zone_archetypes]: https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Demo-Landing-Zone-Archetypes "Wiki - Deploy Demo Landing Zone Archetypes"
diff --git a/locals.management.tf b/locals.management.tf
new file mode 100644
index 000000000..9bf4e2b4b
--- /dev/null
+++ b/locals.management.tf
@@ -0,0 +1,63 @@
+# The following locals are used to extract the Log Analytics
+# configuration from the solution module outputs.
+locals {
+ es_log_analytics_workspaces = module.management_resources.configuration.azurerm_log_analytics_workspace
+}
+
+# The following locals are used to build the map of Log
+# Analytics workspaces to deploy.
+locals {
+ azurerm_log_analytics_workspace_enterprise_scale = {
+ for resource in local.es_log_analytics_workspaces :
+ resource.resource_id => resource
+ if resource.managed_by_module
+ }
+}
+
+# The following locals are used to extract the Log Analytics
+# Solutions configuration from the solution module outputs.
+locals {
+ es_log_analytics_solution = module.management_resources.configuration.azurerm_log_analytics_solution
+}
+
+# The following locals are used to build the map of Log
+# Analytics workspaces to deploy.
+locals {
+ azurerm_log_analytics_solution_enterprise_scale = {
+ for resource in local.es_log_analytics_solution :
+ resource.resource_id => resource
+ if resource.managed_by_module
+ }
+}
+
+# The following locals are used to extract the Automation
+# Account configuration from the solution module outputs.
+locals {
+ es_automation_account = module.management_resources.configuration.azurerm_automation_account
+}
+
+# The following locals are used to build the map of Log
+# Analytics workspaces to deploy.
+locals {
+ azurerm_automation_account_enterprise_scale = {
+ for resource in local.es_automation_account :
+ resource.resource_id => resource
+ if resource.managed_by_module
+ }
+}
+
+# The following locals are used to extract the Log Analytics
+# Linked Service configuration from the solution module outputs.
+locals {
+ es_log_analytics_linked_service = module.management_resources.configuration.azurerm_log_analytics_linked_service
+}
+
+# The following locals are used to build the map of Log
+# Analytics workspaces to deploy.
+locals {
+ azurerm_log_analytics_linked_service_enterprise_scale = {
+ for resource in local.es_log_analytics_linked_service :
+ resource.resource_id => resource
+ if resource.managed_by_module
+ }
+}
diff --git a/locals.management_groups.tf b/locals.management_groups.tf
index 1b2349716..f501ece52 100644
--- a/locals.management_groups.tf
+++ b/locals.management_groups.tf
@@ -206,7 +206,14 @@ locals {
display_name = value.display_name
parent_management_group_id = try(length(value.parent_management_group_id) > 0, false) ? replace(lower(value.parent_management_group_id), "/[^a-z0-9]/", "-") : local.root_parent_id
subscription_ids = value.subscription_ids
- archetype_config = value.archetype_config
+ archetype_config = {
+ archetype_id = value.archetype_config.archetype_id
+ access_control = value.archetype_config.access_control
+ parameters = merge(
+ value.archetype_config.parameters,
+ try(module.management_resources.configuration.archetype_config_overrides[key].parameters, null),
+ )
+ }
}
}
}
diff --git a/locals.policy_assignments.tf b/locals.policy_assignments.tf
index 15af4ce26..6657400e6 100644
--- a/locals.policy_assignments.tf
+++ b/locals.policy_assignments.tf
@@ -3,7 +3,7 @@
locals {
es_policy_assignments_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
- archetype.configuration.policy_assignments
+ archetype.configuration.azurerm_policy_assignment
])
es_policy_assignments_by_subscription = []
es_policy_assignments = concat(
@@ -221,12 +221,11 @@ locals {
for policy_assignment_id, policy_id in local.policy_assignments_with_managed_identity : [
for role_definition_id in try(local.policy_roles[policy_id], local.empty_list) : [
{
- resource_id = "${local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id}${local.provider_path.role_assignment}${uuidv5(uuidv5("url", role_definition_id), policy_assignment_id)}"
- scope_id = local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id
- principal_id = try(azurerm_policy_assignment.enterprise_scale[policy_assignment_id].identity[0].principal_id, null)
- role_definition_name = null
- role_definition_id = role_definition_id
- skip_service_principal_aad_check = true
+ resource_id = "${local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id}${local.provider_path.role_assignment}${uuidv5(uuidv5("url", role_definition_id), policy_assignment_id)}"
+ scope_id = local.azurerm_policy_assignment_enterprise_scale[policy_assignment_id].scope_id
+ principal_id = try(azurerm_policy_assignment.enterprise_scale[policy_assignment_id].identity[0].principal_id, null)
+ role_definition_name = null
+ role_definition_id = role_definition_id
}
]
]
diff --git a/locals.policy_definitions.tf b/locals.policy_definitions.tf
index 036524184..c2458f221 100644
--- a/locals.policy_definitions.tf
+++ b/locals.policy_definitions.tf
@@ -3,7 +3,7 @@
locals {
es_policy_definitions_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
- archetype.configuration.policy_definitions
+ archetype.configuration.azurerm_policy_definition
])
es_policy_definitions_by_subscription = []
es_policy_definitions = concat(
diff --git a/locals.policy_set_definitions.tf b/locals.policy_set_definitions.tf
index a32a83bc9..4ff23ae16 100644
--- a/locals.policy_set_definitions.tf
+++ b/locals.policy_set_definitions.tf
@@ -3,7 +3,7 @@
locals {
es_policy_set_definitions_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
- archetype.configuration.policy_set_definitions
+ archetype.configuration.azurerm_policy_set_definition
])
es_policy_set_definitions_by_subscription = []
es_policy_set_definitions = concat(
diff --git a/locals.resource_groups.tf b/locals.resource_groups.tf
new file mode 100644
index 000000000..6b5142b2b
--- /dev/null
+++ b/locals.resource_groups.tf
@@ -0,0 +1,22 @@
+# The following locals are used to extract the Resource Group
+# configuration from the solution module outputs.
+locals {
+ es_resource_groups = concat(
+ # module.connectivity_hub_spoke_resources.configuration.azurerm_resource_group,
+ # module.connectivity_virtual_wan_resources.configuration.azurerm_resource_group,
+ # module.identity_resources.configuration.azurerm_resource_group,
+ # module.landing_zone_hub_spoke_resources.configuration.azurerm_resource_group,
+ # module.landing_zone_virtual_wan_resources.configuration.azurerm_resource_group,
+ module.management_resources.configuration.azurerm_resource_group,
+ )
+}
+
+# The following locals are used to build the map of Resource
+# Groups to deploy.
+locals {
+ azurerm_resource_group_enterprise_scale = {
+ for resource in local.es_resource_groups :
+ resource.resource_id => resource
+ if resource.managed_by_module
+ }
+}
diff --git a/locals.role_assignments.tf b/locals.role_assignments.tf
index e986d8f83..54728ef5d 100644
--- a/locals.role_assignments.tf
+++ b/locals.role_assignments.tf
@@ -3,7 +3,7 @@
locals {
es_role_assignments_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
- archetype.configuration.role_assignments
+ archetype.configuration.azurerm_role_assignment
])
es_role_assignments_by_subscription = []
es_role_assignments = concat(
diff --git a/locals.role_definitions.tf b/locals.role_definitions.tf
index ef8f4d77d..fe5b8ffdc 100644
--- a/locals.role_definitions.tf
+++ b/locals.role_definitions.tf
@@ -3,7 +3,7 @@
locals {
es_role_definitions_by_management_group = flatten([
for archetype in values(module.management_group_archetypes) :
- archetype.configuration.role_definitions
+ archetype.configuration.azurerm_role_definition
])
es_role_definitions_by_subscription = []
es_role_definitions = concat(
diff --git a/locals.tf b/locals.tf
index 0526d3449..65db9b4c5 100644
--- a/locals.tf
+++ b/locals.tf
@@ -6,21 +6,27 @@ locals {
empty_string = ""
}
-# The following locals are used to convert basic input
+# The following locals are used to convert provided input
# variables to locals before use elsewhere in the module
locals {
- root_id = var.root_id
- root_name = var.root_name
- root_parent_id = var.root_parent_id
- deploy_core_landing_zones = var.deploy_core_landing_zones
- archetype_config_overrides = var.archetype_config_overrides
- subscription_id_overrides = var.subscription_id_overrides
- deploy_demo_landing_zones = var.deploy_demo_landing_zones
- custom_landing_zones = var.custom_landing_zones
- library_path = var.library_path
- template_file_variables = var.template_file_variables
- default_location = var.default_location
- custom_policy_roles = var.custom_policy_roles
+ root_id = var.root_id
+ root_name = var.root_name
+ root_parent_id = var.root_parent_id
+ deploy_core_landing_zones = var.deploy_core_landing_zones
+ deploy_demo_landing_zones = var.deploy_demo_landing_zones
+ deploy_management_resources = var.deploy_management_resources
+ configure_management_resources = var.configure_management_resources
+ archetype_config_overrides = var.archetype_config_overrides
+ subscription_id_overrides = var.subscription_id_overrides
+ subscription_id_connectivity = var.subscription_id_connectivity
+ subscription_id_identity = var.subscription_id_identity
+ subscription_id_management = var.subscription_id_management
+ custom_landing_zones = var.custom_landing_zones
+ custom_policy_roles = var.custom_policy_roles
+ library_path = var.library_path
+ template_file_variables = var.template_file_variables
+ default_location = var.default_location
+ default_tags = var.default_tags
}
# The following locals are used to define base Azure
@@ -38,15 +44,25 @@ locals {
# The following locals are used to define RegEx
# patterns used within this module
-
locals {
regex_extract_provider_scope = "(?i)/(?=.*/providers/)[^/]+/[\\S]+(?=.*/providers/)"
}
+# The following locals are used to identify known
+# sensitive attributes generated when resources
+# are created
+locals {
+ sensitive_attributes = {
+ azurerm_log_analytics_workspace = [
+ "primary_shared_key",
+ "secondary_shared_key",
+ ]
+ }
+}
+
# The following locals are used to control time_sleep
# delays between resources to reduce transient errors
# relating to replication delays in Azure
-
locals {
default_create_duration_delay = "30s"
default_destroy_duration_delay = "0s"
diff --git a/main.tf b/main.tf
index d7cb5a823..6dcfa8d63 100644
--- a/main.tf
+++ b/main.tf
@@ -12,8 +12,35 @@ module "management_group_archetypes" {
scope_id = each.key
archetype_id = each.value.archetype_config.archetype_id
parameters = each.value.archetype_config.parameters
+ enforcement_mode = try(module.management_resources.configuration.archetype_config_overrides[basename(each.key)].enforcement_mode, null)
access_control = each.value.archetype_config.access_control
library_path = local.library_path
template_file_variables = local.template_file_variables
default_location = local.default_location
}
+
+# The following module is used to generate the configuration
+# data used to deploy platform resources based on the
+# "management" landing zone archetype.
+module "management_resources" {
+ source = "./modules/management"
+
+ # Mandatory input variables
+ enabled = local.deploy_management_resources
+ root_id = local.root_id
+ subscription_id = local.subscription_id_management
+ settings = local.configure_management_resources.settings
+
+ # Optional input variables (basic configuration)
+ location = coalesce(local.configure_management_resources.location, local.default_location)
+ tags = coalesce(local.configure_management_resources.tags, local.default_tags)
+
+ # Optional input variables (advanced configuration)
+ resource_prefix = try(local.configure_management_resources.advanced.resource_prefix, local.empty_string)
+ resource_suffix = try(local.configure_management_resources.advanced.resource_suffix, local.empty_string)
+ existing_resource_group_name = try(local.configure_management_resources.advanced.existing_resource_group_name, local.empty_string)
+ existing_log_analytics_workspace_resource_id = try(local.configure_management_resources.advanced.existing_log_analytics_workspace_resource_id, local.empty_string)
+ existing_automation_account_resource_id = try(local.configure_management_resources.advanced.existing_automation_account_resource_id, local.empty_string)
+ link_log_analytics_to_automation_account = try(local.configure_management_resources.advanced.link_log_analytics_to_automation_account, true)
+ custom_settings_by_resource_type = try(local.configure_management_resources.advanced.custom_settings_by_resource_type, local.empty_map)
+}
diff --git a/modules/archetypes/lib/archetype_definitions/archetype_definition_es_root.tmpl.json b/modules/archetypes/lib/archetype_definitions/archetype_definition_es_root.tmpl.json
index 199d682f6..bc4899afd 100644
--- a/modules/archetypes/lib/archetype_definitions/archetype_definition_es_root.tmpl.json
+++ b/modules/archetypes/lib/archetype_definitions/archetype_definition_es_root.tmpl.json
@@ -42,7 +42,17 @@
"Deny-Subnet-Without-Udr",
"Deny-VNET-Peer-Cross-Sub",
"Deny-VNet-Peering",
- "Deploy-ASC-Standard",
+ "Deploy-ASC-Defender-ACR",
+ "Deploy-ASC-Defender-AKS",
+ "Deploy-ASC-Defender-AKV",
+ "Deploy-ASC-Defender-AppSrv",
+ "Deploy-ASC-Defender-ARM",
+ "Deploy-ASC-Defender-DNS",
+ "Deploy-ASC-Defender-SA",
+ "Deploy-ASC-Defender-Sql",
+ "Deploy-ASC-Defender-SQLVM",
+ "Deploy-ASC-Defender-VMs",
+ "Deploy-ASC-SecurityContacts",
"Deploy-Budget",
"Deploy-DDoSProtection",
"Deploy-Diagnostics-AA",
@@ -85,7 +95,6 @@
"Deploy-Diagnostics-NIC",
"Deploy-Diagnostics-PostgreSQL",
"Deploy-Diagnostics-PowerBIEmbedded",
- "Deploy-Diagnostics-PublicIP",
"Deploy-Diagnostics-RecoveryVault",
"Deploy-Diagnostics-RedisCache",
"Deploy-Diagnostics-Relay",
@@ -136,6 +145,7 @@
],
"policy_set_definitions": [
"Deny-PublicEndpoints",
+ "Deploy-ASC-Config",
"Deploy-Diag-LogAnalytics",
"Deploy-Sql-Security",
"Enforce-Encryption-CMK",
diff --git a/modules/archetypes/lib/policy_assignments/policy_assignment_es_deploy_asc_defender.tmpl.json b/modules/archetypes/lib/policy_assignments/policy_assignment_es_deploy_asc_defender.tmpl.json
index 6230f699e..cfadd4b5b 100644
--- a/modules/archetypes/lib/policy_assignments/policy_assignment_es_deploy_asc_defender.tmpl.json
+++ b/modules/archetypes/lib/policy_assignments/policy_assignment_es_deploy_asc_defender.tmpl.json
@@ -6,8 +6,21 @@
"description": "Deploy-ASC-Defender.",
"displayName": "Deploy-ASC-Defender",
"notScopes": [],
- "parameters": {},
- "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Standard",
+ "parameters": {
+ "emailSecurityContact": {
+ "value": "security_contact@replace_me"
+ },
+ "logAnalytics": {
+ "value": "${root_scope_id}-a-00000000-0000-0000-0000-000000000000"
+ },
+ "ascExportResourceGroupName": {
+ "value": "${root_scope_id}-asc-export"
+ },
+ "ascExportResourceGroupLocation": {
+ "value": "${default_location}"
+ }
+ },
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policySetDefinitions/Deploy-ASC-Config",
"scope": "${current_scope_resource_id}",
"enforcementMode": "Default"
},
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_acr.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_acr.json
new file mode 100644
index 000000000..0114c749a
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_acr.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-ACR",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for ACR",
+ "description": "Deploy the Azure Defender settings for Azure Container Registry",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "ContainerRegistry",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "ContainerRegistry",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_aks.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_aks.json
new file mode 100644
index 000000000..35ace7808
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_aks.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-AKS",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for AKS",
+ "description": "Deploy the Azure Defender settings for AKS",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "KubernetesService",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "KubernetesService",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_akv.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_akv.json
new file mode 100644
index 000000000..1682e5e32
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_akv.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-AKV",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for AKV",
+ "description": "Deploy the Azure Defender settings for Azure Key Vault",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "KeyVaults",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "KeyVaults",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_appsrv.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_appsrv.json
new file mode 100644
index 000000000..7637026fd
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_appsrv.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-AppSrv",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for Azure App Services",
+ "description": "Deploy the Azure Defender settings in Azure Security Center for Azure App Services",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "AppServices",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "AppServices",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_arm.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_arm.json
new file mode 100644
index 000000000..d21b9c1a1
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_arm.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-ARM",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for ARM",
+ "description": "Deploy the Azure Defender settings for Azure Resource Manager",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "Arm",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "Arm",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_dns.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_dns.json
new file mode 100644
index 000000000..64cbf36b1
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_dns.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-DNS",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for DNS",
+ "description": "Deploy the Azure Defender settings for DNS",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "Dns",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "Dns",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sa.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sa.json
new file mode 100644
index 000000000..7628839dc
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sa.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-SA",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for Storage Accounts",
+ "description": "Deploy the Azure Defender settings in Azure Security Center for Storage Accounts",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "StorageAccounts",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "StorageAccounts",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sql.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sql.json
new file mode 100644
index 000000000..95f509e01
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sql.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-Sql",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for Azure Sql Databases",
+ "description": "Deploy the Azure Defender settings in Azure Security Center for Azure Sql Databases",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "SqlServers",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "SqlServers",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sqlvm.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sqlvm.json
new file mode 100644
index 000000000..79efe537d
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_sqlvm.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-SQLVM",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for Sql on Virtual Machines",
+ "description": "Deploy the Azure Defender settings in Sql Server on Virtual Machines",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "SqlServerVirtualMachines",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "SqlServerVirtualMachines",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_vms.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_vms.json
new file mode 100644
index 000000000..da350dc36
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_defender_vms.json
@@ -0,0 +1,111 @@
+{
+ "name": "Deploy-ASC-Defender-VMs",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Defender for Virtual Machines",
+ "description": "Deploy the Azure Defender settings in Azure Security Center for Virtual Machines",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier",
+ "description": "Azure Defender pricing tier"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/pricings",
+ "name": "VirtualMachines",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/pricings/pricingTier",
+ "equals": "[parameters('pricingTier')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/pricings"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTier')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "pricingTier": {
+ "type": "string",
+ "metadata": {
+ "description": "Azure Defender pricing tier"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/pricings",
+ "apiVersion": "2018-06-01",
+ "name": "VirtualMachines",
+ "properties": {
+ "pricingTier": "[parameters('pricingTier')]"
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_securitycontacts.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_securitycontacts.json
new file mode 100644
index 000000000..0c7f3c778
--- /dev/null
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_securitycontacts.json
@@ -0,0 +1,123 @@
+{
+ "name": "Deploy-ASC-SecurityContacts",
+ "type": "Microsoft.Authorization/policyDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "mode": "All",
+ "displayName": "Deploy Azure Security Center Security Contacts",
+ "description": "Deploy Azure Security Center Security Contacts",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "emailSecurityContact": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Security contacts email address",
+ "description": "Provide email address for Azure Security Center contact details"
+ }
+ },
+ "effect": {
+ "type": "string",
+ "defaultValue": "DeployIfNotExists",
+ "allowedValues": [
+ "DeployIfNotExists",
+ "Disabled"
+ ],
+ "metadata": {
+ "displayName": "Effect",
+ "description": "Enable or disable the execution of the policy"
+ }
+ }
+ },
+ "policyRule": {
+ "if": {
+ "allOf": [
+ {
+ "field": "type",
+ "equals": "Microsoft.Resources/subscriptions"
+ }
+ ]
+ },
+ "then": {
+ "effect": "[parameters('effect')]",
+ "details": {
+ "type": "Microsoft.Security/securityContacts",
+ "deploymentScope": "Subscription",
+ "existenceScope": "Subscription",
+ "roleDefinitionIds": [
+ "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
+ ],
+ "existenceCondition": {
+ "allOf": [
+ {
+ "field": "Microsoft.Security/securityContacts/email",
+ "contains": "[parameters('emailSecurityContact')]"
+ },
+ {
+ "field": "type",
+ "equals": "Microsoft.Security/securityContacts"
+ },
+ {
+ "field": "Microsoft.Security/securityContacts/alertNotifications",
+ "equals": "On"
+ },
+ {
+ "field": "Microsoft.Security/securityContacts/alertsToAdmins",
+ "equals": "On"
+ }
+ ]
+ },
+ "deployment": {
+ "location": "northeurope",
+ "properties": {
+ "mode": "incremental",
+ "parameters": {
+ "emailSecurityContact": {
+ "value": "[parameters('emailSecurityContact')]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "emailSecurityContact": {
+ "type": "string",
+ "metadata": {
+ "description": "Security contacts email address"
+ }
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.Security/securityContacts",
+ "name": "default",
+ "apiVersion": "2020-01-01-preview",
+ "properties": {
+ "emails": "[parameters('emailSecurityContact')]",
+ "notificationsByRole": {
+ "state": "On",
+ "roles": [
+ "Owner"
+ ]
+ },
+ "alertNotifications": {
+ "state": "On",
+ "minimalSeverity": "High"
+ }
+ }
+ }
+ ],
+ "outputs": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_standard.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_standard.json
deleted file mode 100644
index caadf6385..000000000
--- a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_asc_standard.json
+++ /dev/null
@@ -1,357 +0,0 @@
-{
- "name": "Deploy-ASC-Standard",
- "type": "Microsoft.Authorization/policyDefinitions",
- "apiVersion": "2020-09-01",
- "scope": null,
- "properties": {
- "policyType": "Custom",
- "mode": "All",
- "displayName": "Deploy Azure Defender settings in Azure Security Center.",
- "description": "Deploys the Azure Defender settings in Azure Security Center for the specific services.",
- "metadata": {
- "version": "1.0.0",
- "category": "Security Center"
- },
- "parameters": {
- "pricingTierVMs": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierVMs"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierSqlServers": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierSqlServers"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierAppServices": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierAppServices"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierStorageAccounts": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierStorageAccounts"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierContainerRegistry": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierContainerRegistry"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierKeyVaults": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierKeyVaults"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierKubernetesService": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierKubernetesService"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierDns": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierDns"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "pricingTierArm": {
- "type": "String",
- "metadata": {
- "displayName": "pricingTierArm"
- },
- "allowedValues": [
- "Standard",
- "Free"
- ],
- "defaultValue": "Standard"
- },
- "effect": {
- "type": "String",
- "defaultValue": "DeployIfNotExists",
- "allowedValues": [
- "DeployIfNotExists",
- "Disabled"
- ],
- "metadata": {
- "displayName": "Effect",
- "description": "Enable or disable the execution of the policy"
- }
- }
- },
- "policyRule": {
- "if": {
- "allOf": [
- {
- "field": "type",
- "equals": "Microsoft.Resources/subscriptions"
- }
- ]
- },
- "then": {
- "effect": "[parameters('effect')]",
- "details": {
- "type": "Microsoft.Security/pricings",
- "deploymentScope": "subscription",
- "existenceScope": "subscription",
- "roleDefinitionIds": [
- "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd"
- ],
- "existenceCondition": {
- "allOf": [
- {
- "field": "Microsoft.Security/pricings/pricingTier",
- "equals": "Standard"
- },
- {
- "field": "type",
- "equals": "Microsoft.Security/pricings"
- }
- ]
- },
- "deployment": {
- "location": "northeurope",
- "properties": {
- "mode": "Incremental",
- "parameters": {
- "pricingTierVMs": {
- "value": "[parameters('pricingTierVMs')]"
- },
- "pricingTierSqlServers": {
- "value": "[parameters('pricingTierSqlServers')]"
- },
- "pricingTierAppServices": {
- "value": "[parameters('pricingTierAppServices')]"
- },
- "pricingTierStorageAccounts": {
- "value": "[parameters('pricingTierStorageAccounts')]"
- },
- "pricingTierContainerRegistry": {
- "value": "[parameters('pricingTierContainerRegistry')]"
- },
- "pricingTierKeyVaults": {
- "value": "[parameters('pricingTierKeyVaults')]"
- },
- "pricingTierKubernetesService": {
- "value": "[parameters('pricingTierKubernetesService')]"
- },
- "pricingTierDns": {
- "value": "[parameters('pricingTierDns')]"
- },
- "pricingTierArm": {
- "value": "[parameters('pricingTierArm')]"
- }
- },
- "template": {
- "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
- "contentVersion": "1.0.0.0",
- "parameters": {
- "pricingTierVMs": {
- "type": "String",
- "metadata": {
- "description": "pricingTierVMs"
- }
- },
- "pricingTierSqlServers": {
- "type": "String",
- "metadata": {
- "description": "pricingTierSqlServers"
- }
- },
- "pricingTierAppServices": {
- "type": "String",
- "metadata": {
- "description": "pricingTierAppServices"
- }
- },
- "pricingTierStorageAccounts": {
- "type": "String",
- "metadata": {
- "description": "pricingTierStorageAccounts"
- }
- },
- "pricingTierContainerRegistry": {
- "type": "String",
- "metadata": {
- "description": "ContainerRegistry"
- }
- },
- "pricingTierKeyVaults": {
- "type": "String",
- "metadata": {
- "description": "KeyVaults"
- }
- },
- "pricingTierKubernetesService": {
- "type": "String",
- "metadata": {
- "description": "KubernetesService"
- }
- },
- "pricingTierDns": {
- "type": "String",
- "metadata": {
- "description": "KubernetesService"
- }
- },
- "pricingTierArm": {
- "type": "String",
- "metadata": {
- "description": "KubernetesService"
- }
- }
- },
- "variables": {},
- "resources": [
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "VirtualMachines",
- "properties": {
- "pricingTier": "[parameters('pricingTierVMs')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "StorageAccounts",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/VirtualMachines')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierStorageAccounts')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "AppServices",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/StorageAccounts')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierAppServices')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "SqlServers",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/AppServices')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierSqlServers')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "KeyVaults",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/SqlServers')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierKeyVaults')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "KubernetesService",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/KeyVaults')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierKubernetesService')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "ContainerRegistry",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/KubernetesService')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierContainerRegistry')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "Dns",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/ContainerRegistry')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierDns')]"
- }
- },
- {
- "type": "Microsoft.Security/pricings",
- "apiVersion": "2018-06-01",
- "name": "Arm",
- "dependsOn": [
- "[concat('Microsoft.Security/pricings/Dns')]"
- ],
- "properties": {
- "pricingTier": "[parameters('pricingTierArm')]"
- }
- }
- ],
- "outputs": {}
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_diagnostics_publicip.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_diagnostics_publicip.json
deleted file mode 100644
index 43b335bf0..000000000
--- a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_diagnostics_publicip.json
+++ /dev/null
@@ -1,191 +0,0 @@
-{
- "name": "Deploy-Diagnostics-PublicIP",
- "type": "Microsoft.Authorization/policyDefinitions",
- "apiVersion": "2020-09-01",
- "scope": null,
- "properties": {
- "policyType": "Custom",
- "mode": "Indexed",
- "displayName": "Deploy Diagnostic Settings for Public IP addresses to Log Analytics workspace",
- "description": "Deploys the diagnostic settings for Public IP addresses to stream to a Log Analytics workspace when any Public IP addresses which is missing this diagnostic settings is created or updated. The policy wil set the diagnostic with all metrics and category enabled",
- "metadata": {
- "version": "1.0.0",
- "category": "Monitoring"
- },
- "parameters": {
- "logAnalytics": {
- "type": "String",
- "metadata": {
- "displayName": "Log Analytics workspace",
- "description": "Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.",
- "strongType": "omsWorkspace"
- }
- },
- "effect": {
- "type": "String",
- "defaultValue": "DeployIfNotExists",
- "allowedValues": [
- "DeployIfNotExists",
- "Disabled"
- ],
- "metadata": {
- "displayName": "Effect",
- "description": "Enable or disable the execution of the policy"
- }
- },
- "profileName": {
- "type": "String",
- "defaultValue": "setbypolicy",
- "metadata": {
- "displayName": "Profile name",
- "description": "The diagnostic settings profile name"
- }
- },
- "metricsEnabled": {
- "type": "String",
- "defaultValue": "True",
- "allowedValues": [
- "True",
- "False"
- ],
- "metadata": {
- "displayName": "Enable metrics",
- "description": "Whether to enable metrics stream to the Log Analytics workspace - True or False"
- }
- },
- "logsEnabled": {
- "type": "String",
- "defaultValue": "True",
- "allowedValues": [
- "True",
- "False"
- ],
- "metadata": {
- "displayName": "Enable logs",
- "description": "Whether to enable logs stream to the Log Analytics workspace - True or False"
- }
- }
- },
- "policyRule": {
- "if": {
- "field": "type",
- "equals": "Microsoft.Network/publicIPAddresses"
- },
- "then": {
- "effect": "[parameters('effect')]",
- "details": {
- "type": "Microsoft.Insights/diagnosticSettings",
- "name": "setByPolicy",
- "existenceCondition": {
- "allOf": [
- {
- "field": "Microsoft.Insights/diagnosticSettings/logs.enabled",
- "equals": "true"
- },
- {
- "field": "Microsoft.Insights/diagnosticSettings/metrics.enabled",
- "equals": "true"
- },
- {
- "field": "Microsoft.Insights/diagnosticSettings/workspaceId",
- "equals": "[parameters('logAnalytics')]"
- }
- ]
- },
- "roleDefinitionIds": [
- "/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa",
- "/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293"
- ],
- "deployment": {
- "properties": {
- "mode": "Incremental",
- "template": {
- "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
- "contentVersion": "1.0.0.0",
- "parameters": {
- "resourceName": {
- "type": "String"
- },
- "logAnalytics": {
- "type": "String"
- },
- "location": {
- "type": "String"
- },
- "profileName": {
- "type": "String"
- },
- "metricsEnabled": {
- "type": "String"
- },
- "logsEnabled": {
- "type": "String"
- }
- },
- "variables": {},
- "resources": [
- {
- "type": "Microsoft.Network/publicIPAddresses/providers/diagnosticSettings",
- "apiVersion": "2017-05-01-preview",
- "name": "[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]",
- "location": "[parameters('location')]",
- "dependsOn": [],
- "properties": {
- "workspaceId": "[parameters('logAnalytics')]",
- "metrics": [
- {
- "category": "AllMetrics",
- "timeGrain": null,
- "enabled": "[parameters('metricsEnabled')]",
- "retentionPolicy": {
- "enabled": false,
- "days": 0
- }
- }
- ],
- "logs": [
- {
- "category": "DDoSProtectionNotifications",
- "enabled": "[parameters('logsEnabled')]"
- },
- {
- "category": "DDoSMitigationFlowLogs",
- "enabled": "[parameters('logsEnabled')]"
- },
- {
- "category": "DDoSMitigationReports",
- "enabled": "[parameters('logsEnabled')]"
- }
- ]
- }
- }
- ],
- "outputs": {}
- },
- "parameters": {
- "logAnalytics": {
- "value": "[parameters('logAnalytics')]"
- },
- "location": {
- "value": "[field('location')]"
- },
- "resourceName": {
- "value": "[field('name')]"
- },
- "profileName": {
- "value": "[parameters('profileName')]"
- },
- "metricsEnabled": {
- "value": "[parameters('metricsEnabled')]"
- },
- "logsEnabled": {
- "value": "[parameters('logsEnabled')]"
- }
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_log_analytics.json b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_log_analytics.json
index 6bff082af..407a92d1a 100644
--- a/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_log_analytics.json
+++ b/modules/archetypes/lib/policy_definitions/policy_definition_es_deploy_log_analytics.json
@@ -176,18 +176,18 @@
"comments": "Automation account for ",
"properties": {
"sku": {
- "name": "OMS"
+ "name": "Basic"
}
}
},
{
- "apiVersion": "2017-03-15-preview",
+ "apiVersion": "2020-08-01",
"location": "[parameters('workspaceRegion')]",
"name": "[parameters('workspaceName')]",
"type": "Microsoft.OperationalInsights/workspaces",
"properties": {
"sku": {
- "name": "pernode"
+ "name": "PerGB2018"
},
"enableLogAccessUsingOnlyResourcePermissions": true,
"retentionInDays": "[int(parameters('retentionInDays'))]"
@@ -196,7 +196,7 @@
{
"name": "Automation",
"type": "linkedServices",
- "apiVersion": "2015-11-01-preview",
+ "apiVersion": "2020-08-01",
"dependsOn": [
"[resourceId('Microsoft.OperationalInsights/workspaces/', parameters('workspaceName'))]",
"[resourceId('Microsoft.Automation/automationAccounts/', parameters('AutomationAccountName'))]"
diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_asc_config.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_asc_config.tmpl.json
new file mode 100644
index 000000000..d0e3bb224
--- /dev/null
+++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_asc_config.tmpl.json
@@ -0,0 +1,295 @@
+{
+ "name": "Deploy-ASC-Config",
+ "type": "Microsoft.Authorization/policySetDefinitions",
+ "apiVersion": "2020-09-01",
+ "scope": null,
+ "properties": {
+ "policyType": "Custom",
+ "displayName": "Deploy Azure Security Center configuration",
+ "description": "Deploy Azure Security Center configuration",
+ "metadata": {
+ "version": "1.0.0",
+ "category": "Security Center"
+ },
+ "parameters": {
+ "emailSecurityContact": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Security contacts email address",
+ "description": "Provide email address for Azure Security Center contact details"
+ }
+ },
+ "logAnalytics": {
+ "type": "String",
+ "metadata": {
+ "displayName": "Primary Log Analytics workspace",
+ "description": "Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.",
+ "strongType": "omsWorkspace"
+ }
+ },
+ "ascExportResourceGroupName": {
+ "type": "String",
+ "metadata": {
+ "displayName": "Resource Group name for the export to Log Analytics workspace configuration",
+ "description": "The resource group name where the export to Log Analytics workspace configuration is created. If you enter a name for a resource group that doesn't exist, it'll be created in the subscription. Note that each resource group can only have one export to Log Analytics workspace configured."
+ }
+ },
+ "ascExportResourceGroupLocation": {
+ "type": "String",
+ "metadata": {
+ "displayName": "Resource Group location for the export to Log Analytics workspace configuration",
+ "description": "The location where the resource group and the export to Log Analytics workspace configuration are created."
+ }
+ },
+ "pricingTierVMs": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for Virtual Machines",
+ "description": "Azure Defender pricing tier for Virtual Machines"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierSqlServers": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for SQL Servers",
+ "description": "Azure Defender pricing tier for SQL Servers"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierAppServices": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for App Services",
+ "description": "Azure Defender pricing tier for App Services"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierStorageAccounts": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for Storage Accounts",
+ "description": "Azure Defender pricing tier for Storage Accounts"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierSqlServerVirtualMachines": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for SQL Server Virtual Machines",
+ "description": "Azure Defender pricing tier for SQL Server Virtual Machines"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierKubernetesService": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for AKS",
+ "description": "Azure Defender pricing tier for AKS"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierContainerRegistry": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for ACR",
+ "description": "Azure Defender pricing tier for ACR"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierKeyVaults": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for AKV",
+ "description": "Azure Defender pricing tier for AKV"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierDns": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for DNS",
+ "description": "Azure Defender pricing tier for DNS"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ },
+ "pricingTierArm": {
+ "type": "string",
+ "metadata": {
+ "displayName": "Azure Defender pricing tier for Azure Resource Manager",
+ "description": "Azure Defender pricing tier for Azure Resource Manager"
+ },
+ "allowedValues": [
+ "Standard",
+ "Free"
+ ],
+ "defaultValue": "Standard"
+ }
+ },
+ "policyDefinitions": [
+ {
+ "policyDefinitionReferenceId": "defenderForVM",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-VMs",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierVMs')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForSqlServers",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-Sql",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierSqlServers')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForAppServices",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-AppSrv",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierAppServices')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForStorageAccounts",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-SA",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierStorageAccounts')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForSqlServerVirtualMachines",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-SQLVM",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierSqlServerVirtualMachines')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForKubernetesService",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-AKS",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierKubernetesService')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForContainerRegistry",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-ACR",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierContainerRegistry')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForKeyVaults",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-AKV",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierKeyVaults')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForDns",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-DNS",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierDns')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "defenderForArm",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-Defender-ARM",
+ "parameters": {
+ "pricingTier": {
+ "value": "[parameters('pricingTierArm')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "securityEmailContact",
+ "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-ASC-SecurityContacts",
+ "parameters": {
+ "emailSecurityContact": {
+ "value": "[parameters('emailSecurityContact')]"
+ }
+ },
+ "groupNames": []
+ },
+ {
+ "policyDefinitionReferenceId": "ascExport",
+ "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/ffb6f416-7bd2-4488-8828-56585fef2be9",
+ "parameters": {
+ "resourceGroupName": {
+ "value": "[parameters('ascExportResourceGroupName')]"
+ },
+ "resourceGroupLocation": {
+ "value": "[parameters('ascExportResourceGroupLocation')]"
+ },
+ "workspaceResourceId": {
+ "value": "[parameters('logAnalytics')]"
+ }
+ },
+ "groupNames": []
+ }
+ ],
+ "policyDefinitionGroups": null
+ }
+}
\ No newline at end of file
diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_diag_loganalytics.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_diag_loganalytics.tmpl.json
index a8c234024..69138ebc3 100644
--- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_diag_loganalytics.tmpl.json
+++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_diag_loganalytics.tmpl.json
@@ -1461,7 +1461,7 @@
},
{
"policyDefinitionReferenceId": "NetworkPublicIPNicDeployDiagnosticLogDeployLogAnalytics",
- "policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-PublicIP",
+ "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/752154a7-1e0f-45c6-a880-ac75a7e4f648",
"parameters": {
"logAnalytics": {
"value": "[parameters('logAnalytics')]"
@@ -1471,6 +1471,9 @@
},
"profileName": {
"value": "[parameters('profileName')]"
+ },
+ "metricsEnabled": {
+ "value": "True"
}
},
"groupNames": []
diff --git a/modules/archetypes/locals.archetype_definitions.tf b/modules/archetypes/locals.archetype_definitions.tf
index 7f13bb470..df06ff333 100644
--- a/modules/archetypes/locals.archetype_definitions.tf
+++ b/modules/archetypes/locals.archetype_definitions.tf
@@ -174,14 +174,3 @@ locals {
locals {
archetype_definition = local.archetype_definitions[local.archetype_id]
}
-
-# Generate the configuration output object for the specified archetype
-locals {
- archetype_output = {
- policy_assignments = local.archetype_policy_assignments_output
- policy_definitions = local.archetype_policy_definitions_output
- policy_set_definitions = local.archetype_policy_set_definitions_output
- role_assignments = local.archetype_role_assignments_output
- role_definitions = local.archetype_role_definitions_output
- }
-}
diff --git a/modules/archetypes/locals.policy_assignments.tf b/modules/archetypes/locals.policy_assignments.tf
index 0191117e5..cfa51289a 100644
--- a/modules/archetypes/locals.policy_assignments.tf
+++ b/modules/archetypes/locals.policy_assignments.tf
@@ -95,20 +95,32 @@ locals {
# variable. These come from the archetype_config object in
# the enterprise_scale module and are merged with the Policy
# Assignment template values to provide overrides.
- parameters = contains(keys(local.parameters_at_scope), policy_assignment) ? {
- for parameter_key, parameter_value in local.parameters_at_scope[policy_assignment] :
- parameter_key => {
- # Due to object type limitations in Go, we can only support
- # a single object type in the input parameter for parameters.
- # To support processing parameters with different object
- # types we've added support for converting the input value
- # from JSON but can fallback to the raw value if that fails.
- # This provides backwards compatibility for existing
- # deployments, but also makes it easier to compose the input
- # object if only one parameter value type is needed.
- value = try(jsondecode(parameter_value), parameter_value)
+ parameters = merge(
+ try(local.archetype_policy_assignments_map[policy_assignment].properties.parameters, local.empty_map),
+ {
+ for parameter_key, parameter_value in try(local.parameters_at_scope[policy_assignment], local.empty_map) :
+ parameter_key => {
+ # Due to object type limitations in Go, we can only support
+ # a single object type in the input parameter for parameters.
+ # To support processing parameters with different object
+ # types we've added support for converting the input value
+ # from JSON but can fallback to the raw value if that fails.
+ # This provides backwards compatibility for existing
+ # deployments, but also makes it easier to compose the input
+ # object if only one parameter value type is needed.
+ value = try(jsondecode(parameter_value), parameter_value)
+ }
}
- } : null
+ )
+ # The following attribute is used to control the enforcement mode
+ # on Policy Assignments, allowing the template values to be
+ # over-written with dynamic values generated by the module, or
+ # default to true when neither exist (as per default platform
+ # behaviour).
+ enforcement_mode = coalesce(
+ try(local.enforcement_mode[policy_assignment], null),
+ try(lower(local.archetype_policy_assignments_map[policy_assignment].properties.enforcementMode) == "default", true) ? true : false,
+ )
}
]
}
diff --git a/modules/archetypes/locals.tf b/modules/archetypes/locals.tf
index 8211bceb4..a3a625031 100644
--- a/modules/archetypes/locals.tf
+++ b/modules/archetypes/locals.tf
@@ -13,6 +13,7 @@ locals {
scope_id = var.scope_id
archetype_id = var.archetype_id
parameters = var.parameters
+ enforcement_mode = var.enforcement_mode
access_control = var.access_control
library_path = var.library_path
template_file_variables = var.template_file_variables
@@ -69,3 +70,21 @@ locals {
local.builtin_template_file_variables,
)
}
+
+# Generate the configuration output object for the specified archetype
+# depends_on_files = [
+# locals.policy_assignments.tf
+# locals.policy_definitions.tf
+# locals.policy_set_definitions.tf
+# locals.role_assignments.tf
+# locals.role_definitions.tf
+# ]
+locals {
+ module_output = {
+ azurerm_policy_assignment = local.archetype_policy_assignments_output
+ azurerm_policy_definition = local.archetype_policy_definitions_output
+ azurerm_policy_set_definition = local.archetype_policy_set_definitions_output
+ azurerm_role_assignment = local.archetype_role_assignments_output
+ azurerm_role_definition = local.archetype_role_definitions_output
+ }
+}
diff --git a/modules/archetypes/outputs.tf b/modules/archetypes/outputs.tf
index 22b11c7d0..42b05b319 100644
--- a/modules/archetypes/outputs.tf
+++ b/modules/archetypes/outputs.tf
@@ -1,4 +1,4 @@
output "configuration" {
- value = local.archetype_output
- description = "Returns the archetype configuration data used to generate all resources needed to complete deployment of the Enterprise-scale Landing Zones as per the specified archetype_id."
+ value = local.module_output
+ description = "Returns the archetype configuration data used to generate all resources needed to complete deployment of the Enterprise-scale Landing Zones, as per the specified archetype_id."
}
diff --git a/modules/archetypes/variables.tf b/modules/archetypes/variables.tf
index 035dc8790..6d55a296d 100644
--- a/modules/archetypes/variables.tf
+++ b/modules/archetypes/variables.tf
@@ -27,45 +27,39 @@ variable "scope_id" {
variable "archetype_id" {
type = string
description = "Specifies the ID of the archetype to apply against the provided scope. Must be a valid archetype ID from either the built-in module library, or as defined by the library_path variable."
-
- # validation {
- # condition = can(regex("^[a-z0-9-]{2,36}$", var.archetype_id))
- # error_message = "The archetype_id value must be a valid archetype ID from either the built-in module library, or as defined by the library_path variable."
- # }
}
variable "parameters" {
- type = map(any)
- description = "OPTIONAL: If specified, will use the specified parameters to override archetype defaults."
+ type = any
+ description = "If specified, will use the specified parameters to override defaults for Policy Assignments."
+ default = {}
+}
+
+variable "enforcement_mode" {
+ type = map(string)
+ description = "If specified, will use the specified enforcement_mode values to override defaults for Policy Assignments."
default = {}
}
variable "access_control" {
type = map(any)
- description = "OPTIONAL: If specified, will use the specified access control map to set Role Assignments on the archetype instance at the current scope."
+ description = "If specified, will use the specified access control map to set Role Assignments on the archetype instance at the current scope."
default = {}
}
variable "library_path" {
type = string
- description = "OPTIONAL: If specified, sets the path to a custom library folder for archetype artefacts."
+ description = "If specified, sets the path to a custom library folder for archetype artefacts."
default = ""
-
- # validation {
- # condition = fileexists(var.library_path) // does not work with a directory
- # error_message = "The library_path must be a valid file path accessible from the root module scope."
- # }
}
variable "template_file_variables" {
type = map(any)
- description = "OPTIONAL: If specified, provides the ability to define custom template vars used when reading in template files from the library_path"
+ description = "If specified, provides the ability to define custom template vars used when reading in template files from the library_path"
default = {}
}
variable "default_location" {
type = string
description = "Sets the default location used for resource deployments where needed."
-
- # Need to add validation covering all Azure locations
}
diff --git a/modules/management/locals.tf b/modules/management/locals.tf
new file mode 100644
index 000000000..385412b80
--- /dev/null
+++ b/modules/management/locals.tf
@@ -0,0 +1,306 @@
+# The following block of locals are used to avoid using
+# empty object types in the code.
+locals {
+ empty_list = []
+ empty_map = {}
+ empty_string = ""
+}
+
+# Convert the input vars to locals, applying any required
+# logic needed before they are used in the module.
+# No vars should be referenced elsewhere in the module.
+# NOTE: Need to catch error for resource_suffix when
+# no value for subscription_id is provided.
+locals {
+ enabled = var.enabled
+ root_id = var.root_id
+ subscription_id = coalesce(var.subscription_id, "00000000-0000-0000-0000-000000000000")
+ settings = var.settings
+ location = var.location
+ tags = var.tags
+ resource_prefix = coalesce(var.resource_prefix, local.root_id)
+ resource_suffix = length(var.resource_suffix) > 0 ? "-${var.resource_suffix}" : local.empty_string
+ resource_suffix_automation_account = length(local.root_id) + length(local.resource_suffix) < 3 ? "cc${local.resource_suffix}" : local.resource_suffix
+ existing_resource_group_name = var.existing_resource_group_name
+ existing_log_analytics_workspace_resource_id = var.existing_log_analytics_workspace_resource_id
+ existing_automation_account_resource_id = var.existing_automation_account_resource_id
+ link_log_analytics_to_automation_account = var.link_log_analytics_to_automation_account
+ custom_settings_by_resource_type = var.custom_settings_by_resource_type
+}
+
+# Extract individual custom settings blocks from
+# the custom_settings_by_resource_type variable.
+locals {
+ custom_settings_rsg = try(local.custom_settings_by_resource_type.azurerm_resource_group, null)
+ custom_settings_la_workspace = try(local.custom_settings_by_resource_type.azurerm_log_analytics_workspace, null)
+ custom_settings_la_solution = try(local.custom_settings_by_resource_type.azurerm_log_analytics_solution, null)
+ custom_settings_aa = try(local.custom_settings_by_resource_type.azurerm_automation_account, null)
+ custom_settings_la_linked_service = try(local.custom_settings_by_resource_type.azurerm_log_analytics_linked_service, null)
+}
+
+# Logic to determine whether specific resources
+# should be created by this module
+locals {
+ deploy_monitoring = local.enabled && local.settings.log_analytics.enabled
+ deploy_monitoring_for_arc = local.deploy_monitoring && local.settings.log_analytics.config.enable_monitoring_for_arc
+ deploy_monitoring_for_vm = local.deploy_monitoring && local.settings.log_analytics.config.enable_monitoring_for_vm
+ deploy_monitoring_for_vmss = local.deploy_monitoring && local.settings.log_analytics.config.enable_monitoring_for_vmss
+ deploy_resource_group = local.deploy_monitoring && local.existing_resource_group_name == local.empty_string
+ deploy_log_analytics_workspace = local.deploy_monitoring && local.existing_log_analytics_workspace_resource_id == local.empty_string
+ deploy_log_analytics_linked_service = local.deploy_monitoring && local.link_log_analytics_to_automation_account
+ deploy_automation_account = local.deploy_monitoring && local.existing_automation_account_resource_id == local.empty_string
+ deploy_azure_monitor_solutions = {
+ AgentHealthAssessment = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_agent_health_assessment
+ AntiMalware = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_anti_malware
+ AzureActivity = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_azure_activity
+ ChangeTracking = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_change_tracking
+ Security = local.deploy_monitoring && local.settings.log_analytics.config.enable_sentinel
+ SecurityInsights = local.deploy_monitoring && local.settings.log_analytics.config.enable_sentinel
+ ServiceMap = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_service_map
+ SQLAssessment = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_sql_assessment
+ Updates = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_updates
+ VMInsights = local.deploy_monitoring && local.settings.log_analytics.config.enable_solution_for_vm_insights
+ }
+ deploy_security = local.enabled && local.settings.security_center.enabled
+ deploy_defender_for_acr = local.settings.security_center.config.enable_defender_for_acr
+ deploy_defender_for_app_services = local.settings.security_center.config.enable_defender_for_app_services
+ deploy_defender_for_arm = local.settings.security_center.config.enable_defender_for_arm
+ deploy_defender_for_dns = local.settings.security_center.config.enable_defender_for_dns
+ deploy_defender_for_key_vault = local.settings.security_center.config.enable_defender_for_key_vault
+ deploy_defender_for_kubernetes = local.settings.security_center.config.enable_defender_for_kubernetes
+ deploy_defender_for_servers = local.settings.security_center.config.enable_defender_for_servers
+ deploy_defender_for_sql_servers = local.settings.security_center.config.enable_defender_for_sql_servers
+ deploy_defender_for_sql_server_vms = local.settings.security_center.config.enable_defender_for_sql_server_vms
+ deploy_defender_for_storage = local.settings.security_center.config.enable_defender_for_storage
+}
+
+# Configuration settings for resource type:
+# - azurerm_resource_group
+locals {
+ resource_group_name = coalesce(
+ local.existing_resource_group_name,
+ try(local.custom_settings_rsg.name, null),
+ "${local.resource_prefix}-mgmt",
+ )
+ resource_group_resource_id = "/subscriptions/${local.subscription_id}/resourceGroups/${local.resource_group_name}"
+ azurerm_resource_group = {
+ name = local.resource_group_name,
+ location = try(local.custom_settings_rsg.location, local.location)
+ tags = try(local.custom_settings_rsg.tags, local.tags)
+ }
+}
+
+
+# Configuration settings for resource type:
+# - azurerm_log_analytics_workspace
+locals {
+ log_analytics_workspace_resource_id = coalesce(
+ local.existing_log_analytics_workspace_resource_id,
+ "${local.resource_group_resource_id}/providers/Microsoft.OperationalInsights/workspaces/${local.azurerm_log_analytics_workspace.name}"
+ )
+ azurerm_log_analytics_workspace = {
+ name = try(local.custom_settings_la_workspace.name, "${local.resource_prefix}-la${local.resource_suffix}")
+ location = try(local.custom_settings_la_workspace.location, local.location)
+ sku = try(local.custom_settings_la_workspace.sku, "PerGB2018")
+ retention_in_days = try(local.custom_settings_la_workspace.retention_in_days, 30)
+ daily_quota_gb = try(local.custom_settings_la_workspace.daily_quota_gb, null)
+ internet_ingestion_enabled = try(local.custom_settings_la_workspace.internet_ingestion_enabled, true)
+ internet_query_enabled = try(local.custom_settings_la_workspace.internet_query_enabled, true)
+ reservation_capcity_in_gb_per_day = try(local.custom_settings_la_workspace.reservation_capcity_in_gb_per_day, null) # Requires version = "~> 2.48.0"
+ tags = try(local.custom_settings_la_workspace.tags, local.tags)
+ resource_group_name = coalesce(
+ try(local.custom_settings_la_workspace.resource_group_name, null),
+ local.resource_group_name,
+ )
+ }
+}
+
+# Configuration settings for resource type:
+# - azurerm_log_analytics_solution
+locals {
+ log_analytics_solution_resource_id = {
+ for resource in local.azurerm_log_analytics_solution :
+ resource.solution_name => "${local.resource_group_resource_id}/providers/Microsoft.OperationsManagement/solutions/${resource.solution_name}(${local.azurerm_log_analytics_workspace.name})"
+ }
+ azurerm_log_analytics_solution = [
+ for solution_name, solution_enabled in local.deploy_azure_monitor_solutions :
+ {
+ solution_name = solution_name
+ location = try(local.custom_settings_la_solution.location, local.location)
+ workspace_resource_id = local.log_analytics_workspace_resource_id
+ workspace_name = basename(local.log_analytics_workspace_resource_id)
+ tags = try(local.custom_settings_la_solution.tags, local.tags)
+ plan = {
+ publisher = "Microsoft"
+ product = "OMSGallery/${solution_name}"
+ }
+ resource_group_name = coalesce(
+ try(local.custom_settings_la_solution.resource_group_name, null),
+ local.resource_group_name,
+ )
+ }
+ if solution_enabled
+ ]
+}
+
+# Configuration settings for resource type:
+# - azurerm_automation_account
+locals {
+ automation_account_resource_id = coalesce(
+ local.existing_automation_account_resource_id,
+ "${local.resource_group_resource_id}/providers/Microsoft.Automation/automationAccounts/${local.azurerm_automation_account.name}"
+ )
+ azurerm_automation_account = {
+ name = try(local.custom_settings_aa.name, "${local.resource_prefix}-aa${local.resource_suffix_automation_account}")
+ location = try(local.custom_settings_aa.location, local.location)
+ sku_name = try(local.custom_settings_aa.sku_name, "Basic")
+ tags = try(local.custom_settings_aa.tags, local.tags)
+ resource_group_name = coalesce(
+ try(local.custom_settings_aa.resource_group_name, null),
+ local.resource_group_name,
+ )
+ }
+}
+
+# Configuration settings for resource type:
+# - azurerm_log_analytics_linked_service
+locals {
+ log_analytics_linked_service_resource_id = "${local.log_analytics_workspace_resource_id}/linkedServices/Automation"
+ azurerm_log_analytics_linked_service = {
+ workspace_id = try(local.custom_settings_la_linked_service.workspace_id, local.log_analytics_workspace_resource_id)
+ read_access_id = try(local.custom_settings_la_linked_service.read_access_id, local.automation_account_resource_id) # This should be used for linking to an Automation Account resource.
+ write_access_id = null # DO NOT USE. This should be used for linking to a Log Analytics Cluster resource
+ tags = try(local.custom_settings_la_linked_service.tags, local.tags)
+ resource_group_name = coalesce(
+ try(local.custom_settings_la_linked_service.resource_group_name, null),
+ local.resource_group_name,
+ )
+ }
+}
+
+# Archetype configuration overrides
+locals {
+ archetype_config_overrides = {
+ (local.root_id) = {
+ parameters = {
+ Deploy-ASC-Defender = {
+ emailSecurityContact = local.settings.security_center.config.email_security_contact
+ logAnalytics = local.log_analytics_workspace_resource_id
+ ascExportResourceGroupName = "${local.root_id}-asc-export"
+ ascExportResourceGroupLocation = local.location
+ pricingTierContainerRegistry = local.deploy_defender_for_acr ? "Standard" : "Free"
+ pricingTierAppServices = local.deploy_defender_for_app_services ? "Standard" : "Free"
+ pricingTierArm = local.deploy_defender_for_arm ? "Standard" : "Free"
+ pricingTierDns = local.deploy_defender_for_dns ? "Standard" : "Free"
+ pricingTierKeyVaults = local.deploy_defender_for_key_vault ? "Standard" : "Free"
+ pricingTierKubernetesService = local.deploy_defender_for_kubernetes ? "Standard" : "Free"
+ pricingTierVMs = local.deploy_defender_for_servers ? "Standard" : "Free"
+ pricingTierSqlServers = local.deploy_defender_for_sql_servers ? "Standard" : "Free"
+ pricingTierSqlServerVirtualMachines = local.deploy_defender_for_sql_server_vms ? "Standard" : "Free"
+ pricingTierStorageAccounts = local.deploy_defender_for_storage ? "Standard" : "Free"
+ }
+ Deploy-LX-Arc-Monitoring = {
+ logAnalytics = local.log_analytics_workspace_resource_id
+
+ }
+ Deploy-VM-Monitoring = {
+ logAnalytics_1 = local.log_analytics_workspace_resource_id
+
+ }
+ Deploy-VMSS-Monitoring = {
+ logAnalytics_1 = local.log_analytics_workspace_resource_id
+ }
+ Deploy-WS-Arc-Monitoring = {
+ logAnalytics = local.log_analytics_workspace_resource_id
+ }
+ }
+ enforcement_mode = {
+ Deploy-ASC-Defender = local.deploy_security
+ Deploy-LX-Arc-Monitoring = local.deploy_monitoring_for_arc
+ Deploy-VM-Monitoring = local.deploy_monitoring_for_vm
+ Deploy-VMSS-Monitoring = local.deploy_monitoring_for_vmss
+ Deploy-WS-Arc-Monitoring = local.deploy_monitoring_for_arc
+ }
+ }
+ "${local.root_id}-management" = {
+ parameters = {
+ Deploy-Log-Analytics = {
+ automationAccountName = local.azurerm_automation_account.name
+ automationRegion = local.azurerm_automation_account.location
+ retentionInDays = jsonencode(tostring(local.settings.log_analytics.config.retention_in_days)) # Need to ensure this gets handled as a string
+ rgName = local.azurerm_resource_group.name
+ workspaceName = local.azurerm_log_analytics_workspace.name
+ workspaceRegion = local.azurerm_log_analytics_workspace.location
+ }
+ }
+ enforcement_mode = {
+ Deploy-Log-Analytics = local.deploy_monitoring
+ }
+ }
+ }
+}
+
+
+# Generate the configuration output object for the management module
+locals {
+ module_output = {
+ azurerm_resource_group = [
+ {
+ resource_id = local.resource_group_resource_id
+ resource_name = basename(local.resource_group_resource_id)
+ template = {
+ for key, value in local.azurerm_resource_group :
+ key => value
+ if local.deploy_resource_group
+ }
+ managed_by_module = local.deploy_resource_group
+ },
+ ]
+ azurerm_log_analytics_workspace = [
+ {
+ resource_id = local.log_analytics_workspace_resource_id
+ resource_name = basename(local.log_analytics_workspace_resource_id)
+ template = {
+ for key, value in local.azurerm_log_analytics_workspace :
+ key => value
+ if local.deploy_log_analytics_workspace
+ }
+ managed_by_module = local.deploy_log_analytics_workspace
+ },
+ ]
+ azurerm_log_analytics_solution = [
+ for resource in local.azurerm_log_analytics_solution :
+ {
+ resource_id = local.log_analytics_solution_resource_id[resource.solution_name]
+ resource_name = basename(local.log_analytics_solution_resource_id[resource.solution_name])
+ template = resource
+ managed_by_module = true
+ }
+ ]
+ azurerm_automation_account = [
+ {
+ resource_id = local.automation_account_resource_id
+ resource_name = basename(local.automation_account_resource_id)
+ template = {
+ for key, value in local.azurerm_automation_account :
+ key => value
+ if local.deploy_automation_account
+ }
+ managed_by_module = local.deploy_automation_account
+ },
+ ]
+ azurerm_log_analytics_linked_service = [
+ {
+ resource_id = local.log_analytics_linked_service_resource_id
+ resource_name = basename(local.log_analytics_linked_service_resource_id)
+ template = {
+ for key, value in local.azurerm_log_analytics_linked_service :
+ key => value
+ if local.deploy_log_analytics_linked_service
+ }
+ managed_by_module = local.deploy_log_analytics_linked_service
+ },
+ ]
+ archetype_config_overrides = local.archetype_config_overrides
+ }
+}
diff --git a/modules/management/main.tf b/modules/management/main.tf
new file mode 100644
index 000000000..c3b854037
--- /dev/null
+++ b/modules/management/main.tf
@@ -0,0 +1,7 @@
+# No resources deployed by this module so this file is here as an entry point only
+# Please navigate the variables, locals and outputs to see how the data model is generated from the inputs
+
+# Need to consider remediation steps for Landing Zones once deploy_management_resources has been run, for example:
+# - remediate_arc_monitoring = bool
+# - remediate_vm_monitoring = bool
+# - remediate_vmss_monitoring = bool
diff --git a/modules/management/outputs.tf b/modules/management/outputs.tf
new file mode 100644
index 000000000..b822b11d1
--- /dev/null
+++ b/modules/management/outputs.tf
@@ -0,0 +1,4 @@
+output "configuration" {
+ value = local.module_output
+ description = "Returns the resources to deploy for the management solution and additional configuration settings."
+}
diff --git a/modules/management/variables.tf b/modules/management/variables.tf
new file mode 100644
index 000000000..a16dbe335
--- /dev/null
+++ b/modules/management/variables.tf
@@ -0,0 +1,140 @@
+# The following variables are used to determine the archetype
+# definition to use and create the required resources.
+#
+# Further information provided within the description block
+# for each variable
+
+variable "enabled" {
+ type = bool
+ description = "Controls whether to deploy the management resources into the current Subscription context."
+}
+
+variable "root_id" {
+ type = string
+ description = "Specifies the ID of the Enterprise-scale root Management Group, used as a prefix for resources created by this module."
+
+ validation {
+ condition = can(regex("^[a-zA-Z0-9-]{2,10}$", var.root_id))
+ error_message = "Value must be between 2 to 10 characters long, consisting of alphanumeric characters and hyphens."
+ }
+}
+
+variable "subscription_id" {
+ type = string
+ description = "Specifies the Subscription ID for the Subscription containing all management resources."
+
+ validation {
+ condition = can(regex("^[a-z0-9-]{36}$", var.subscription_id)) || var.subscription_id == ""
+ error_message = "Value must be a valid Subscription ID (GUID)."
+ }
+}
+
+variable "location" {
+ type = string
+ description = "Sets the default location used for resource deployments where needed."
+ default = "eastus"
+}
+
+variable "tags" {
+ type = map(string)
+ description = "If specified, will set the default tags for all resources deployed by this module where supported."
+ default = {}
+}
+
+variable "settings" {
+ type = object({
+ log_analytics = object({
+ enabled = bool
+ config = object({
+ retention_in_days = number
+ enable_monitoring_for_arc = bool
+ enable_monitoring_for_vm = bool
+ enable_monitoring_for_vmss = bool
+ enable_solution_for_agent_health_assessment = bool
+ enable_solution_for_anti_malware = bool
+ enable_solution_for_azure_activity = bool
+ enable_solution_for_change_tracking = bool
+ enable_solution_for_service_map = bool
+ enable_solution_for_sql_assessment = bool
+ enable_solution_for_updates = bool
+ enable_solution_for_vm_insights = bool
+ enable_sentinel = bool
+ })
+ })
+ security_center = object({
+ enabled = bool
+ config = object({
+ email_security_contact = string
+ enable_defender_for_acr = bool
+ enable_defender_for_app_services = bool
+ enable_defender_for_arm = bool
+ enable_defender_for_dns = bool
+ enable_defender_for_key_vault = bool
+ enable_defender_for_kubernetes = bool
+ enable_defender_for_servers = bool
+ enable_defender_for_sql_servers = bool
+ enable_defender_for_sql_server_vms = bool
+ enable_defender_for_storage = bool
+ })
+ })
+ })
+ description = "Configuration settings for the \"Management\" landing zone resources."
+}
+
+variable "resource_prefix" {
+ type = string
+ description = "If specified, will set the resource name prefix for management resources (default value determined from \"var.root_id\")."
+ default = ""
+
+ validation {
+ condition = can(regex("^[a-zA-Z0-9-]{2,10}$", var.resource_prefix)) || var.resource_prefix == ""
+ error_message = "Value must be between 2 to 10 characters long, consisting of alphanumeric characters and hyphens."
+ }
+}
+
+variable "resource_suffix" {
+ type = string
+ description = "If specified, will set the resource name suffix for management resources (default value determined from \"var.subscription_id\")."
+ default = ""
+
+ validation {
+ condition = can(regex("^[a-zA-Z0-9-]{2,36}$", var.resource_suffix)) || var.resource_suffix == ""
+ error_message = "Value must be between 2 to 36 characters long, consisting of alphanumeric characters and hyphens."
+ }
+
+}
+
+variable "existing_resource_group_name" {
+ type = string
+ description = "If specified, module will skip creation of the management Resource Group and use existing."
+ default = ""
+}
+
+variable "existing_log_analytics_workspace_resource_id" {
+ type = string
+ description = "If specified, module will skip creation of Log Analytics workspace and use existing."
+ default = ""
+}
+
+variable "existing_automation_account_resource_id" {
+ type = string
+ description = "If specified, module will skip creation of Automation Account and use existing."
+ default = ""
+}
+
+variable "link_log_analytics_to_automation_account" {
+ type = bool
+ description = "If set to true, module will link the Log Analytics workspace and Automation Account."
+ default = true
+}
+
+variable "custom_settings_by_resource_type" {
+ type = any
+ description = "If specified, allows full customization of common settings for all resources (by type) deployed by this module."
+ default = {}
+
+ validation {
+ condition = can([for k in keys(var.custom_settings_by_resource_type) : contains(["azurerm_resource_group", "azurerm_log_analytics_workspace", "azurerm_log_analytics_solution", "azurerm_automation_account", "azurerm_log_analytics_linked_service"], k)]) || var.custom_settings_by_resource_type == {}
+ error_message = "Invalid key specified. Please check the list of allowed resource types supported by the management module for caf-enterprise-scale."
+ }
+}
diff --git a/outputs.tf b/outputs.tf
index 1c6cf4b31..3f28eff7a 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -53,3 +53,56 @@ output "azurerm_role_assignment" {
}
description = "Returns the configuration data for all Role Assignments created by this module."
}
+
+# The following output is used to ensure all Resource
+# Group data is returned to the root module.
+output "azurerm_resource_group" {
+ value = {
+ enterprise_scale = azurerm_resource_group.enterprise_scale
+ }
+ description = "Returns the configuration data for all Resource Groups created by this module."
+}
+
+# The following output is used to ensure all Log Analytics
+# Workspace data is returned to the root module.
+# Includes logic to remove sensitive values.
+output "azurerm_log_analytics_workspace" {
+ value = {
+ enterprise_scale = {
+ for rk, rv in azurerm_log_analytics_workspace.enterprise_scale :
+ rk => {
+ for ak, av in rv :
+ ak => av
+ if contains(local.sensitive_attributes["azurerm_log_analytics_workspace"], ak) != true
+ }
+ }
+ }
+ description = "Returns the configuration data for all Log Analytics workspaces created by this module. Excludes sensitive values."
+}
+
+# The following output is used to ensure all Log Analytics
+# Solution data is returned to the root module.
+output "azurerm_log_analytics_solution" {
+ value = {
+ enterprise_scale = azurerm_log_analytics_solution.enterprise_scale
+ }
+ description = "Returns the configuration data for all Log Analytics solutions created by this module."
+}
+
+# The following output is used to ensure all Automation
+# Account data is returned to the root module.
+output "azurerm_automation_account" {
+ value = {
+ enterprise_scale = azurerm_automation_account.enterprise_scale
+ }
+ description = "Returns the configuration data for all Automation Accounts created by this module."
+}
+
+# The following output is used to ensure all Log Analytics
+# Linked Service data is returned to the root module.
+output "azurerm_log_analytics_linked_service" {
+ value = {
+ enterprise_scale = azurerm_log_analytics_linked_service.enterprise_scale
+ }
+ description = "Returns the configuration data for all Log Analytics linked services created by this module."
+}
diff --git a/resources.management.tf b/resources.management.tf
new file mode 100644
index 000000000..1e5329df2
--- /dev/null
+++ b/resources.management.tf
@@ -0,0 +1,94 @@
+resource "azurerm_log_analytics_workspace" "enterprise_scale" {
+ for_each = local.azurerm_log_analytics_workspace_enterprise_scale
+
+ # Mandatory resource attributes
+ name = each.value.template.name
+ location = each.value.template.location
+ resource_group_name = each.value.template.resource_group_name
+
+ # Optional resource attributes
+ sku = each.value.template.sku
+ retention_in_days = each.value.template.retention_in_days
+ daily_quota_gb = each.value.template.daily_quota_gb
+ internet_ingestion_enabled = each.value.template.internet_ingestion_enabled
+ internet_query_enabled = each.value.template.internet_query_enabled
+ tags = each.value.template.tags
+
+ # Optional resource attributes (removed for backward
+ # compatibility with older azurerm provider versions,
+ # as not currently used by Enterprise-scale)/
+ # Requires version = "~> 2.48.0"
+ # reservation_capcity_in_gb_per_day = each.value.template.reservation_capcity_in_gb_per_day
+
+ # Set explicit dependency on Resource Group deployment
+ depends_on = [
+ azurerm_resource_group.enterprise_scale,
+ ]
+
+}
+
+resource "azurerm_log_analytics_solution" "enterprise_scale" {
+ for_each = local.azurerm_log_analytics_solution_enterprise_scale
+
+ # Mandatory resource attributes
+ solution_name = each.value.template.solution_name
+ location = each.value.template.location
+ resource_group_name = each.value.template.resource_group_name
+ workspace_resource_id = each.value.template.workspace_resource_id
+ workspace_name = each.value.template.workspace_name
+
+ plan {
+ publisher = each.value.template.plan.publisher
+ product = each.value.template.plan.product
+ }
+
+ # Optional resource attributes
+ tags = each.value.template.tags
+
+ # Set explicit dependency on Resource Group and Log Analytics workspace deployments
+ depends_on = [
+ azurerm_resource_group.enterprise_scale,
+ azurerm_log_analytics_workspace.enterprise_scale,
+ ]
+
+}
+
+resource "azurerm_automation_account" "enterprise_scale" {
+ for_each = local.azurerm_automation_account_enterprise_scale
+
+ # Mandatory resource attributes
+ name = each.value.template.name
+ location = each.value.template.location
+ resource_group_name = each.value.template.resource_group_name
+
+ # Optional resource attributes
+ sku_name = each.value.template.sku_name
+ tags = each.value.template.tags
+
+ # Set explicit dependency on Resource Group deployment
+ depends_on = [
+ azurerm_resource_group.enterprise_scale,
+ ]
+
+}
+
+resource "azurerm_log_analytics_linked_service" "enterprise_scale" {
+ for_each = local.azurerm_log_analytics_linked_service_enterprise_scale
+
+ # Mandatory resource attributes
+ resource_group_name = each.value.template.resource_group_name
+ workspace_id = each.value.template.workspace_id
+
+ # Optional resource attributes
+ read_access_id = each.value.template.read_access_id
+ write_access_id = each.value.template.write_access_id
+ tags = each.value.template.tags
+
+ # Set explicit dependency on Resource Group, Log Analytics workspace and Automation Account deployments
+ depends_on = [
+ azurerm_resource_group.enterprise_scale,
+ azurerm_log_analytics_workspace.enterprise_scale,
+ azurerm_automation_account.enterprise_scale,
+ ]
+
+}
diff --git a/resources.policy_assignments.tf b/resources.policy_assignments.tf
index a5b7914f9..563a6d780 100644
--- a/resources.policy_assignments.tf
+++ b/resources.policy_assignments.tf
@@ -16,9 +16,9 @@ resource "azurerm_policy_assignment" "enterprise_scale" {
description = try(each.value.template.properties.description, "${each.value.template.name} Policy Assignment at scope ${each.value.scope_id}")
display_name = try(each.value.template.properties.displayName, each.value.template.name)
metadata = try(length(each.value.template.properties.metadata) > 0, false) ? jsonencode(each.value.template.properties.metadata) : null
- parameters = try(length(each.value.template.properties.parameters) > 0, false) ? jsonencode(merge(each.value.template.properties.parameters, each.value.parameters)) : jsonencode(each.value.parameters)
+ parameters = try(length(each.value.parameters) > 0, false) ? jsonencode(each.value.parameters) : null
not_scopes = try(each.value.template.properties.notScopes, local.empty_list)
- enforcement_mode = try(lower(each.value.template.properties.enforcementMode) == "default", true) ? true : false
+ enforcement_mode = each.value.enforcement_mode
# Set explicit dependency on Management Group, Policy Definition and Policy Set Definition deployments
depends_on = [
diff --git a/resources.resource_groups.tf b/resources.resource_groups.tf
new file mode 100644
index 000000000..737a359d6
--- /dev/null
+++ b/resources.resource_groups.tf
@@ -0,0 +1,8 @@
+resource "azurerm_resource_group" "enterprise_scale" {
+ for_each = local.azurerm_resource_group_enterprise_scale
+
+ # Mandatory resource attributes
+ name = each.value.template.name
+ location = each.value.template.location
+ tags = each.value.template.tags
+}
diff --git a/resources.role_assignments.tf b/resources.role_assignments.tf
index 5396d7534..1d0f76dcf 100644
--- a/resources.role_assignments.tf
+++ b/resources.role_assignments.tf
@@ -10,9 +10,8 @@ resource "azurerm_role_assignment" "enterprise_scale" {
principal_id = each.value.principal_id
# Optional attributes
- role_definition_name = try(each.value.role_definition_name, null)
- role_definition_id = try(each.value.role_definition_id, null)
- skip_service_principal_aad_check = try(each.value.skip_service_principal_aad_check, null)
+ role_definition_name = try(each.value.role_definition_name, null)
+ role_definition_id = try(each.value.role_definition_id, null)
# Set explicit dependency on Management Group, Policy, and Role Definition deployments
depends_on = [
diff --git a/terraform.tf b/terraform.tf
index 0462adf50..73c8b563c 100644
--- a/terraform.tf
+++ b/terraform.tf
@@ -4,7 +4,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = ">= 2.34.0"
+ version = ">= 2.41.0"
}
time = {
source = "hashicorp/time"
diff --git a/tests/deployment/lib/archetype_definitions/archetype_definition_customer_root.json b/tests/deployment/lib/archetype_definitions/archetype_definition_customer_root.json
index 790e365f0..05667323e 100644
--- a/tests/deployment/lib/archetype_definitions/archetype_definition_customer_root.json
+++ b/tests/deployment/lib/archetype_definitions/archetype_definition_customer_root.json
@@ -46,7 +46,17 @@
"Deny-Subnet-Without-Udr",
"Deny-VNET-Peer-Cross-Sub",
"Deny-VNet-Peering",
- "Deploy-ASC-Standard",
+ "Deploy-ASC-Defender-ACR",
+ "Deploy-ASC-Defender-AKS",
+ "Deploy-ASC-Defender-AKV",
+ "Deploy-ASC-Defender-AppSrv",
+ "Deploy-ASC-Defender-ARM",
+ "Deploy-ASC-Defender-DNS",
+ "Deploy-ASC-Defender-SA",
+ "Deploy-ASC-Defender-Sql",
+ "Deploy-ASC-Defender-SQLVM",
+ "Deploy-ASC-Defender-VMs",
+ "Deploy-ASC-SecurityContacts",
"Deploy-Budget",
"Deploy-DDoSProtection",
"Deploy-Diagnostics-AA",
@@ -89,7 +99,6 @@
"Deploy-Diagnostics-NIC",
"Deploy-Diagnostics-PostgreSQL",
"Deploy-Diagnostics-PowerBIEmbedded",
- "Deploy-Diagnostics-PublicIP",
"Deploy-Diagnostics-RecoveryVault",
"Deploy-Diagnostics-RedisCache",
"Deploy-Diagnostics-Relay",
@@ -139,6 +148,7 @@
"Deploy-Windows-DomainJoin" ],
"policy_set_definitions": [
"Deny-PublicEndpoints",
+ "Deploy-ASC-Config",
"Deploy-Diag-LogAnalytics",
"Deploy-Sql-Security",
"Enforce-Encryption-CMK",
diff --git a/tests/deployment/main.tf b/tests/deployment/main.tf
index 13a7270bf..0b92c5907 100644
--- a/tests/deployment/main.tf
+++ b/tests/deployment/main.tf
@@ -2,7 +2,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
- version = "2.34.0"
+ version = "2.41.0"
}
}
}
diff --git a/tests/scripts/azp-strategy.ps1 b/tests/scripts/azp-strategy.ps1
index be2594f70..d2a039db6 100755
--- a/tests/scripts/azp-strategy.ps1
+++ b/tests/scripts/azp-strategy.ps1
@@ -16,28 +16,27 @@ $azurermProviderUrl = "https://registry.terraform.io/v1/providers/hashicorp/azur
# - Base Version: "0.13.2"
# - Latest Versions:
# 0.13.* (latest 1)
-# 0.14.* (latest 3)
-# 0.15.* (latest 1)
+# 0.14.* (latest 1)
+# 0.15.* (latest 2)
########################################
$terraformVersionsResponse = Invoke-RestMethod -Method Get -Uri $terraformUrl
$terraformVersionsAll = $terraformVersionsResponse.name -replace "v", ""
$terraformVersions = @("0.13.2")
-$terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.13" } | Select-Object -First 1
-$terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.14" } | Select-Object -First 3
-# Terraform v0.15.x currently causes validation errors. Needs further investigation.
-# $terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.15" } | Select-Object -First 1
+$terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.13.\d{1,2}(?!-)" } | Select-Object -First 1
+$terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.14.\d{1,2}(?!-)" } | Select-Object -First 1
+$terraformVersions += $terraformVersionsAll | Where-Object { $_ -match "^0.15.\d{1,2}(?!-)" } | Select-Object -First 2
$terraformVersions = $terraformVersions | Sort-Object
#######################################
# Terraform AzureRM Provider Versions
-# - Base Version: (2.34.0)
+# - Base Version: (2.41.0)
# - Latest Versions: (latest 1)
#######################################
-$azurermProviderVersionBase = "2.34.0"
+$azurermProviderVersionBase = "2.41.0"
$azurermProviderVersionLatest = (Invoke-RestMethod -Method Get -Uri $azurermProviderUrl).version
#############################################################################
diff --git a/tests/scripts/tf-apply.sh b/tests/scripts/tf-apply.sh
index 5921d4525..5d2c040af 100755
--- a/tests/scripts/tf-apply.sh
+++ b/tests/scripts/tf-apply.sh
@@ -12,6 +12,6 @@ cd "$PIPELINE_WORKSPACE/s/tests/deployment"
echo "==> Applying infrastructure..."
terraform apply \
-auto-approve \
- -parallelism=256 \
+ -parallelism=100 \
-state="./terraform-$TF_VERSION-$TF_AZ_VERSION.tfstate" \
"terraform-plan-$TF_VERSION-$TF_AZ_VERSION"
\ No newline at end of file
diff --git a/variables.tf b/variables.tf
index 1221f474e..779a53ee1 100644
--- a/variables.tf
+++ b/variables.tf
@@ -10,7 +10,7 @@ variable "root_parent_id" {
validation {
condition = can(regex("^[a-zA-Z0-9-_\\(\\)\\.]{1,36}$", var.root_parent_id))
- error_message = "The root_parent_id value must be a valid GUID, or Management Group ID."
+ error_message = "Value must be a valid Management Group ID, consisting of alphanumeric characters, hyphens, underscores, periods and parentheses."
}
}
@@ -21,7 +21,7 @@ variable "root_id" {
validation {
condition = can(regex("^[a-zA-Z0-9-]{2,10}$", var.root_id))
- error_message = "The root_id value must be between 2 to 10 characters long and can only contain alphanumeric characters and hyphens."
+ error_message = "Value must be between 2 to 10 characters long, consisting of alphanumeric characters and hyphens."
}
}
@@ -32,18 +32,122 @@ variable "root_name" {
validation {
condition = can(regex("^[A-Za-z][A-Za-z0-9- ._]{1,22}[A-Za-z0-9]?$", var.root_name))
- error_message = "The root_name value must be between 2 to 24 characters long, start with a letter, end with a letter or number, and can only contain space, hyphen, underscore or period characters."
+ error_message = "Value must be between 2 to 24 characters long, start with a letter, end with a letter or number, and can only contain space, hyphen, underscore or period characters."
}
}
variable "deploy_core_landing_zones" {
type = bool
- description = "If set to true, will include the core Enterprise-scale Management Group hierarchy."
+ 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
}
+variable "deploy_demo_landing_zones" {
+ type = bool
+ description = "If set to true, module will deploy the demo \"Landing Zone\" Management Groups (\"Corp\", \"Online\", and \"SAP\") into the core Enterprise-scale Management Group hierarchy."
+ default = false
+}
+
+variable "deploy_management_resources" {
+ type = bool
+ description = "If set to true, will deploy the \"Management\" landing zone resources into the current Subscription context."
+ default = false
+}
+
+variable "configure_management_resources" {
+ type = object({
+ settings = object({
+ log_analytics = object({
+ enabled = bool
+ config = object({
+ retention_in_days = number
+ enable_monitoring_for_arc = bool
+ enable_monitoring_for_vm = bool
+ enable_monitoring_for_vmss = bool
+ enable_solution_for_agent_health_assessment = bool
+ enable_solution_for_anti_malware = bool
+ enable_solution_for_azure_activity = bool
+ enable_solution_for_change_tracking = bool
+ enable_solution_for_service_map = bool
+ enable_solution_for_sql_assessment = bool
+ enable_solution_for_updates = bool
+ enable_solution_for_vm_insights = bool
+ enable_sentinel = bool
+ })
+ })
+ security_center = object({
+ enabled = bool
+ config = object({
+ email_security_contact = string
+ enable_defender_for_acr = bool
+ enable_defender_for_app_services = bool
+ enable_defender_for_arm = bool
+ enable_defender_for_dns = bool
+ enable_defender_for_key_vault = bool
+ enable_defender_for_kubernetes = bool
+ enable_defender_for_servers = bool
+ enable_defender_for_sql_servers = bool
+ enable_defender_for_sql_server_vms = bool
+ enable_defender_for_storage = bool
+ })
+ })
+ })
+ location = any
+ tags = any
+ advanced = any
+ })
+ description = "If specified, will customize the \"Management\" landing zone resources."
+ default = {
+ 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 = "security_contact@replace_me"
+ 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
+ }
+}
+
variable "archetype_config_overrides" {
- type = map(any)
+ type = map(
+ object({
+ archetype_id = string
+ parameters = any
+ access_control = any
+ })
+ )
description = "If specified, will set custom Archetype configurations to the default Enterprise-scale Management Groups."
default = {}
}
@@ -54,10 +158,37 @@ variable "subscription_id_overrides" {
default = {}
}
-variable "deploy_demo_landing_zones" {
- type = bool
- description = "If set to true, will include the demo \"Landing Zone\" Management Groups."
- default = false
+variable "subscription_id_connectivity" {
+ type = string
+ description = "If specified, identifies the Platform subscription for \"Connectivity\" for resource deployment and correct placement in the Management Group hierarchy."
+ default = ""
+
+ validation {
+ condition = can(regex("^[a-z0-9-]{36}$", var.subscription_id_connectivity)) || var.subscription_id_connectivity == ""
+ error_message = "Value must be a valid Subscription ID (GUID)."
+ }
+}
+
+variable "subscription_id_identity" {
+ type = string
+ description = "If specified, identifies the Platform subscription for \"Identity\" for resource deployment and correct placement in the Management Group hierarchy."
+ default = ""
+
+ validation {
+ condition = can(regex("^[a-z0-9-]{36}$", var.subscription_id_identity)) || var.subscription_id_identity == ""
+ error_message = "Value must be a valid Subscription ID (GUID)."
+ }
+}
+
+variable "subscription_id_management" {
+ type = string
+ description = "If specified, identifies the Platform subscription for \"Management\" for resource deployment and correct placement in the Management Group hierarchy."
+ default = ""
+
+ validation {
+ condition = can(regex("^[a-z0-9-]{36}$", var.subscription_id_management)) || var.subscription_id_management == ""
+ error_message = "Value must be a valid Subscription ID (GUID)."
+ }
}
variable "custom_landing_zones" {
@@ -102,6 +233,12 @@ variable "default_location" {
# Need to add validation covering all Azure locations
}
+variable "default_tags" {
+ type = map(string)
+ description = "If specified, will set the default tags for all resources deployed by this module where supported."
+ default = {}
+}
+
variable "create_duration_delay" {
type = map(string)
description = "Used to tune terraform apply when faced with errors caused by API caching or eventual consistency. Sets a custom delay period after creation of the specified resource type."