From 09c25c11742c188cf3f8d4333631991e482efbd0 Mon Sep 17 00:00:00 2001 From: Anthony Watherston Date: Tue, 13 Sep 2022 10:53:23 +1000 Subject: [PATCH] Add CAF sync script and assignments (#66) * Added CAF sync script and assignments * Cleanup and documentation --- README.md | 2 + .../Assignments/CAF-Connectivity-Default.json | 26 +++ .../Assignments/CAF-CorpMG-Default.json | 80 ++++++++ .../Assignments/CAF-IdentityMG-Default.json | 74 +++++++ .../Assignments/CAF-LandingZonesMG.json | 190 ++++++++++++++++++ .../Assignments/CAF-ManagementMG-Default.json | 34 ++++ .../Assignments/CAF-RootMG-Default.json | 175 ++++++++++++++++ Scripts/CloudAdoptionFramework/README.md | 73 +++++++ .../Sync-CAFPolicies.ps1 | 74 +++++++ 9 files changed, 728 insertions(+) create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-Connectivity-Default.json create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-CorpMG-Default.json create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-IdentityMG-Default.json create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-LandingZonesMG.json create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-ManagementMG-Default.json create mode 100644 Scripts/CloudAdoptionFramework/Assignments/CAF-RootMG-Default.json create mode 100644 Scripts/CloudAdoptionFramework/README.md create mode 100644 Scripts/CloudAdoptionFramework/Sync-CAFPolicies.ps1 diff --git a/README.md b/README.md index a055e4da..42b0afce 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ The repo contains a script to synchronize directories in both directions: `Sync- | **Deployment Scripts** | Scripts are used to deploy your Policies, Initiatives, and Assignments to Azure. They do not need to be modified. If you have improvements, please offer to contribute them. | Folder `Scripts/Deploy` | | **Operational Scripts** | Scripts used to during operations (e.g., creating remediation tasks). | Folder `Scripts/Operations` | | **Helper Scripts** | These Scripts are used by other scripts. | Folder `Scripts/Helpers` | +| **Cloud Adoption Framework Scripts** | The files in here are used to synchronize policies from the main ESLZ repository | Folder `Scripts\CloudAdoptionFramework` |
@@ -270,6 +271,7 @@ The repo contains a script to synchronize directories in both directions: `Sync- 1. **[Define Policy Exemptions](Definitions/Exemptions/README.md)** 1. **[Documenting Assignments and Initiatives](Definitions/Documentation/README.md)** 1. **[Operational Scripts](Scripts/Operations/README.md)** +1. **[Cloud Adoption Framework Policies](Scripts/CloudAdoptionFramework/README.md)**
diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-Connectivity-Default.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-Connectivity-Default.json new file mode 100644 index 00000000..690880b2 --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-Connectivity-Default.json @@ -0,0 +1,26 @@ +{ + "nodeName": "/Connectivity/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/connectivity" + ] + }, + "children": [ + { + "nodeName": "Networking", + "assignment": { + "name": "Enable-DDoS-VNET", + "displayName": "Virtual networks should be protected by Azure DDoS Protection Standard", + "description": "Protect your virtual networks against volumetric and protocol attacks with Azure DDoS Protection Standard. For more information, visit https://aka.ms/ddosprotectiondocs." + }, + "definitionEntry": { + "policyName": "94de2ad3-e0c1-4caf-ad78-5d47bbc83d3d", + "friendlyNameToDocumentIfGuid": "Audit D" + }, + "parameters": { + "effect": "Modify", + "ddosPlan": "" + } + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-CorpMG-Default.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-CorpMG-Default.json new file mode 100644 index 00000000..b71840a3 --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-CorpMG-Default.json @@ -0,0 +1,80 @@ +{ + "nodeName": "/Corp/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/corp" + ] + }, + "children": [ + { + "nodeName": "Networking/", + "children": [ + { + "nodeName": "PublicEndpoint", + "assignment": { + "name": "Deny-Public-Endpoints", + "displayName": "Public network access should be disabled for PaaS services", + "description": "This policy initiative is a group of policies that prevents creation of Azure PaaS services with exposed public endpoints" + }, + "definitionEntry": { + "initiativeName": "Deny-PublicPaaSEndpoints", + "friendlyNameToDocumentIfGuid": "Deny Public PaaS Endpoints" + } + }, + { + "nodeName": "PublicIP", + "assignment": { + "name": "Deny-Public-IP-Corp", + "displayName": "Deny the creation of public IP", + "description": "This policy denies creation of Public IPs under the assigned scope." + }, + "definitionEntry": { + "policyName": "Deny-PublicIP", + "friendlyNameToDocumentIfGuid": "Deny Public IP" + } + } + ] + }, + { + "nodeName": "Databricks/", + "children": [ + { + "nodeName": "NoDBPIP", + "assignment": { + "name": "Deny-DataB-Pip", + "displayName": "Prevent usage of Databricks with public IP", + "description": "Prevent the deployment of Databricks workspaces that do not use the noPublicIp feature to host Databricks clusters without public IPs." + }, + "definitionEntry": { + "policyName": "Deny-Databricks-NoPublicIp", + "friendlyNameToDocumentIfGuid": "Deny Databricks with Public Ip" + } + }, + { + "nodeName": "DbPremium", + "assignment": { + "name": "Deny-DataB-Sku", + "displayName": "Enforces the use of Premium Databricks workspaces", + "description": "Enforces the use of Premium Databricks workspaces to make sure appropriate security features are available including Databricks Access Controls, Credential Passthrough and SCIM provisioning for AAD." + }, + "definitionEntry": { + "policyName": "Deny-Databricks-Sku", + "friendlyNameToDocumentIfGuid": "Deny Databricks Sku" + } + }, + { + "nodeName": "DbVnet", + "assignment": { + "name": "Deny-DataB-Vnet", + "displayName": "Enforces the use of vnet injection for Databricks", + "description": "Enforces the use of vnet injection for Databricks workspaces." + }, + "definitionEntry": { + "policyName": "Deny-Databricks-VirtualNetwork", + "friendlyNameToDocumentIfGuid": "Deny Databricks Virtual Network" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-IdentityMG-Default.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-IdentityMG-Default.json new file mode 100644 index 00000000..025165be --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-IdentityMG-Default.json @@ -0,0 +1,74 @@ +{ + "nodeName": "/Identity/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/identity" + ] + }, + "children": [ + { + "nodeName": "Networking/", + "children": [ + { + "nodeName": "PublicIP", + "assignment": { + "name": "Deny-Public-IP", + "displayName": "Deny the creation of public IP", + "description": "This policy denies creation of Public IPs under the assigned scope." + }, + "definitionEntry": { + "policyName": "Deny-PublicIP", + "friendlyNameToDocumentIfGuid": "Deny Public IP" + } + }, + { + "nodeName": "RDP", + "assignment": { + "name": "Deny-RDP-From-Internet", + "displayName": "RDP access from the Internet should be blocked", + "description": "This policy denies any network security rule that allows RDP access from Internet." + }, + "definitionEntry": { + "policyName": "Deny-RDP-From-Internet", + "friendlyNameToDocumentIfGuid": "Deny RDP From Internet" + } + }, + { + "nodeName": "NoNSG", + "assignment": { + "name": "Deny-Subnet-Without-Nsg", + "displayName": "Subnets should have a Network Security Group", + "description": "This policy denies the creation of a subnet without a Network Security Group to protect traffic across subnets." + }, + "definitionEntry": { + "policyName": "Deny-Subnet-Without-Nsg", + "friendlyNameToDocumentIfGuid": "Deny Subnet without NSG" + } + } + ] + }, + { + "nodeName": "Compute/", + "children": [ + { + "nodeName": "Backup", + "assignment": { + "name": "Deploy-VM-Backup", + "displayName": "Configure backup on virtual machines without a given tag to a new recovery services vault with a default policy", + "description": "Enforce backup for all virtual machines by deploying a recovery services vault in the same location and resource group as the virtual machine. Doing this is useful when different application teams in your organization are allocated separate resource groups and need to manage their own backups and restores. You can optionally exclude virtual machines containing a specified tag to control the scope of assignment. See https://aka.ms/AzureVMAppCentricBackupExcludeTag." + }, + "definitionEntry": { + "policyName": "98d0b9f8-fd90-49c9-88e2-d3baf3b0dd86", + "friendlyNameToDocumentIfGuid": "Deploy VM Backup" + }, + "parameters": { + "exclusionTagName": "Backup", + "exclusionTagValue": [ + "False" + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-LandingZonesMG.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-LandingZonesMG.json new file mode 100644 index 00000000..c643742e --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-LandingZonesMG.json @@ -0,0 +1,190 @@ +{ + "nodeName": "/LandingZones/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/landingzones" + ] + }, + "children": [ + { + "nodeName": "AKS/", + "children": [ + { + "nodeName": "PrivilegeEscalation", + "assignment": { + "name": "Deny-Priv-Esc-AKS", + "displayName": "Kubernetes clusters should not allow container privilege escalation", + "description": "Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." + }, + "definitionEntry": { + "policyName": "1c6e92c9-99f0-4e55-9cf2-0c234dc48f99", + "friendlyNameToDocumentIfGuid": "AKS Privilege Escalation" + } + }, + { + "nodeName": "PrivilegeEscalation", + "assignment": { + "name": "Deny-Privileged-AKS", + "displayName": "Kubernetes cluster should not allow privileged containers", + "description": "Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." + }, + "definitionEntry": { + "policyName": "95edb821-ddaf-4404-9732-666045e056b4", + "friendlyNameToDocumentIfGuid": "AKS Privilege Containers" + } + }, + { + "nodeName": "Security", + "assignment": { + "name": "Enforce-AKS-HTTPS", + "displayName": "Kubernetes clusters should be accessible only over HTTPS", + "description": "Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for AKS Engine and Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc" + }, + "definitionEntry": { + "policyName": "1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d", + "friendlyNameToDocumentIfGuid": "AKS HTTPS Access" + } + }, + { + "nodeName": "Security", + "assignment": { + "name": "Deploy-AKS-Policy", + "displayName": "Deploy Azure Policy Add-on to Azure Kubernetes Service clusters", + "description": "Use Azure Policy Add-on to manage and report on the compliance state of your Azure Kubernetes Service (AKS) clusters. For more information, see https://aka.ms/akspolicydoc." + }, + "definitionEntry": { + "policyName": "a8eff44f-8c92-45c3-a3fb-9880802d67a7", + "friendlyNameToDocumentIfGuid": "Deploy AKS Policy" + } + } + ] + }, + { + "nodeName": "Networking/", + "children": [ + { + "nodeName": "IPForwarding", + "assignment": { + "name": "Deny-IP-forwarding", + "displayName": "Network interfaces should disable IP forwarding", + "description": "This policy denies the network interfaces which enabled IP forwarding. The setting of IP forwarding disables Azure's check of the source and destination for a network interface. This should be reviewed by the network security team." + }, + "definitionEntry": { + "policyName": "88c0b9da-ce96-4b03-9635-f29a937e2900", + "friendlyNameToDocumentIfGuid": "Deny IP Forwarding" + } + }, + { + "nodeName": "NoNSG", + "assignment": { + "name": "Deny-Subnet-Without-Nsg", + "displayName": "Subnets should have a Network Security Group", + "description": "This policy denies the creation of a subnet without a Network Security Group to protect traffic across subnets." + }, + "definitionEntry": { + "policyName": "Deny-Subnet-Without-Nsg", + "friendlyNameToDocumentIfGuid": "Deny Subnet without NSG" + } + }, + { + "nodeName": "NoRDP", + "assignment": { + "name": "Deny-RDP-From-Internet", + "displayName": "RDP access from the Internet should be blocked", + "description": "This policy denies any network security rule that allows RDP access from Internet." + }, + "definitionEntry": { + "policyName": "Deny-RDP-From-Internet", + "friendlyNameToDocumentIfGuid": "Deny RDP from Internet" + } + } + ] + }, + { + "nodeName": "Storage/", + "children": [ + { + "nodeName": "NoHTTP", + "assignment": { + "name": "Deny-Storage-http", + "displayName": "Secure transfer to storage accounts should be enabled", + "description": "Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking" + }, + "definitionEntry": { + "policyName": "404c3081-a854-4457-ae30-26a93ef643f9", + "friendlyNameToDocumentIfGuid": "Deny Storage HTTP" + } + } + ] + }, + { + "nodeName": "SQL/", + "children": [ + { + "nodeName": "Auditing", + "assignment": { + "name": "Deploy-SQL-DB-Auditing", + "displayName": "Auditing on SQL server should be enabled", + "description": "Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log." + }, + "definitionEntry": { + "policyName": "a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9", + "friendlyNameToDocumentIfGuid": "Deploy SQL DB Auditing" + } + } + ] + }, + { + "nodeName": "Compute/", + "children": [ + { + "nodeName": "Backup", + "assignment": { + "name": "Deploy-VM-Backup-LZ", + "displayName": "Configure backup on virtual machines without a given tag to a new recovery services vault with a default policy", + "description": "Enforce backup for all virtual machines by deploying a recovery services vault in the same location and resource group as the virtual machine. Doing this is useful when different application teams in your organization are allocated separate resource groups and need to manage their own backups and restores. You can optionally exclude virtual machines containing a specified tag to control the scope of assignment. See https://aka.ms/AzureVMAppCentricBackupExcludeTag." + }, + "definitionEntry": { + "policyName": "98d0b9f8-fd90-49c9-88e2-d3baf3b0dd86", + "friendlyNameToDocumentIfGuid": "Deploy VM Backup" + }, + "parameters": { + "exclusionTagName": "Backup", + "exclusionTagValue": [ + "False" + ] + } + } + ] + }, + { + "nodeName": "Security/", + "children": [ + { + "nodeName": "TLS", + "assignment": { + "name": "Enforce-TLS-SSL", + "displayName": "Deny or Deploy and append TLS requirements and SSL enforcement on resources without Encryption in transit", + "description": "Choose either Deploy if not exist and append in combination with audit or Select Deny in the Policy effect. Deny polices shift left. Deploy if not exist and append enforce but can be changed, and because missing exsistense condition require then the combination of Audit." + }, + "definitionEntry": { + "initiativeName": "Enforce-EncryptTransit", + "friendlyNameToDocumentIfGuid": "Enforce Encrypt Transit" + } + }, + { + "nodeName": "SQLThreat", + "assignment": { + "name": "Deploy-SQL-Threat", + "displayName": "Deploy Threat Detection on SQL servers", + "description": "This policy ensures that Threat Detection is enabled on SQL Servers." + }, + "definitionEntry": { + "policyName": "36d49e87-48c4-4f2e-beed-ba4ed02b71f5", + "friendlyNameToDocumentIfGuid": "Deploy SQL Threat Detection" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-ManagementMG-Default.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-ManagementMG-Default.json new file mode 100644 index 00000000..96629128 --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-ManagementMG-Default.json @@ -0,0 +1,34 @@ +{ + "nodeName": "/Management/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/management" + ] + }, + "parameters": { + "logAnalytics": "" + }, + "children": [ + { + "nodeName": "Logging/", + "children": [ + { + "nodeName": "ActivityLogs", + "assignment": { + "name": "Deploy-AzActivity-Log-MG", + "displayName": "Configure Azure Activity logs to stream to specified Log Analytics workspace", + "description": "Deploys the diagnostic settings for Azure Activity to stream subscriptions audit logs to a Log Analytics workspace to monitor subscription-level events" + }, + "definitionEntry": { + "policyName": "2465583e-4e78-4c15-b6be-a36cbc7c8b0f", + "friendlyNameToDocumentIfGuid": "Activity Logs" + }, + "parameters": { + "effect": "DeployIfNotExists", + "logsEnabled": "True" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/Assignments/CAF-RootMG-Default.json b/Scripts/CloudAdoptionFramework/Assignments/CAF-RootMG-Default.json new file mode 100644 index 00000000..82129a7f --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Assignments/CAF-RootMG-Default.json @@ -0,0 +1,175 @@ +{ + "nodeName": "/Root/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/toplevelmanagementgroup" + ] + }, + "parameters": { + "logAnalytics": "", + "logAnalytics_1": "", + "emailSecurityContact": "", + "ascExportResourceGroupName": "", + "ascExportResourceGroupLocation": "" + }, + "children": [ + { + "nodeName": "Security/", + "children": [ + { + "nodeName": "ASB", + "assignment": { + "name": "Deploy-ASC-Monitoring", + "displayName": "Azure Security Benchmark", + "description": "Azure Security Benchmark policy initiative" + }, + "definitionEntry": { + "initiativeName": "1f3afdf9-d0c9-4c3d-847f-89da613e70a8", + "friendlyNameToDocumentIfGuid": "Azure Security Benchmark" + }, + "parameters": { + "aadAuthenticationInSqlServerMonitoringEffect": "Disabled", + "diskEncryptionMonitoringEffect": "Disabled", + "encryptionOfAutomationAccountMonitoringEffect": "Disabled", + "identityDesignateLessThanOwnersMonitoringEffect": "Disabled", + "identityDesignateMoreThanOneOwnerMonitoringEffect": "Disabled", + "identityEnableMFAForWritePermissionsMonitoringEffect": "Disabled", + "identityRemoveDeprecatedAccountMonitoringEffect": "Disabled", + "identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect": "Disabled", + "identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect": "Disabled", + "identityRemoveExternalAccountWithReadPermissionsMonitoringEffect": "Disabled", + "identityRemoveExternalAccountWithWritePermissionsMonitoringEffect": "Disabled", + "jitNetworkAccessMonitoringEffect": "Disabled", + "networkSecurityGroupsOnSubnetsMonitoringEffect": "AuditIfNotExists", + "sqlDbEncryptionMonitoringEffect": "Disabled", + "sqlManagedInstanceAdvancedDataSecurityEmailAdminsMonitoringEffect": "Disabled", + "sqlManagedInstanceAdvancedDataSecurityEmailsMonitoringEffect": "Disabled", + "sqlServerAdvancedDataSecurityEmailAdminsMonitoringEffect": "Disabled", + "sqlServerAdvancedDataSecurityMonitoringEffect": "Disabled", + "systemUpdatesMonitoringEffect": "Disabled", + "vmssSystemUpdatesMonitoringEffect": "Disabled", + "windowsDefenderExploitGuardMonitoringEffect": "Disabled", + "useRbacRulesMonitoringEffect": "Disabled", + "useServicePrincipalToProtectSubscriptionsMonitoringEffect": "Disabled", + "identityEnableMFAForOwnerPermissionsMonitoringEffect": "Disabled", + "networkWatcherShouldBeEnabledMonitoringEffect": "Disabled", + "autoProvisioningOfTheLogAnalyticsAgentShouldBeEnabledOnYourSubscriptionMonitoringEffect": "Disabled" + } + }, + { + "nodeName": "MDFC", + "assignment": { + "name": "Deploy-MDFC-Config", + "displayName": "Deploy Microsoft Defender for Cloud configuration", + "description": "Deploy Microsoft Defender for Cloud and Security Contacts" + }, + "definitionEntry": { + "initiativeName": "Deploy-MDFC-Config", + "friendlyNameToDocumentIfGuid": "Microsoft Defender For Cloud" + }, + "parameters": { + "enableAscForServers": "DeployIfNotExists", + "enableAscForSql": "DeployIfNotExists", + "enableAscForAppServices": "DeployIfNotExists", + "enableAscForStorage": "DeployIfNotExists", + "enableAscForContainers": "DeployIfNotExists", + "enableAscForKeyVault": "DeployIfNotExists", + "enableAscForSqlOnVm": "DeployIfNotExists", + "enableAscForArm": "DeployIfNotExists", + "enableAscForDns": "DeployIfNotExists", + "enableAscForOssDb": "DeployIfNotExists" + } + } + ] + }, + { + "nodeName": "Logging/", + "children": [ + { + "nodeName": "ActivityLogs", + "assignment": { + "name": "Deploy-AzActivity-Log", + "displayName": "Deploy Diagnostic Settings for Activity Log to Log Analytics workspace", + "description": "Ensures that Activity Log Diagnostics settings are set to push logs into Log Analytics workspace." + }, + "definitionEntry": { + "policyName": "2465583e-4e78-4c15-b6be-a36cbc7c8b0f", + "friendlyNameToDocumentIfGuid": "Activity Logs" + }, + "parameters": { + "effect": "DeployIfNotExists", + "logsEnabled": "True" + } + }, + { + "nodeName": "ResourceDiagnostics", + "assignment": { + "name": "Deploy-Resource-Diag", + "displayName": "Deploy-Resource-Diag", + "description": "Ensures that Azure resources are configured to forward diagnostic logs and metrics to an Azure Log Analytics workspace." + }, + "definitionEntry": { + "policyName": "2465583e-4e78-4c15-b6be-a36cbc7c8b0f", + "friendlyNameToDocumentIfGuid": "Activity Logs" + }, + "parameters": { + "effect": "DeployIfNotExists" + } + }, + { + "nodeName": "VMMonitoring", + "assignment": { + "name": "Deploy-VM-Monitoring", + "displayName": "Enable Azure Monitor for VMs", + "description": "Enable Azure Monitor for the virtual machines (VMs) in the specified scope (management group, subscription or resource group). Takes Log Analytics workspace as parameter." + }, + "definitionEntry": { + "initiativeName": "55f3eceb-5573-4f18-9695-226972c6d74a", + "friendlyNameToDocumentIfGuid": "VM Monitoring" + } + }, + { + "nodeName": "VMSSMonitoring", + "assignment": { + "name": "Deploy-VMSS-Monitoring", + "displayName": "Enable Azure Monitor for Virtual Machine Scale Sets", + "description": "Enable Azure Monitor for the Virtual Machine Scale Sets in the specified scope (Management group, Subscription or resource group). Takes Log Analytics workspace as parameter. Note: if your scale set upgradePolicy is set to Manual, you need to apply the extension to the all VMs in the set by calling upgrade on them. In CLI this would be az vmss update-instances." + }, + "definitionEntry": { + "initiativeName": "75714362-cae7-409e-9b99-a8e5075b7fad", + "friendlyNameToDocumentIfGuid": "VMSS Monitoring" + } + } + ] + }, + { + "nodeName": "Compute", + "children": [ + { + "nodeName": "Arc-Linux-Monitoring", + "assignment": { + "name": "Deploy-LX-Arc-Monitoring", + "displayName": "Deploy-Linux-Arc-Monitoring", + "description": "Deploy-Linux-Arc-Monitoring" + }, + "definitionEntry": { + "policyName": "9d2b61b4-1d14-4a63-be30-d4498e7ad2cf", + "friendlyNameToDocumentIfGuid": "Arc Linux Monitoring" + } + }, + { + "nodeName": "Arc-Windows-Monitoring", + "assignment": { + "name": "Deploy-Arc-Monitoring", + "displayName": "Deploy-Windows-Arc-Monitoring", + "description": "Deploy-Windows-Arc-Monitoring" + }, + "definitionEntry": { + "policyName": "69af7d4a-7b18-4044-93a9-2651498ef203", + "friendlyNameToDocumentIfGuid": "Arc Windows Monitoring" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Scripts/CloudAdoptionFramework/README.md b/Scripts/CloudAdoptionFramework/README.md new file mode 100644 index 00000000..6edad846 --- /dev/null +++ b/Scripts/CloudAdoptionFramework/README.md @@ -0,0 +1,73 @@ +# Cloud Adoption Framework Policies + +## Table of Contents + +* Rationale +* Sync Script +* Update Assignment Scopes +* Update Parameters + +## Rationale + +Microsoft publishes and maintains a [list of policies, set definitions and assignments](https://github.com/Azure/Enterprise-Scale/blob/main/docs/ESLZ-Policies.md) which are deployed as part of the Cloud Adoption Framework Azure Landing Zones deployment. The central repository that contains these policies acts as the source of truth for ALZ deployments via the portal, Bicep and Terraform. A current list of policies which are deployed using these solutions is found at this link. + +To enable customers to use the Enterprise Policy as Code solution and combine Microsoft's policy recommendations there is a script which will pull the policies, initiatives and assignments from the central repository and allow you to deploy them using this solution. + +As the policies and assignments change in main repository the base files in this solution can be updated to match. + +## Sync Script + +The script located at ```Scripts\CloudAdoptionFramework\Sync-CAFPolicies.ps1``` will synchronise the policies from the upstream repository. You should ensure that you are keeping the main repository in sync with the project fork to ensure that any changes to this script are reflected accurately. + +### Usage + +``` +.\Scripts\CloudAdoptionFramework\Sync-CAFPolicies.ps1 [[-DefinitionsRootFolder] ] +``` + +Specifying the ```DefinitionsRootFolder``` parameter allows to you sync the policies to a different folder. This may be preferable when running yhe script periodically to sync in changes. + +## Update Assignment Scopes + +Each assignment file has a default scope assigned to it - this need to be updated to reflect your environment and ```global-settings.jsonc``` file. + +For example:- +``` +{ + "nodeName": "/Root/", + "scope": { + "tenant1": [ + "/providers/Microsoft.Management/managementGroups/toplevelmanagementgroup" + ] + }, + "parameters": { + "logAnalytics": "", + "logAnalytics_1": "", + "emailSecurityContact": "", + "ascExportResourceGroupName": "", + "ascExportResourceGroupLocation": "" + } +``` +If my top level management group had an ID of contoso I and my PAC environments specified a production environment I would need to update the block as below. +``` +{ + "nodeName": "/Root/", + "scope": { + "production": [ + "/providers/Microsoft.Management/managementGroups/contoso" + ] + }, + "parameters": { + "logAnalytics": "", + "logAnalytics_1": "", + "emailSecurityContact": "", + "ascExportResourceGroupName": "", + "ascExportResourceGroupLocation": "" + } +``` +Each assignment file corresponds to a management group deployed as part of the [CAF Azure Landing Zone](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-groups-in-the-azure-landing-zone-accelerator) management group structure. + +## Update Assignment Parameters + +Several of the assignment files also have parameters which need to be in place. Pay attention to the requirements about having a Log Analytics workspace deployed prior to assigning these policies as it is a requirement for several of the assignments. Less generic parameters are also available for modification in the assignment files. + diff --git a/Scripts/CloudAdoptionFramework/Sync-CAFPolicies.ps1 b/Scripts/CloudAdoptionFramework/Sync-CAFPolicies.ps1 new file mode 100644 index 00000000..2266a855 --- /dev/null +++ b/Scripts/CloudAdoptionFramework/Sync-CAFPolicies.ps1 @@ -0,0 +1,74 @@ +#Requires -PSEdition Core + +Param( + [Parameter(Mandatory = $false)] [string] $DefinitionsRootFolder +) + +if ($definitionsRootFolder -eq "") { + if ($null -eq $env:PAC_DEFINITIONS_FOLDER) { + $definitionsRootFolder = "$PSScriptRoot/../../Definitions" + } + else { + $definitionsRootFolder = $env:PAC_DEFINITIONS_FOLDER + } +} + +New-Item -Path "$definitionsRootFolder\Policies" -ItemType Directory -Force -ErrorAction SilentlyContinue +New-Item -Path "$definitionsRootFolder\policies\CAF" -ItemType Directory -Force -ErrorAction SilentlyContinue +New-Item -Path "$definitionsRootFolder\Initiatives" -ItemType Directory -Force -ErrorAction SilentlyContinue +New-Item -Path "$definitionsRootFolder\initiatives\CAF" -ItemType Directory -Force -ErrorAction SilentlyContinue +New-Item -Path "$definitionsRootFolder\Assignments" -ItemType Directory -Force -ErrorAction SilentlyContinue +New-Item -Path "$definitionsRootFolder\Assignments\CAF" -ItemType Directory -Force -ErrorAction SilentlyContinue + +. .\Scripts\Helpers\ConvertTo-HashTable.ps1 + +$defaultPolicyURIs = @( + 'https://raw.githubusercontent.com/Azure/Enterprise-Scale/main/eslzArm/managementGroupTemplates/policyDefinitions/policies.json' +) + +foreach ($policyUri in $defaultPolicyURIs) { + $rawContent = (Invoke-WebRequest -Uri $policyUri).Content | ConvertFrom-Json + $jsonPolicyDefsHash = $rawContent.variables | ConvertTo-HashTable + $jsonPolicyDefsHash.GetEnumerator() | Foreach-Object { + if ($_.Key -match 'fxv') { + $type = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Type + if ($type -eq 'Microsoft.Authorization/policyDefinitions') { + $name = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Name + $baseTemplate = @{ + name = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Name + properties = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Properties + } + $baseTemplate | ConvertTo-Json -Depth 50 | Out-File -FilePath $definitionsRootFolder\policies\CAF\$name.json -Force + (Get-Content $definitionsRootFolder\policies\CAF\$name.json) -replace "\[\[", "[" | Set-Content $definitionsRootFolder\policies\CAF\$name.json + } + if ($type -match 'Microsoft.Authorization/policySetDefinitions') { + $name = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Name + $baseTemplate = @{ + name = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Name + properties = $_.Value | ConvertFrom-Json | Select-Object -ExpandProperty Properties + } + $baseTemplate | ConvertTo-Json -Depth 50 | Out-File -FilePath $definitionsRootFolder\initiatives\CAF\$name.json -Force + (Get-Content $definitionsRootFolder\initiatives\CAF\$name.json) -replace "\[\[", "[" | Set-Content $definitionsRootFolder\initiatives\CAF\$name.json + (Get-Content $definitionsRootFolder\initiatives\CAF\$name.json) -replace "variables\('scope'\)", "'/providers/Microsoft.Management/managementGroups/$managementGroupId'" | Set-Content $definitionsRootFolder\initiatives\CAF\$name.json + (Get-Content $definitionsRootFolder\initiatives\CAF\$name.json) -replace "', '", "" | Set-Content $definitionsRootFolder\initiatives\CAF\$name.json + (Get-Content $definitionsRootFolder\initiatives\CAF\$name.json) -replace "\[concat\(('(.+)')\)\]", "`$2" | Set-Content $definitionsRootFolder\initiatives\CAF\$name.json + } + + } + } +} + +foreach ($initiativeFile in Get-ChildItem $definitionsRootFolder\Initiatives\CAF -Filter *.json) { + $rawContent = Get-Content $initiativeFile | ConvertFrom-Json -Depth 20 + $jsonContent = ConvertTo-HashTable $rawContent + $jsonContent.properties.policyDefinitions | Foreach-Object { + + $_ | Add-Member -Type NoteProperty -Name policyDefinitionName -Value $_.policyDefinitionId.Split("/")[-1] + $_.psObject.Properties.Remove('policyDefinitionId') + + } + $jsonContent | ConvertTo-Json -Depth 20 | Set-Content $initiativeFile +} + +Copy-Item -Path .\Scripts\CloudAdoptionFramework\Assignments\*.json -Destination "$definitionsRootFolder\assignments\CAF\" -Force +