diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 769d5168f..1d10239cd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ ---- -version: 2 +# --- +# version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: daily +# updates: +# - package-ecosystem: "github-actions" +# directory: "/" +# schedule: +# interval: daily diff --git a/.github/workflows/update-policy.yml b/.github/workflows/update-policy.yml index 958dda771..f035ac762 100644 --- a/.github/workflows/update-policy.yml +++ b/.github/workflows/update-policy.yml @@ -97,35 +97,35 @@ jobs: echo "changes=${#CHECK_GIT_STATUS[@]}" >> "$GITHUB_OUTPUT" working-directory: ${{ github.repository }} - - name: Add files, commit and push - if: steps.git_status.outputs.changes > 0 - run: | - echo "Pushing changes to origin..." - git add modules/archetypes/lib - git commit -m '${{ env.pr_title }}' - git push origin ${{ env.branch_name }} - working-directory: ${{ github.repository }} + # - name: Add files, commit and push + # if: steps.git_status.outputs.changes > 0 + # run: | + # echo "Pushing changes to origin..." + # git add modules/archetypes/lib + # git commit -m '${{ env.pr_title }}' + # git push origin ${{ env.branch_name }} + # working-directory: ${{ github.repository }} - - name: Create pull request - if: steps.git_status.outputs.changes > 0 - run: | - HEAD_LABEL="${{ github.repository_owner }}:${{ env.branch_name }}" - BASE_LABEL="${{ github.repository_owner }}:$(echo '${{ github.ref }}' | sed 's:refs/heads/::')" - PULL_REQUEST_URL="repos/${{ github.repository }}/pulls" - JQ_FILTER=".[] | select(.head.label == \"$HEAD_LABEL\") | select(.base.label == \"$BASE_LABEL\") | .url" - CHECK_PULL_REQUEST_URL=$(gh api $PULL_REQUEST_URL | jq -r "$JQ_FILTER") - if [ -z "$CHECK_PULL_REQUEST_URL" ] - then - CHECK_PULL_REQUEST_URL=$(gh pr create \ - --title "${{ env.pr_title }}" \ - --body "${{ env.pr_body }}" \ - --base "${{ github.ref }}" \ - --head "${{ env.branch_name }}" \ - --draft) - echo "Created new PR: $CHECK_PULL_REQUEST_URL" - else - echo "Existing PR found: $CHECK_PULL_REQUEST_URL" - fi - working-directory: ${{ github.repository }} - env: - GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + # - name: Create pull request + # if: steps.git_status.outputs.changes > 0 + # run: | + # HEAD_LABEL="${{ github.repository_owner }}:${{ env.branch_name }}" + # BASE_LABEL="${{ github.repository_owner }}:$(echo '${{ github.ref }}' | sed 's:refs/heads/::')" + # PULL_REQUEST_URL="repos/${{ github.repository }}/pulls" + # JQ_FILTER=".[] | select(.head.label == \"$HEAD_LABEL\") | select(.base.label == \"$BASE_LABEL\") | .url" + # CHECK_PULL_REQUEST_URL=$(gh api $PULL_REQUEST_URL | jq -r "$JQ_FILTER") + # if [ -z "$CHECK_PULL_REQUEST_URL" ] + # then + # CHECK_PULL_REQUEST_URL=$(gh pr create \ + # --title "${{ env.pr_title }}" \ + # --body "${{ env.pr_body }}" \ + # --base "${{ github.ref }}" \ + # --head "${{ env.branch_name }}" \ + # --draft) + # echo "Created new PR: $CHECK_PULL_REQUEST_URL" + # else + # echo "Existing PR found: $CHECK_PULL_REQUEST_URL" + # fi + # working-directory: ${{ github.repository }} + # env: + # GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} diff --git a/README.md b/README.md index c909b6acf..a94f2c708 100644 --- a/README.md +++ b/README.md @@ -654,11 +654,14 @@ object({ log_analytics = optional(object({ enabled = optional(bool, true) config = optional(object({ - retention_in_days = optional(number, 30) - enable_monitoring_for_vm = optional(bool, true) - enable_monitoring_for_vmss = optional(bool, true) - enable_sentinel = optional(bool, true) - enable_change_tracking = optional(bool, true) + retention_in_days = optional(number, 30) + enable_monitoring_for_vm = optional(bool, true) + enable_monitoring_for_vmss = optional(bool, true) + enable_sentinel = optional(bool, true) + enable_change_tracking = optional(bool, true) + enable_solution_for_vm_insights = optional(bool, true) + enable_solution_for_container_insights = optional(bool, true) + sentinel_customer_managed_key_enabled = optional(bool, false) # not used at this time }), {}) }), {}) security_center = optional(object({ @@ -1103,6 +1106,8 @@ The following resources are used by this module: - [azurerm_resource_group.connectivity](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource) - [azurerm_resource_group.management](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource) - [azurerm_resource_group.virtual_wan](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource) +- [azurerm_role_assignment.ama_managed_identity_operator](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) +- [azurerm_role_assignment.ama_reader](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) - [azurerm_role_assignment.enterprise_scale](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) - [azurerm_role_assignment.policy_assignment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) - [azurerm_role_assignment.private_dns_zone_contributor_connectivity](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) diff --git a/docs/wiki/[Examples]-Deploy-Management-Resources-With-Custom-Settings.md b/docs/wiki/[Examples]-Deploy-Management-Resources-With-Custom-Settings.md index 4f51b07ea..a55c82461 100644 --- a/docs/wiki/[Examples]-Deploy-Management-Resources-With-Custom-Settings.md +++ b/docs/wiki/[Examples]-Deploy-Management-Resources-With-Custom-Settings.md @@ -162,23 +162,21 @@ This helps to keep the module block clean, whilst providing clear separation bet locals { configure_management_resources = { settings = { + ama = { + enable_uami = true + enable_vminsights_dcr = true + enable_change_tracking_dcr = true + enable_mdfc_defender_for_sql_dcr = false + enable_mdfc_defender_for_sql_query_collection_for_security_research = false + } log_analytics = { enabled = true config = { - retention_in_days = var.log_retention_in_days - 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_change_tracking = true - enable_solution_for_service_map = false - enable_solution_for_sql_assessment = false - enable_solution_for_sql_vulnerability_assessment = false - enable_solution_for_sql_advanced_threat_detection = false - enable_solution_for_updates = true - enable_solution_for_vm_insights = true - enable_solution_for_container_insights = true - enable_sentinel = true + retention_in_days = var.log_retention_in_days + enable_monitoring_for_vm = true + enable_monitoring_for_vmss = true + enable_sentinel = true + enable_change_tracking = true } } security_center = { diff --git a/docs/wiki/[Examples]-Deploy-Connectivity-Resources-With-Custom-Settings.md b/docs/wiki/[Examples]-Deploy-Multi-Region-Networking-With-Custom-Settings.md similarity index 98% rename from docs/wiki/[Examples]-Deploy-Connectivity-Resources-With-Custom-Settings.md rename to docs/wiki/[Examples]-Deploy-Multi-Region-Networking-With-Custom-Settings.md index 5bbff5671..05f57da55 100644 --- a/docs/wiki/[Examples]-Deploy-Connectivity-Resources-With-Custom-Settings.md +++ b/docs/wiki/[Examples]-Deploy-Multi-Region-Networking-With-Custom-Settings.md @@ -1,7 +1,7 @@ ## Overview -This page describes how to deploy Azure landing zones with connectivity resources based on the [Traditional Azure networking topology (hub and spoke)][wiki_connectivity_resources_hub_and_spoke] created in the current Subscription context, using custom configuration settings. +This page describes how to deploy a multi-region Azure landing zone with connectivity resources based on the [Traditional Azure networking topology (hub and spoke)][wiki_connectivity_resources_hub_and_spoke] created in the current Subscription context, using custom configuration settings. > **NOTE:** > If you need to deploy a network based on Virtual WAN, please see our [Deploy Connectivity Resources With Custom Settings (Virtual WAN)][wiki_deploy_virtual_wan_resources_custom] example. diff --git a/docs/wiki/[Examples]-Deploy-Virtual-WAN-Resources-With-Custom-Settings.md b/docs/wiki/[Examples]-Deploy-Virtual-WAN-Multi-Region-With-Custom-Settings.md similarity index 98% rename from docs/wiki/[Examples]-Deploy-Virtual-WAN-Resources-With-Custom-Settings.md rename to docs/wiki/[Examples]-Deploy-Virtual-WAN-Multi-Region-With-Custom-Settings.md index eb4e6a0c4..b76a24890 100644 --- a/docs/wiki/[Examples]-Deploy-Virtual-WAN-Resources-With-Custom-Settings.md +++ b/docs/wiki/[Examples]-Deploy-Virtual-WAN-Multi-Region-With-Custom-Settings.md @@ -1,7 +1,7 @@ ## Overview -This page describes how to deploy Azure landing zones with connectivity resources based on the [Virtual WAN network topology (Microsoft-managed)][wiki_connectivity_resources_virtual_wan] created in the current Subscription context, using custom configuration settings. +This page describes how to deploy a multi-region Azure landing zone with connectivity resources based on the [Virtual WAN network topology (Microsoft-managed)][wiki_connectivity_resources_virtual_wan] created in the current Subscription context, using custom configuration settings. > **NOTE:** > If you need to deploy a network based on traditional virtual networks, please see our [Deploy Connectivity Resources With Custom Settings (Hub and Spoke)][wiki_deploy_connectivity_resources_custom] example. diff --git a/docs/wiki/[User-Guide]-Upgrade-from-v5.2.1-to-v6.0.0.md b/docs/wiki/[User-Guide]-Upgrade-from-v5.2.1-to-v6.0.0.md index 5e1edfd3e..d92cc6ef6 100644 --- a/docs/wiki/[User-Guide]-Upgrade-from-v5.2.1-to-v6.0.0.md +++ b/docs/wiki/[User-Guide]-Upgrade-from-v5.2.1-to-v6.0.0.md @@ -23,7 +23,7 @@ See: ## Azure Monitor Agent -The Microsoft Monitoring Agent is deprecated and all assignments have been removed, howwver the policy definitions remain. +The Microsoft Monitoring Agent is deprecated and all assignments have been removed, however the policy definitions remain. We now assign polices that deploy the Azure Monitor Agent (AMA) instead of the Microsoft Monitoring Agent (MMA). We deploy AMA resources using the new `configure_management_resources` variable. diff --git a/docs/wiki/_Sidebar.md b/docs/wiki/_Sidebar.md index 3a6c7ee9a..47a6764e5 100644 --- a/docs/wiki/_Sidebar.md +++ b/docs/wiki/_Sidebar.md @@ -32,8 +32,8 @@ - [Create and assign custom RBAC roles][wiki_create_and_assign_custom_rbac_roles] - [Set parameter values for Policy Assignments][wiki_set_parameter_values_for_policy_assignments] - [Level 300][wiki_examples_level_300] - - [Deploy connectivity resources with custom settings (Hub and Spoke)][wiki_deploy_connectivity_resources_custom] - - [Deploy connectivity resources with custom settings (Virtual WAN)][wiki_deploy_virtual_wan_resources_custom] + - [Deploy multi region networking with custom settings (Hub and Spoke)][wiki_deploy_connectivity_resources_custom] + - [Deploy multi region networking with custom settings (Virtual WAN)][wiki_deploy_virtual_wan_resources_custom] - [Deploy with Zero Trust network principles (Hub and Spoke)][wiki_deploy_ZT_network] - [Deploy identity resources with custom settings][wiki_deploy_identity_resources_custom] - [Deploy management resources with custom settings][wiki_deploy_management_resources_custom] @@ -84,9 +84,9 @@ [wiki_deploy_management_resources]: %5BExamples%5D-Deploy-Management-Resources "Wiki - Deploy management resources" [wiki_deploy_management_resources_custom]: %5BExamples%5D-Deploy-Management-Resources-With-Custom-Settings "Wiki - Deploy management resources with custom settings" [wiki_deploy_connectivity_resources]: %5BExamples%5D-Deploy-Connectivity-Resources "Wiki - Deploy connectivity resources (Hub and Spoke)" -[wiki_deploy_connectivity_resources_custom]: %5BExamples%5D-Deploy-Connectivity-Resources-With-Custom-Settings "Wiki - Deploy connectivity resources with custom settings (Hub and Spoke)" +[wiki_deploy_connectivity_resources_custom]: %5BExamples%5D-Deploy-Multi-Region-Networking-With-Custom-Settings "Wiki - Deploy multi region networking with custom settings (Hub and Spoke)" [wiki_deploy_virtual_wan_resources]: %5BExamples%5D-Deploy-Virtual-WAN-Resources "Wiki - Deploy connectivity resources (Virtual WAN)" -[wiki_deploy_virtual_wan_resources_custom]: %5BExamples%5D-Deploy-Virtual-WAN-Resources-With-Custom-Settings "Wiki - Deploy connectivity resources with custom settings (Virtual WAN)" +[wiki_deploy_virtual_wan_resources_custom]: %5BExamples%5D-Deploy-Virtual-WAN-Multi-Region-With-Custom-Settings "Wiki - Deploy multi region networking with custom settings (Virtual WAN)" [wiki_deploy_identity_resources]: %5BExamples%5D-Deploy-Identity-Resources "Wiki - Deploy identity resources" [wiki_deploy_identity_resources_custom]: %5BExamples%5D-Deploy-Identity-Resources-With-Custom-Settings "Wiki - Deploy identity resources with custom settings" [wiki_deploy_using_module_nesting]: %5BExamples%5D-Deploy-Using-Module-Nesting "Wiki - Deploy using module nesting" diff --git a/examples/complete/main.tf b/examples/complete/main.tf index c3168a79d..bd38cb1dc 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -15,6 +15,7 @@ data "azurerm_client_config" "core" {} module "enterprise_scale" { + # source = "clouddrove/landingzone/azure" source = "../../" # version = "5.0.3" # change this to your desired version, https://www.terraform.io/language/expressions/version-constraints diff --git a/locals.management.tf b/locals.management.tf index 6f8ab8970..d739ee8b1 100644 --- a/locals.management.tf +++ b/locals.management.tf @@ -66,3 +66,11 @@ locals { if resource.managed_by_module } } + +# locals { +# azapi_sentinel_onboarding = { +# for resource in module.management_resources.configuration.azapi_sentinel_onboarding : +# resource.resource_id => resource +# if resource.managed_by_module +# } +# } diff --git a/locals.role_assignments.tf b/locals.role_assignments.tf index 86bfe1fa5..274c5a2c1 100644 --- a/locals.role_assignments.tf +++ b/locals.role_assignments.tf @@ -44,4 +44,5 @@ locals { locals { connectivity_mg_exists = length([for k, v in local.es_landing_zones_map : v if(v.id == "${var.root_id}-connectivity")]) > 0 -} \ No newline at end of file + platform_mg_exists = length([for k, v in local.es_landing_zones_map : v if(v.id == "${var.root_id}-platform")]) > 0 +} diff --git a/main.tf b/main.tf index 4a42a4f8a..a641b4e20 100644 --- a/main.tf +++ b/main.tf @@ -75,12 +75,13 @@ module "connectivity_resources" { tags = local.connectivity_resources_tags # Optional input variables (advanced configuration) - resource_prefix = lookup(local.connectivity_resources_advanced, "resource_prefix", local.empty_string) - resource_suffix = lookup(local.connectivity_resources_advanced, "resource_suffix", local.empty_string) - existing_ddos_protection_plan_resource_id = lookup(local.connectivity_resources_advanced, "existing_ddos_protection_plan_resource_id", local.empty_string) - existing_virtual_wan_resource_id = lookup(local.connectivity_resources_advanced, "existing_virtual_wan_resource_id", local.empty_string) - existing_virtual_wan_resource_group_name = lookup(local.connectivity_resources_advanced, "existing_virtual_wan_resource_group_name", local.empty_string) - resource_group_per_virtual_hub_location = lookup(local.connectivity_resources_advanced, "resource_group_per_virtual_hub_location", false) - custom_azure_backup_geo_codes = lookup(local.connectivity_resources_advanced, "custom_azure_backup_geo_codes", local.empty_map) - custom_settings_by_resource_type = lookup(local.connectivity_resources_advanced, "custom_settings_by_resource_type", local.empty_map) + resource_prefix = lookup(local.connectivity_resources_advanced, "resource_prefix", local.empty_string) + resource_suffix = lookup(local.connectivity_resources_advanced, "resource_suffix", local.empty_string) + existing_ddos_protection_plan_resource_id = lookup(local.connectivity_resources_advanced, "existing_ddos_protection_plan_resource_id", local.empty_string) + existing_virtual_wan_resource_id = lookup(local.connectivity_resources_advanced, "existing_virtual_wan_resource_id", local.empty_string) + existing_virtual_wan_resource_group_name = lookup(local.connectivity_resources_advanced, "existing_virtual_wan_resource_group_name", local.empty_string) + resource_group_per_virtual_hub_location = lookup(local.connectivity_resources_advanced, "resource_group_per_virtual_hub_location", false) + custom_azure_backup_geo_codes = lookup(local.connectivity_resources_advanced, "custom_azure_backup_geo_codes", local.empty_map) + custom_privatelink_azurestaticapps_partitionids = lookup(local.connectivity_resources_advanced, "custom_privatelink_azurestaticapps_partitionids", null) + custom_settings_by_resource_type = lookup(local.connectivity_resources_advanced, "custom_settings_by_resource_type", local.empty_map) } diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_private_dns_zones.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_private_dns_zones.tmpl.json index 97f15044f..27be37895 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_private_dns_zones.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_deploy_private_dns_zones.tmpl.json @@ -1430,13 +1430,13 @@ "policyDefinitionReferenceId": "DINE-Private-DNS-Azure-Arc", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/55c4db33-97b0-437b-8469-c4f4498f5df9", "parameters": { - "privateDnsZoneIdForGuestConfiguration": { + "privateDnsZoneIDForGuestConfiguration": { "value": "[parameters('azureArcGuestconfigurationPrivateDnsZoneId')]" }, - "privateDnsZoneIdForHybridResourceProvider": { + "privateDnsZoneIDForHybridResourceProvider": { "value": "[parameters('azureArcHybridResourceProviderPrivateDnsZoneId')]" }, - "privateDnsZoneIdForKubernetesConfiguration": { + "privateDnsZoneIDForKubernetesConfiguration": { "value": "[parameters('azureArcKubernetesConfigurationPrivateDnsZoneId')]" }, "effect": { diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_backup.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_backup.tmpl.json index 30de60651..9c1c69e4c 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_backup.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_backup.tmpl.json @@ -63,7 +63,7 @@ "effect": { "value": "[parameters('effect')]" }, - "CheckLockedImmutabiltyOnly": { + "checkLockedImmutabiltyOnly": { "value": "[parameters('checkLockedImmutabilityOnly')]" } }, diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_keyvault.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_keyvault.tmpl.json index 1663c22df..c46d2cc28 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_keyvault.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_keyvault.tmpl.json @@ -8,7 +8,7 @@ "displayName": "Enforce recommended guardrails for Azure Key Vault", "description": "Enforce recommended guardrails for Azure Key Vault.", "metadata": { - "version": "2.0.0", + "version": "2.1.0", "category": "Key Vault", "source": "https://github.com/Azure/Enterprise-Scale/", "alzCloudEnvironments": [ @@ -236,8 +236,11 @@ "type": "string", "defaultValue": "Disabled", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_kubernetes.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_kubernetes.tmpl.json index 44ac2927e..85c57faf1 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_kubernetes.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_kubernetes.tmpl.json @@ -8,7 +8,7 @@ "displayName": "Enforce recommended guardrails for Kubernetes", "description": "This policy initiative is a group of policies that ensures Kubernetes is compliant per regulated Landing Zones.", "metadata": { - "version": "1.0.0", + "version": "1.1.0", "category": "Kubernetes", "source": "https://github.com/Azure/Enterprise-Scale/", "alzCloudEnvironments": [ @@ -81,8 +81,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, @@ -90,8 +93,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, @@ -99,8 +105,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, @@ -117,8 +126,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, @@ -126,8 +138,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, @@ -144,8 +159,11 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ + "audit", "Audit", + "deny", "Deny", + "disabled", "Disabled" ] }, diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_network.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_network.tmpl.json index 4de2ce7f4..28a05525f 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_network.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_network.tmpl.json @@ -8,7 +8,7 @@ "displayName": "Enforce recommended guardrails for Network and Networking services", "description": "This policy initiative is a group of policies that ensures Network and Networking services are compliant per regulated Landing Zones.", "metadata": { - "version": "1.0.0", + "version": "1.1.0", "category": "Network", "source": "https://github.com/Azure/Enterprise-Scale/", "alzCloudEnvironments": [ @@ -56,7 +56,12 @@ }, "vnetModifyDdos": { "type": "string", - "defaultValue": "Modify" + "defaultValue": "Modify", + "allowedValues": [ + "Audit", + "Modify", + "Disabled" + ] }, "ddosPlanResourceId": { "type": "string", @@ -229,9 +234,8 @@ "type": "string", "defaultValue": "Deny", "allowedValues": [ - "Audit", - "Deny", - "Disabled" + "Allow", + "Deny" ] }, "modifyNsgRuleProtocol": { diff --git a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_synapse.tmpl.json b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_synapse.tmpl.json index 96b0213ea..011c041ca 100644 --- a/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_synapse.tmpl.json +++ b/modules/archetypes/lib/policy_set_definitions/policy_set_definition_es_enforce_guardrails_synapse.tmpl.json @@ -8,7 +8,7 @@ "displayName": "Enforce recommended guardrails for Synapse workspaces", "description": "This policy initiative is a group of policies that ensures Synapse workspaces is compliant per regulated Landing Zones.", "metadata": { - "version": "1.0.0", + "version": "1.1.0", "category": "Synapse", "source": "https://github.com/Azure/Enterprise-Scale/", "alzCloudEnvironments": [ @@ -65,7 +65,6 @@ "defaultValue": "Audit", "allowedValues": [ "Audit", - "Deny", "Disabled" ] }, diff --git a/modules/connectivity/README.md b/modules/connectivity/README.md index 4df0f68f7..a11d5032e 100644 --- a/modules/connectivity/README.md +++ b/modules/connectivity/README.md @@ -49,6 +49,25 @@ Type: `map(string)` Default: `{}` +### [custom\_privatelink\_azurestaticapps\_partitionids](#input\_custom\_privatelink\_azurestaticapps\_partitionids) + +Description: As a uncertanty in the partition id for the azure static web app, this variable is used to specify the partition ids deployed for the azure static web app private DNS zones. +For more information, please refer to: https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-dns#web and https://learn.microsoft.com/en-us/azure/static-web-apps/private-endpoint + +Type: `list(number)` + +Default: + +```json +[ + 1, + 2, + 3, + 4, + 5 +] +``` + ### [custom\_settings\_by\_resource\_type](#input\_custom\_settings\_by\_resource\_type) Description: If specified, allows full customization of common settings for all resources (by type) deployed by this module. diff --git a/modules/connectivity/locals.tf b/modules/connectivity/locals.tf index a81ed48a3..f12cbee4b 100644 --- a/modules/connectivity/locals.tf +++ b/modules/connectivity/locals.tf @@ -12,20 +12,21 @@ locals { # 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 = lower(var.location) - tags = var.tags - resource_prefix = coalesce(var.resource_prefix, local.root_id) - resource_suffix = var.resource_suffix != local.empty_string ? "-${var.resource_suffix}" : local.empty_string - existing_ddos_protection_plan_resource_id = var.existing_ddos_protection_plan_resource_id - existing_virtual_wan_resource_id = var.existing_virtual_wan_resource_id != null ? var.existing_virtual_wan_resource_id : local.empty_string - existing_virtual_wan_resource_group_name = var.existing_virtual_wan_resource_group_name != null ? var.existing_virtual_wan_resource_group_name : local.empty_string - resource_group_per_virtual_hub_location = var.resource_group_per_virtual_hub_location - custom_azure_backup_geo_codes = var.custom_azure_backup_geo_codes - custom_settings = var.custom_settings_by_resource_type + enabled = var.enabled + root_id = var.root_id + subscription_id = coalesce(var.subscription_id, "00000000-0000-0000-0000-000000000000") + settings = var.settings + location = lower(var.location) + tags = var.tags + resource_prefix = coalesce(var.resource_prefix, local.root_id) + resource_suffix = var.resource_suffix != local.empty_string ? "-${var.resource_suffix}" : local.empty_string + existing_ddos_protection_plan_resource_id = var.existing_ddos_protection_plan_resource_id + existing_virtual_wan_resource_id = var.existing_virtual_wan_resource_id != null ? var.existing_virtual_wan_resource_id : local.empty_string + existing_virtual_wan_resource_group_name = var.existing_virtual_wan_resource_group_name != null ? var.existing_virtual_wan_resource_group_name : local.empty_string + resource_group_per_virtual_hub_location = var.resource_group_per_virtual_hub_location + custom_azure_backup_geo_codes = var.custom_azure_backup_geo_codes + custom_privatelink_azurestaticapps_partitionids = var.custom_privatelink_azurestaticapps_partitionids + custom_settings = var.custom_settings_by_resource_type } # Logic to help keep code DRY @@ -419,7 +420,6 @@ locals { # Resource definition attributes resource_group_name = local.resource_group_names_by_scope_and_location["connectivity"][location] virtual_network_name = local.virtual_network_name[location] - private_endpoint_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location][subnet.name].private_endpoint_network_policies_enabled, null) private_link_service_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location][subnet.name].private_link_service_network_policies_enabled, null) service_endpoints = try(local.custom_settings.azurerm_subnet["connectivity"][location][subnet.name].service_endpoints, null) service_endpoint_policy_ids = try(local.custom_settings.azurerm_subnet["connectivity"][location][subnet.name].service_endpoint_policy_ids, null) @@ -440,7 +440,6 @@ locals { address_prefixes = [hub_network.config.virtual_network_gateway.config.address_prefix, ] resource_group_name = local.resource_group_names_by_scope_and_location["connectivity"][location] virtual_network_name = local.virtual_network_name[location] - private_endpoint_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["GatewaySubnet"].private_endpoint_network_policies_enabled, null) private_link_service_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["GatewaySubnet"].private_link_service_network_policies_enabled, null) service_endpoints = try(local.custom_settings.azurerm_subnet["connectivity"][location]["GatewaySubnet"].service_endpoints, null) service_endpoint_policy_ids = try(local.custom_settings.azurerm_subnet["connectivity"][location]["GatewaySubnet"].service_endpoint_policy_ids, null) @@ -460,7 +459,6 @@ locals { address_prefixes = [hub_network.config.azure_firewall.config.address_prefix, ] resource_group_name = local.resource_group_names_by_scope_and_location["connectivity"][location] virtual_network_name = local.virtual_network_name[location] - private_endpoint_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallSubnet"].private_endpoint_network_policies_enabled, null) private_link_service_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallSubnet"].private_link_service_network_policies_enabled, null) service_endpoints = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallSubnet"].service_endpoints, null) service_endpoint_policy_ids = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallSubnet"].service_endpoint_policy_ids, null) @@ -480,7 +478,6 @@ locals { address_prefixes = [hub_network.config.azure_firewall.config.address_management_prefix, ] resource_group_name = local.resource_group_names_by_scope_and_location["connectivity"][location] virtual_network_name = local.virtual_network_name[location] - private_endpoint_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallManagementSubnet"].private_endpoint_network_policies_enabled, null) private_link_service_network_policies_enabled = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallManagementSubnet"].private_link_service_network_policies_enabled, null) service_endpoints = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallManagementSubnet"].service_endpoints, null) service_endpoint_policy_ids = try(local.custom_settings.azurerm_subnet["connectivity"][location]["AzureFirewallManagementSubnet"].service_endpoint_policy_ids, null) @@ -1495,7 +1492,7 @@ locals { azure_synapse_analytics_sql = ["privatelink.sql.azuresynapse.net"] azure_synapse_studio = ["privatelink.azuresynapse.net"] azure_virtual_desktop = ["privatelink.wvd.microsoft.com"] - azure_web_apps_sites = ["privatelink.azurewebsites.net", "scm.privatelink.azurewebsites.net"] + azure_web_apps_sites = ["privatelink.azurewebsites.net"] azure_web_apps_static_sites = ["privatelink.azurestaticapps.net"] cognitive_services_account = ["privatelink.cognitiveservices.azure.com"] microsoft_power_bi = ["privatelink.analysis.windows.net", "privatelink.pbidedicated.windows.net", "privatelink.tip1.powerquery.microsoft.com"] @@ -1518,6 +1515,10 @@ locals { for location in local.private_link_locations : "privatelink.${location}.azmk8s.io" ] + azure_web_apps_static_sites = concat(["privatelink.azurestaticapps.net"], [ + for partitionid in local.custom_privatelink_azurestaticapps_partitionids : + "privatelink.${partitionid}.azurestaticapps.net" + ]) } # The lookup_private_link_group_id_by_service local doesn't currently # do anything but is planned to control policy configuration for @@ -1681,7 +1682,7 @@ locals { [ for location, virtual_hub_config in local.virtual_hubs_by_location : [ - for spoke_resource_id in virtual_hub_config.config.spoke_virtual_network_resource_ids : + for spoke_resource_id in concat(virtual_hub_config.config.spoke_virtual_network_resource_ids, virtual_hub_config.config.secure_spoke_virtual_network_resource_ids) : { resource_id = spoke_resource_id name = "${split("/", spoke_resource_id)[2]}-${uuidv5("url", spoke_resource_id)}" diff --git a/modules/connectivity/variables.tf b/modules/connectivity/variables.tf index 1606f9e0a..c72987d0d 100644 --- a/modules/connectivity/variables.tf +++ b/modules/connectivity/variables.tf @@ -367,6 +367,16 @@ DESCRIPTION default = {} } +variable "custom_privatelink_azurestaticapps_partitionids" { + type = list(number) + nullable = false + description = < value + if local.deploy_azure_monitor_solutions.SecurityInsights + } + managed_by_module = local.deploy_azure_monitor_solutions.SecurityInsights + } + ] archetype_config_overrides = local.archetype_config_overrides template_file_variables = local.template_file_variables } diff --git a/modules/management/variables.tf b/modules/management/variables.tf index 179aff872..2f982b168 100644 --- a/modules/management/variables.tf +++ b/modules/management/variables.tf @@ -53,11 +53,14 @@ variable "settings" { log_analytics = optional(object({ enabled = optional(bool, true) config = optional(object({ - retention_in_days = optional(number, 30) - enable_monitoring_for_vm = optional(bool, true) - enable_monitoring_for_vmss = optional(bool, true) - enable_sentinel = optional(bool, true) - enable_change_tracking = optional(bool, true) + retention_in_days = optional(number, 30) + enable_monitoring_for_vm = optional(bool, true) + enable_monitoring_for_vmss = optional(bool, true) + enable_sentinel = optional(bool, true) + enable_change_tracking = optional(bool, true) + enable_solution_for_vm_insights = optional(bool, true) + enable_solution_for_container_insights = optional(bool, true) + sentinel_customer_managed_key_enabled = optional(bool, false) }), {}) }), {}) security_center = optional(object({ @@ -136,7 +139,7 @@ variable "custom_settings_by_resource_type" { 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 == {} + 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", "azurerm_data_collection_rule"], 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/resources.connectivity.tf b/resources.connectivity.tf index 6bc9ee75e..89920cfd9 100644 --- a/resources.connectivity.tf +++ b/resources.connectivity.tf @@ -55,7 +55,6 @@ resource "azurerm_subnet" "connectivity" { address_prefixes = each.value.template.address_prefixes # Optional resource attributes - private_endpoint_network_policies_enabled = each.value.template.private_endpoint_network_policies_enabled private_link_service_network_policies_enabled = each.value.template.private_link_service_network_policies_enabled service_endpoints = each.value.template.service_endpoints service_endpoint_policy_ids = each.value.template.service_endpoint_policy_ids diff --git a/resources.management.tf b/resources.management.tf index cac2feb63..a86b7f08a 100644 --- a/resources.management.tf +++ b/resources.management.tf @@ -167,3 +167,20 @@ resource "azapi_resource" "data_collection_rule" { depends_on = [azurerm_log_analytics_workspace.management] } + +# Delaying until next major release as this will be a breaking change requiring state manipulation +# as the old LA solution will have to be removed from state, but we cannot use the removed block as +# it does not support interpolation for map keys. +# +# resource "azapi_resource" "sentinel_onboarding" { +# for_each = local.azapi_sentinel_onboarding +# name = each.value.template.name +# parent_id = each.value.template.parent_id +# type = each.value.template.type +# body = each.value.template.body + +# depends_on = [ +# azurerm_log_analytics_workspace.management, +# azurerm_log_analytics_solution.management, +# ] +# } diff --git a/resources.management_groups.tf b/resources.management_groups.tf index 19dcc7428..1cda6e248 100644 --- a/resources.management_groups.tf +++ b/resources.management_groups.tf @@ -79,12 +79,12 @@ resource "azurerm_management_group" "level_6" { # This will deploy Diagnostic Settings for the Management Groups # when the input variable deploy_diagnostics_for_mg is true resource "azapi_resource" "diag_settings" { - for_each = local.azapi_mg_diagnostics - type = "Microsoft.Insights/diagnosticSettings@2021-05-01-preview" - name = "toLA" - location = local.default_location - parent_id = each.key - body = jsonencode({ + for_each = local.azapi_mg_diagnostics + type = "Microsoft.Insights/diagnosticSettings@2021-05-01-preview" + name = "toLA" + parent_id = each.key + schema_validation_enabled = false + body = { properties = { logAnalyticsDestinationType = "null" logs = [ @@ -99,7 +99,7 @@ resource "azapi_resource" "diag_settings" { ] workspaceId = local.template_file_variables.log_analytics_workspace_resource_id } - }) + } depends_on = [ time_sleep.after_azurerm_management_group, azurerm_management_group.level_1, diff --git a/resources.role_assignments.tf b/resources.role_assignments.tf index e25e4944b..6fa63e82b 100644 --- a/resources.role_assignments.tf +++ b/resources.role_assignments.tf @@ -33,7 +33,7 @@ module "role_assignments_for_policy" { policy_assignment_id = each.key scope_id = azurerm_management_group_policy_assignment.enterprise_scale[each.key].management_group_id principal_id = ( - lookup(azurerm_management_group_policy_assignment.enterprise_scale[each.key].identity[0], "type") == "UserAssigned" + lookup(azurerm_management_group_policy_assignment.enterprise_scale[each.key].identity[0], "type", "") == "UserAssigned" ? jsondecode(data.azapi_resource.user_msi[each.key].output).properties.principalId # workarround as azurerm_management_group_policy_assignment does not export the principal_id when using UserAssigned identity : azurerm_management_group_policy_assignment.enterprise_scale[each.key].identity[0].principal_id ) @@ -55,7 +55,7 @@ module "role_assignments_for_policy" { # The data source will retrieve the principalId of a user msi # used for the policy assignment -# +# data "azapi_resource" "user_msi" { for_each = { for ik, iv in local.es_role_assignments_by_policy_assignment : ik => iv @@ -114,4 +114,32 @@ resource "azurerm_role_assignment" "private_dns_zone_contributor_connectivity" { time_sleep.after_azurerm_policy_assignment, azurerm_role_assignment.policy_assignment, ] -} \ No newline at end of file +} + +resource "azurerm_role_assignment" "ama_reader" { + for_each = local.platform_mg_exists ? { for k, v in azurerm_management_group_policy_assignment.enterprise_scale : k => v if endswith(k, "Deploy-VM-Monitoring") } : {} + role_definition_name = "Reader" + scope = "/providers/Microsoft.Management/managementGroups/${var.root_id}-platform" + principal_id = each.value.identity[0].principal_id + depends_on = [ + time_sleep.after_azurerm_management_group, + time_sleep.after_azurerm_policy_definition, + time_sleep.after_azurerm_policy_set_definition, + time_sleep.after_azurerm_policy_assignment, + azurerm_role_assignment.policy_assignment, + ] +} + +resource "azurerm_role_assignment" "ama_managed_identity_operator" { + for_each = local.platform_mg_exists ? { for k, v in azurerm_management_group_policy_assignment.enterprise_scale : k => v if endswith(k, "Deploy-VM-Monitoring") } : {} + role_definition_name = "Managed Identity Operator" + scope = "/providers/Microsoft.Management/managementGroups/${var.root_id}-platform" + principal_id = each.value.identity[0].principal_id + depends_on = [ + time_sleep.after_azurerm_management_group, + time_sleep.after_azurerm_policy_definition, + time_sleep.after_azurerm_policy_set_definition, + time_sleep.after_azurerm_policy_assignment, + azurerm_role_assignment.policy_assignment, + ] +} diff --git a/tests/scripts/azp-strategy.ps1 b/tests/scripts/azp-strategy.ps1 index 4c22f79ef..f78a93c82 100755 --- a/tests/scripts/azp-strategy.ps1 +++ b/tests/scripts/azp-strategy.ps1 @@ -21,15 +21,14 @@ Write-Information "==> Generating Azure Pipelines Strategy Matrix..." -Informati $jsonDepth = 4 $terraformUrl = "https://api.github.com/repos/hashicorp/terraform/tags" -$azurermProviderUrl = "https://registry.terraform.io/v1/providers/hashicorp/azurerm" function Get-RandomId { - [CmdletBinding()] - [OutputType([String])] - param ( - [Int]$Length = 8 - ) - return -join ((48..57) + (97..122) | Get-Random -Count $Length | ForEach-Object { [char]$_ }) + [CmdletBinding()] + [OutputType([String])] + param ( + [Int]$Length = 8 + ) + return -join ((48..57) + (97..122) | Get-Random -Count $Length | ForEach-Object { [char]$_ }) } ######################################## @@ -56,7 +55,7 @@ $terraformVersionsCount = $terraformVersions.Count ####################################### $azurermProviderVersionBase = "3.107.0" -$azurermProviderVersionLatest = (Invoke-RestMethod -Method Get -Uri $azurermProviderUrl).version +$azurermProviderVersionLatest = "3.116.0" ####################################### # Generate Subscription Aliases @@ -64,7 +63,7 @@ $azurermProviderVersionLatest = (Invoke-RestMethod -Method Get -Uri $azurermProv Write-Information "==> Checking for `"Az.Accounts`" PowerShell module..." -InformationAction Continue if ((Get-Module -ListAvailable "Az.Accounts").Count -eq 0) { - Install-Module -Name "Az.Accounts" -Force + Install-Module -Name "Az.Accounts" -Force } Import-Module -Name "Az.Accounts" -Force @@ -72,72 +71,72 @@ Write-Information "==> Getting Subscription Aliases..." -InformationAction Conti Write-Verbose "Switching Azure Context using Client ID [$($env:ARM_CLIENT_ID)]." $Credential = New-Object System.Management.Automation.PSCredential ( - $($env:ARM_CLIENT_ID), - $($env:ARM_CLIENT_SECRET | ConvertTo-SecureString -AsPlainText -Force) + $($env:ARM_CLIENT_ID), + $($env:ARM_CLIENT_SECRET | ConvertTo-SecureString -AsPlainText -Force) ) $ctx = Connect-AzAccount ` - -ServicePrincipal ` - -Tenant $($env:ARM_TENANT_ID) ` - -SubscriptionId $($env:ARM_SUBSCRIPTION_ID) ` - -Credential $Credential ` - -WarningAction SilentlyContinue + -ServicePrincipal ` + -Tenant $($env:ARM_TENANT_ID) ` + -SubscriptionId $($env:ARM_SUBSCRIPTION_ID) ` + -Credential $Credential ` + -WarningAction SilentlyContinue Write-Information " Successfully authenticated account ($($ctx.Context.Account.Id))." -InformationAction Continue Write-Verbose "Checking for Management Subscription Aliases." $subscriptionAliasesManagement = [PSCustomObject]@{} for ($i = 1; $i -lt (($terraformVersionsCount * 2) + 1); $i++) { - $alias = "csu-tf-management-$i" - $aliasesApiVersion = "2020-09-01" - $requestPath = "/providers/Microsoft.Subscription/aliases/$($alias)?api-version=$($aliasesApiVersion)" - $requestMethod = "PUT" - $requestBody = @{ - properties = @{ - displayName = $alias - billingScope = $($env:BILLING_SCOPE) - workload = "Production" - } - } | ConvertTo-Json -Depth 10 - $aliasResponse = Invoke-AzRestMethod -Method $requestMethod -Path $requestPath -Payload $requestBody - if ($aliasResponse.StatusCode -eq "200") { - $subscriptionId = ($aliasResponse.Content | ConvertFrom-Json).properties.subscriptionId - Write-Information " Found Subscription Alias ($($alias)) ($($subscriptionId))." -InformationAction Continue + $alias = "csu-tf-management-$i" + $aliasesApiVersion = "2020-09-01" + $requestPath = "/providers/Microsoft.Subscription/aliases/$($alias)?api-version=$($aliasesApiVersion)" + $requestMethod = "PUT" + $requestBody = @{ + properties = @{ + displayName = $alias + billingScope = $($env:BILLING_SCOPE) + workload = "Production" } - else { - Write-Warning "Unable to find Subscription Alias ($($alias)). Failing back to current Subscription context ($($env:ARM_SUBSCRIPTION_ID))." - $subscriptionId = $env:ARM_SUBSCRIPTION_ID - } - $subscriptionAliasesManagement | Add-Member ` - -NotePropertyName "$alias" ` - -NotePropertyValue "$subscriptionId" + } | ConvertTo-Json -Depth 10 + $aliasResponse = Invoke-AzRestMethod -Method $requestMethod -Path $requestPath -Payload $requestBody + if ($aliasResponse.StatusCode -eq "200") { + $subscriptionId = ($aliasResponse.Content | ConvertFrom-Json).properties.subscriptionId + Write-Information " Found Subscription Alias ($($alias)) ($($subscriptionId))." -InformationAction Continue + } + else { + Write-Warning "Unable to find Subscription Alias ($($alias)). Failing back to current Subscription context ($($env:ARM_SUBSCRIPTION_ID))." + $subscriptionId = $env:ARM_SUBSCRIPTION_ID + } + $subscriptionAliasesManagement | Add-Member ` + -NotePropertyName "$alias" ` + -NotePropertyValue "$subscriptionId" } Write-Verbose "Checking for Connectivity Subscription Aliases." $subscriptionAliasesConnectivity = [PSCustomObject]@{} for ($i = 1; $i -lt (($terraformVersionsCount * 2) + 1); $i++) { - $alias = "csu-tf-connectivity-$i" - $aliasesApiVersion = "2020-09-01" - $requestPath = "/providers/Microsoft.Subscription/aliases/$($alias)?api-version=$($aliasesApiVersion)" - $requestMethod = "PUT" - $requestBody = @{ - properties = @{ - displayName = $alias - billingScope = $($env:BILLING_SCOPE) - workload = "Production" - } - } | ConvertTo-Json -Depth 10 - $aliasResponse = Invoke-AzRestMethod -Method $requestMethod -Path $requestPath -Payload $requestBody - if ($aliasResponse.StatusCode -eq "200") { - $subscriptionId = ($aliasResponse.Content | ConvertFrom-Json).properties.subscriptionId - Write-Information " Found Subscription Alias ($($alias)) ($($subscriptionId))." -InformationAction Continue - } - else { - Write-Warning "Unable to find Subscription Alias ($($alias)). Failing back to current Subscription context ($($env:ARM_SUBSCRIPTION_ID))." - $subscriptionId = $env:ARM_SUBSCRIPTION_ID + $alias = "csu-tf-connectivity-$i" + $aliasesApiVersion = "2020-09-01" + $requestPath = "/providers/Microsoft.Subscription/aliases/$($alias)?api-version=$($aliasesApiVersion)" + $requestMethod = "PUT" + $requestBody = @{ + properties = @{ + displayName = $alias + billingScope = $($env:BILLING_SCOPE) + workload = "Production" } - $subscriptionAliasesConnectivity | Add-Member ` - -NotePropertyName "$alias" ` - -NotePropertyValue "$subscriptionId" + } | ConvertTo-Json -Depth 10 + $aliasResponse = Invoke-AzRestMethod -Method $requestMethod -Path $requestPath -Payload $requestBody + if ($aliasResponse.StatusCode -eq "200") { + $subscriptionId = ($aliasResponse.Content | ConvertFrom-Json).properties.subscriptionId + Write-Information " Found Subscription Alias ($($alias)) ($($subscriptionId))." -InformationAction Continue + } + else { + Write-Warning "Unable to find Subscription Alias ($($alias)). Failing back to current Subscription context ($($env:ARM_SUBSCRIPTION_ID))." + $subscriptionId = $env:ARM_SUBSCRIPTION_ID + } + $subscriptionAliasesConnectivity | Add-Member ` + -NotePropertyName "$alias" ` + -NotePropertyValue "$subscriptionId" } ############################################################################# @@ -148,33 +147,33 @@ Write-Information "==> Building Strategy Matrix..." -InformationAction Continue $matrixObject = [PSCustomObject]@{} for ($i = 0; $i -lt $terraformVersionsCount; $i++) { - $terraformVersion = $terraformVersions[$i] - $jobId1 = ($i * 2) + 1 - $jobId2 = ($i * 2) + 2 - $jobName1 = "$jobId1. (TF: $terraformVersion, AZ: $azurermProviderVersionBase)" - $jobName2 = "$jobId2. (TF: $terraformVersion, AZ: $azurermProviderVersionLatest)" - $matrixObject | Add-Member ` - -NotePropertyName $jobName1 ` - -NotePropertyValue @{ - TF_ROOT_ID = Get-RandomId - TF_VERSION = $terraformVersion - TF_AZ_VERSION = $azurermProviderVersionBase - TF_JOB_ID = $jobId1 - TF_SUBSCRIPTION_ID_MANAGEMENT = ($subscriptionAliasesManagement."csu-tf-management-$jobId1") - TF_SUBSCRIPTION_ID_CONNECTIVITY = ($subscriptionAliasesConnectivity."csu-tf-connectivity-$jobId1") - } - Write-Information " Added job to matrix ($($jobName1))." -InformationAction Continue - $matrixObject | Add-Member ` - -NotePropertyName $jobName2 ` - -NotePropertyValue @{ - TF_ROOT_ID = Get-RandomId - TF_VERSION = $terraformVersion - TF_AZ_VERSION = $azurermProviderVersionLatest - TF_JOB_ID = $jobId2 - TF_SUBSCRIPTION_ID_MANAGEMENT = ($subscriptionAliasesManagement."csu-tf-management-$jobId2") - TF_SUBSCRIPTION_ID_CONNECTIVITY = ($subscriptionAliasesConnectivity."csu-tf-connectivity-$jobId2") - } - Write-Information " Added job to matrix ($($jobName2))." -InformationAction Continue + $terraformVersion = $terraformVersions[$i] + $jobId1 = ($i * 2) + 1 + $jobId2 = ($i * 2) + 2 + $jobName1 = "$jobId1. (TF: $terraformVersion, AZ: $azurermProviderVersionBase)" + $jobName2 = "$jobId2. (TF: $terraformVersion, AZ: $azurermProviderVersionLatest)" + $matrixObject | Add-Member ` + -NotePropertyName $jobName1 ` + -NotePropertyValue @{ + TF_ROOT_ID = Get-RandomId + TF_VERSION = $terraformVersion + TF_AZ_VERSION = $azurermProviderVersionBase + TF_JOB_ID = $jobId1 + TF_SUBSCRIPTION_ID_MANAGEMENT = ($subscriptionAliasesManagement."csu-tf-management-$jobId1") + TF_SUBSCRIPTION_ID_CONNECTIVITY = ($subscriptionAliasesConnectivity."csu-tf-connectivity-$jobId1") + } + Write-Information " Added job to matrix ($($jobName1))." -InformationAction Continue + $matrixObject | Add-Member ` + -NotePropertyName $jobName2 ` + -NotePropertyValue @{ + TF_ROOT_ID = Get-RandomId + TF_VERSION = $terraformVersion + TF_AZ_VERSION = $azurermProviderVersionLatest + TF_JOB_ID = $jobId2 + TF_SUBSCRIPTION_ID_MANAGEMENT = ($subscriptionAliasesManagement."csu-tf-management-$jobId2") + TF_SUBSCRIPTION_ID_CONNECTIVITY = ($subscriptionAliasesConnectivity."csu-tf-connectivity-$jobId2") + } + Write-Information " Added job to matrix ($($jobName2))." -InformationAction Continue } # Convert PSCustomObject to JSON. diff --git a/variables.tf b/variables.tf index e510f656d..e8a9a402c 100644 --- a/variables.tf +++ b/variables.tf @@ -26,8 +26,8 @@ variable "root_name" { default = "Enterprise-Scale" validation { - condition = can(regex("^[A-Za-z][A-Za-z0-9- ._]{1,22}[A-Za-z0-9]?$", var.root_name)) - 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." + condition = can(regex("^[A-Za-z][A-Za-z0-9- ._]{1,34}[A-Za-z0-9]?$", var.root_name)) + error_message = "Value must be between 2 to 35 characters long, start with a letter, end with a letter or number, and can only contain space, hyphen, underscore or period characters." } } @@ -85,11 +85,14 @@ variable "configure_management_resources" { log_analytics = optional(object({ enabled = optional(bool, true) config = optional(object({ - retention_in_days = optional(number, 30) - enable_monitoring_for_vm = optional(bool, true) - enable_monitoring_for_vmss = optional(bool, true) - enable_sentinel = optional(bool, true) - enable_change_tracking = optional(bool, true) + retention_in_days = optional(number, 30) + enable_monitoring_for_vm = optional(bool, true) + enable_monitoring_for_vmss = optional(bool, true) + enable_sentinel = optional(bool, true) + enable_change_tracking = optional(bool, true) + enable_solution_for_vm_insights = optional(bool, true) + enable_solution_for_container_insights = optional(bool, true) + sentinel_customer_managed_key_enabled = optional(bool, false) # not used at this time }), {}) }), {}) security_center = optional(object({