From 1d413de5a53bb6af64142aa47bb70ccc8d2da196 Mon Sep 17 00:00:00 2001 From: magrande Date: Tue, 12 Apr 2022 19:49:14 -0300 Subject: [PATCH 01/17] subscription migration json-->bicep --- ...merManagedEncryptionPolicyAssignment.bicep | 11 + .../DenyAagWithoutWafPolicyAssignment.bicep | 14 + ...nyAksWithoutDefenderPolicyAssignment.bicep | 14 + ...DenyAksWithoutPolicyPolicyAssignment.bicep | 14 + .../DenyAksWithoutRbacPolicyAssignment.bicep | 14 + modules/DenyOldAksPolicyAssignment.bicep | 14 + modules/DenyPublicAksPolicyAssignment.bicep | 12 + .../EncryptionAtHostPolicyAssignment.bicep | 13 + ...licIPsForVMScaleSetsPolicyAssignment.bicep | 13 + .../allowedResourcespolicyAssignment.bicep | 41 + .../defenderPolicyAssignmentDeployment.bicep | 51 ++ modules/hubsPoliciesDeployment.bicep | 49 + .../networkWatchersPoliciesDeployment.bicep | 25 + modules/policyAssignmentDeploymentRG.bicep | 35 + modules/spokesPoliciesDeployment.bicep | 42 + modules/workloadPoliciesDeployment.bicep | 62 ++ subscription.bicep | 469 ++++++++++ subscription.json | 834 ------------------ 18 files changed, 893 insertions(+), 834 deletions(-) create mode 100644 modules/CustomerManagedEncryptionPolicyAssignment.bicep create mode 100644 modules/DenyAagWithoutWafPolicyAssignment.bicep create mode 100644 modules/DenyAksWithoutDefenderPolicyAssignment.bicep create mode 100644 modules/DenyAksWithoutPolicyPolicyAssignment.bicep create mode 100644 modules/DenyAksWithoutRbacPolicyAssignment.bicep create mode 100644 modules/DenyOldAksPolicyAssignment.bicep create mode 100644 modules/DenyPublicAksPolicyAssignment.bicep create mode 100644 modules/EncryptionAtHostPolicyAssignment.bicep create mode 100644 modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep create mode 100644 modules/allowedResourcespolicyAssignment.bicep create mode 100644 modules/defenderPolicyAssignmentDeployment.bicep create mode 100644 modules/hubsPoliciesDeployment.bicep create mode 100644 modules/networkWatchersPoliciesDeployment.bicep create mode 100644 modules/policyAssignmentDeploymentRG.bicep create mode 100644 modules/spokesPoliciesDeployment.bicep create mode 100644 modules/workloadPoliciesDeployment.bicep create mode 100644 subscription.bicep delete mode 100644 subscription.json diff --git a/modules/CustomerManagedEncryptionPolicyAssignment.bicep b/modules/CustomerManagedEncryptionPolicyAssignment.bicep new file mode 100644 index 00000000..2d0ac0f2 --- /dev/null +++ b/modules/CustomerManagedEncryptionPolicyAssignment.bicep @@ -0,0 +1,11 @@ +targetScope = 'resourceGroup' + +@description('\'Customer-Managed Disk Encryption\' applied to resource group - Policy Assignment.') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67', '2020-09-01').displayName}', 125)) + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67' + parameters: {} + } +} diff --git a/modules/DenyAagWithoutWafPolicyAssignment.bicep b/modules/DenyAagWithoutWafPolicyAssignment.bicep new file mode 100644 index 00000000..6917f195 --- /dev/null +++ b/modules/DenyAagWithoutWafPolicyAssignment.bicep @@ -0,0 +1,14 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Only allow Azure Application Gateway SKU with WAF support. - Policy assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(guid(subscription().id, 'DenyAagWithoutWaf'), resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyAagWithoutWaf')), '2020-09-01').displayName}', 125)) + description: 'Only allow Azure Application Gateway SKU with WAF support.' + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyAagWithoutWaf')) + parameters: {} + } +} diff --git a/modules/DenyAksWithoutDefenderPolicyAssignment.bicep b/modules/DenyAksWithoutDefenderPolicyAssignment.bicep new file mode 100644 index 00000000..5c54eb77 --- /dev/null +++ b/modules/DenyAksWithoutDefenderPolicyAssignment.bicep @@ -0,0 +1,14 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Microsoft Defender for Containers should be enabled in the cluster - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(guid(subscription().id, 'DenyNonDefenderAks'), resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyNonDefenderAks')), '2020-09-01').displayName}', 125)) + description: 'Microsoft Defender for Containers should be enabled in the cluster.' + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyNonDefenderAks')) + parameters: {} + } +} diff --git a/modules/DenyAksWithoutPolicyPolicyAssignment.bicep b/modules/DenyAksWithoutPolicyPolicyAssignment.bicep new file mode 100644 index 00000000..99fbc1be --- /dev/null +++ b/modules/DenyAksWithoutPolicyPolicyAssignment.bicep @@ -0,0 +1,14 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Only support AKS clusters with Azure Policy enabled, deny any other. - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d', '2020-09-01').displayName}', 125)) + description: 'Only support AKS clusters with Azure Policy enabled, deny any other.' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d' + parameters: {} + } +} diff --git a/modules/DenyAksWithoutRbacPolicyAssignment.bicep b/modules/DenyAksWithoutRbacPolicyAssignment.bicep new file mode 100644 index 00000000..230483ff --- /dev/null +++ b/modules/DenyAksWithoutRbacPolicyAssignment.bicep @@ -0,0 +1,14 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Only allow AKS with RBAC support enabled. - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457', '2020-09-01').displayName}', 125)) + description: 'Only allow AKS with RBAC support enabled.' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + parameters: {} + } +} diff --git a/modules/DenyOldAksPolicyAssignment.bicep b/modules/DenyOldAksPolicyAssignment.bicep new file mode 100644 index 00000000..90e14529 --- /dev/null +++ b/modules/DenyOldAksPolicyAssignment.bicep @@ -0,0 +1,14 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Disallow older AKS versions - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c', '2020-09-01').displayName}', 125)) + description: 'Disallow older AKS versions.' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c' + parameters: {} + } +} diff --git a/modules/DenyPublicAksPolicyAssignment.bicep b/modules/DenyPublicAksPolicyAssignment.bicep new file mode 100644 index 00000000..49521cf2 --- /dev/null +++ b/modules/DenyPublicAksPolicyAssignment.bicep @@ -0,0 +1,12 @@ +targetScope = 'resourceGroup' + +@description('Only support private AKS clusters, deny any other. - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(guid(subscription().id, 'DenyPublicAks'), resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyPublicAks')), '2020-09-01').displayName}', 125)) + description: 'Only support private AKS clusters, deny any other.' + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyPublicAks')) + parameters: {} + } +} diff --git a/modules/EncryptionAtHostPolicyAssignment.bicep b/modules/EncryptionAtHostPolicyAssignment.bicep new file mode 100644 index 00000000..914040cd --- /dev/null +++ b/modules/EncryptionAtHostPolicyAssignment.bicep @@ -0,0 +1,13 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('\'Encryption at Host\' policy applied to the resource group - Policy Assignment.') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c', '2020-09-01').displayName}', 125)) + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c' + parameters: {} + } +} diff --git a/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep b/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep new file mode 100644 index 00000000..0412a392 --- /dev/null +++ b/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep @@ -0,0 +1,13 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('\'No Public IPs on VMSS\' policy applied to the workload resource group. - Policy Assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(guid(subscription().id, 'NoPublicIPsForVMScaleSets'), resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'NoPublicIPsForVMScaleSets')), '2020-09-01').displayName}', 125)) + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'NoPublicIPsForVMScaleSets')) + parameters: {} + } +} diff --git a/modules/allowedResourcespolicyAssignment.bicep b/modules/allowedResourcespolicyAssignment.bicep new file mode 100644 index 00000000..02d46e21 --- /dev/null +++ b/modules/allowedResourcespolicyAssignment.bicep @@ -0,0 +1,41 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Only support the a list of resources for our workload resource group - Policy assignment') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) + properties: { + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + description: 'List of supported resources for our workload resource group' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' + parameters: { + listOfResourceTypesAllowed: { + value: [ + 'Microsoft.Compute/images' + 'Microsoft.Compute/virtualMachineScaleSets' + 'Microsoft.ContainerRegistry/registries' + 'Microsoft.ContainerRegistry/registries/agentPools' + 'Microsoft.ContainerRegistry/registries/replications' + 'Microsoft.ContainerService/managedClusters' + 'Microsoft.Insights/activityLogAlerts' + 'Microsoft.Insights/metricAlerts' + 'Microsoft.Insights/scheduledQueryRules' + 'Microsoft.Insights/workbooks' + 'Microsoft.KeyVault/vaults' + 'Microsoft.ManagedIdentity/userAssignedIdentities' + 'Microsoft.Network/applicationGateways' + 'Microsoft.Network/networkInterfaces' + 'Microsoft.Network/networkSecurityGroups' + 'Microsoft.Network/networkSecurityGroups/securityRules' + 'Microsoft.Network/privateDnsZones' + 'Microsoft.Network/privateDnsZones/virtualNetworkLinks' + 'Microsoft.Network/privateEndpoints' + 'Microsoft.OperationalInsights/workspaces' + 'Microsoft.OperationsManagement/solutions' + 'Microsoft.VirtualMachineImages/imageTemplates' + ] + } + } + } +} diff --git a/modules/defenderPolicyAssignmentDeployment.bicep b/modules/defenderPolicyAssignmentDeployment.bicep new file mode 100644 index 00000000..9dd9c39b --- /dev/null +++ b/modules/defenderPolicyAssignmentDeployment.bicep @@ -0,0 +1,51 @@ +targetScope = 'subscription' + +/*** PARAMETERS ***/ + +@description('The policy assignment enforcement mode.') +param enforcementMode string = 'Default' + +@description('Subsription deployment\'s main location (centralus if not specified)') +@allowed([ + 'australiaeast' + 'canadacentral' + 'centralus' + 'eastus' + 'eastus2' + 'westus2' + 'francecentral' + 'germanywestcentral' + 'northeurope' + 'southafricanorth' + 'southcentralus' + 'uksouth' + 'westeurope' + 'japaneast' + 'southeastasia' + ]) +param location string = 'centralus' + +@description('Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled. - Policy Assignment') +param enableDefenderPolicyDefinitionSetName string + +/*** RESOURCES ***/ + +@description('Assignment of policy') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(enableDefenderPolicyDefinitionSetName, subscription().id) + identity: { + type: 'SystemAssigned' + } + location: location + properties: { + displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', enableDefenderPolicyDefinitionSetName), '2020-09-01').displayName + description: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' + notScopes: [] + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', enableDefenderPolicyDefinitionSetName) + enforcementMode: enforcementMode + metadata: { + version: '1.0.0' + category: 'Microsoft Defender for Cloud' + } + } +} diff --git a/modules/hubsPoliciesDeployment.bicep b/modules/hubsPoliciesDeployment.bicep new file mode 100644 index 00000000..9e642011 --- /dev/null +++ b/modules/hubsPoliciesDeployment.bicep @@ -0,0 +1,49 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.') +module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { + name: 'Hubs-allowedResourcespolicyAssignment' + scope: resourceGroup() + params: { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + policyAssignmentDescription: 'List of supported resources for our enterprise hubs resource group' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' + parameters: { + listOfResourceTypesAllowed: { + value: [ + 'Microsoft.Insights/diagnosticSettings' + 'Microsoft.Insights/workbooks' + 'Microsoft.Network/azureFirewalls' + 'Microsoft.Network/bastionHosts' + 'Microsoft.Network/ipGroups' + 'Microsoft.Network/networkSecurityGroups' + 'Microsoft.Network/networkSecurityGroups/securityRules' + 'Microsoft.Network/publicIpAddresses' + 'Microsoft.Network/virtualNetworkGateways' + 'Microsoft.Network/virtualNetworks' + 'Microsoft.Network/virtualNetworks/subnets' + 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings' + 'Microsoft.OperationalInsights/workspaces' + 'Microsoft.OperationsManagement/solutions' + 'Microsoft.Storage/storageAccounts' + ] + } + } + } +} + +@description('Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.') +module NetworkWatcherShouldBeEnabledPolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { + name: 'Hubs-NetworkWatcherShouldBeEnabledPolicyAssignment' + scope: resourceGroup() + params: { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', resourceGroup().name) + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', '2020-09-01').displayName}', 125)) + policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + parameters: {} + } +} diff --git a/modules/networkWatchersPoliciesDeployment.bicep b/modules/networkWatchersPoliciesDeployment.bicep new file mode 100644 index 00000000..79745eba --- /dev/null +++ b/modules/networkWatchersPoliciesDeployment.bicep @@ -0,0 +1,25 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Allowed Resources Policy applied to the network watchers resource group to only allow select networking resources.') +module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { + name: 'NetworkWatchers-allowedResourcespolicyAssignment' + scope: resourceGroup() + params: { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + policyAssignmentDescription: 'List of supported resources for our Network Watcher resource group' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' + enforcementMode: 'DoNotEnforce' + parameters: { + listOfResourceTypesAllowed: { + value: [ + 'Microsoft.Network/networkWatchers' + 'Microsoft.Network/networkWatchers/flowLogs' + ] + } + } + } +} + diff --git a/modules/policyAssignmentDeploymentRG.bicep b/modules/policyAssignmentDeploymentRG.bicep new file mode 100644 index 00000000..1873c59e --- /dev/null +++ b/modules/policyAssignmentDeploymentRG.bicep @@ -0,0 +1,35 @@ +targetScope = 'resourceGroup' + +/*** PARAMETERS ***/ + +@description('The definitionID of the policy to assign.') +param policyDefinitionId string + +@description('The name of the policy assignment.') +param name string + +@description('The policy assignment\'s display name.') +param displayName string + +@description('Object with parameters applied to the policy assignment. ') +param parameters object + +@description('Policy assignment\'s description') +param policyAssignmentDescription string = '' + +@description('Provides the ability to test the outcome of a policy on existing resources without initiating the policy effect') +param enforcementMode string = 'Default' + +/*** RESOURCES ***/ + +@description('Assignment of policy') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: name + properties: { + displayName: displayName + description: policyAssignmentDescription + enforcementMode: enforcementMode + policyDefinitionId: policyDefinitionId + parameters: parameters + } +} diff --git a/modules/spokesPoliciesDeployment.bicep b/modules/spokesPoliciesDeployment.bicep new file mode 100644 index 00000000..c0164aa7 --- /dev/null +++ b/modules/spokesPoliciesDeployment.bicep @@ -0,0 +1,42 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Allowed Resources Policy applied to the spokes RG to only allow select networking and observation resources.') +module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { + name: 'Spokes-allowedResourcespolicyAssignment' + scope: resourceGroup() + params: { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + policyAssignmentDescription: 'List of supported resources for our enterprise spokes resource group' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' + parameters: { + listOfResourceTypesAllowed: { + value: [ + 'Microsoft.Network/networkSecurityGroups' + 'Microsoft.Network/privateDnsZones' + 'Microsoft.Network/privateDnsZones/virtualNetworkLinks' + 'Microsoft.Network/publicIpAddresses' + 'Microsoft.Network/routeTables' + 'Microsoft.Network/virtualNetworks' + 'Microsoft.Network/virtualNetworks/subnets' + 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings' + ] + } + } + } +} + +@description('Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.') +module NetworkWatcherShouldBeEnabledPolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { + name: 'Spokes-NetworkWatcherShouldBeEnabledPolicyAssignment' + scope: resourceGroup() + params: { + name: guid('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', resourceGroup().name) + displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', '2020-09-01').displayName}', 125)) + policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Spoke resource group.' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + parameters: {} + } +} diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep new file mode 100644 index 00000000..11a70aac --- /dev/null +++ b/modules/workloadPoliciesDeployment.bicep @@ -0,0 +1,62 @@ +targetScope = 'resourceGroup' + +/*** RESOURCES ***/ + +@description('Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.') +module allowedResourcespolicyAssignment 'allowedResourcespolicyAssignment.bicep' = { + name: 'Hubs-allowedResourcespolicyAssignment' + scope: resourceGroup() +} + +module DenyPublicAksPolicyAssignment 'DenyPublicAksPolicyAssignment.bicep' = { + name: 'Workload-DenyPublicAksPolicyAssignment' + scope: resourceGroup() +} + +@description('Deny the creation of Azure Kubernetes Service cluster that is not protected with Microsoft Defender for Containers.') +module DenyAksWithoutDefenderPolicyAssignment 'DenyAksWithoutDefenderPolicyAssignment.bicep' = { + name: 'Workload-DenyAksWithoutDefenderPolicyAssignment' + scope: resourceGroup() +} + +@description('Applying the \'No Public IPs on VMSS\' policy to the appliction resource group.') +module NoPublicIPsForVMScaleSetsPolicyAssignment 'NoPublicIPsForVMScaleSetsPolicyAssignment.bicep' = { + name: 'Workload-NoPublicIPsForVMScaleSetsPolicyAssignment' + scope: resourceGroup() +} + +@description('Deny AKS clusters that do not have Azure Policy enabled in the appliction resource group.') +module DenyAksWithoutPolicyPolicyAssignment 'DenyAksWithoutPolicyPolicyAssignment.bicep' = { + name: 'Workload-DenyAksWithoutPolicyPolicyAssignment' + scope: resourceGroup() +} + +@description('Deny public AKS clusters policy applied to the appliction resource group.') +module DenyAagWithoutWafPolicyAssignment 'DenyAagWithoutWafPolicyAssignment.bicep' = { + name: 'Workload-DenyAagWithoutWafPolicyAssignment' + scope: resourceGroup() +} + +@description('Deny AKS clusters without RBAC policy applied to the appliction resource group.') +module DenyAksWithoutRbacPolicyAssignment 'DenyAksWithoutRbacPolicyAssignment.bicep' = { + name: 'Workload-DenyAksWithoutRbacPolicyAssignment' + scope: resourceGroup() +} + +@description('Deny AKS clusters on old version policy applied to the appliction resource group.') +module DenyOldAksPolicyAssignment 'DenyOldAksPolicyAssignment.bicep' = { + name: 'Workload-DenyOldAksPolicyAssignment' + scope: resourceGroup() +} + +@description('Applying the \'Customer-Managed Disk Encryption\' policy to the resource group.') +module CustomerManagedEncryptionPolicyAssignment 'CustomerManagedEncryptionPolicyAssignment.bicep' = { + name: 'Workload-CustomerManagedEncryptionPolicyAssignment' + scope: resourceGroup() +} + +@description('Applying the \'Encryption at Host\' policy to the resource group.') +module EncryptionAtHostPolicyAssignment 'EncryptionAtHostPolicyAssignment.bicep' = { + name: 'Workload-EncryptionAtHostPolicyAssignment' + scope: resourceGroup() +} diff --git a/subscription.bicep b/subscription.bicep new file mode 100644 index 00000000..b76a5ec9 --- /dev/null +++ b/subscription.bicep @@ -0,0 +1,469 @@ +targetScope = 'subscription' + +/*** PARAMETERS ***/ + +@description('By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are configured to deploy via Azure Policy, use this parameter to disable that.') +param enforceAzureDefenderAutoDeployPolicies bool = true + +@description('By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are enabled; use this parameter to prevent them from being enabled. Deploying these requires subscription Owner or Security Admin roles.') +param enableAzureDefender bool = true + +@description('networkWatcherRG often times already exists in a subscription. Empty string will result in using the default resource location.') +param networkWatcherRGRegion string = '' + +@description('Subsription deployment\'s main location (centralus if not specified)') +@allowed([ + 'australiaeast' + 'canadacentral' + 'centralus' + 'eastus' + 'eastus2' + 'westus2' + 'francecentral' + 'germanywestcentral' + 'northeurope' + 'southafricanorth' + 'southcentralus' + 'uksouth' + 'westeurope' + 'japaneast' + 'southeastasia' + ]) +param location string = 'centralus' + +/*** RESOURCES ***/ + +@description('This contains all of our regional hubs. Typically this would be found in your enterprise\'s Connectivity subscription.') +resource rgHubs 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'rg-enterprise-networking-hubs' + location: location +} + +@description('This contains all of our regional spokes. Typically this would be found in your enterprise\'s Connectivity subscription or in the workload\'s subscription.') +resource rgSpokes 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'rg-enterprise-networking-spokes' + location: location +} + +@description('This is the resource group for BU001A0005. Typically this would be found in your workload\'s subscription.') +resource rgbu0001a0005 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'rg-bu0001a0005' + location: location +} + +@description('This is the resource group for Azure Network Watchers. Most subscriptions already have this.') +resource rgNetworkWatchers 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'networkWatcherRG' + location: empty(networkWatcherRGRegion) ? 'centralus' : networkWatcherRGRegion +} + +@description('Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.') +resource pdEnableAksDefender 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'EnableDefenderForAks') + properties: { + displayName: 'Microsoft Defender for Containers is enabled' + policyType: 'Custom' + mode: 'All' + description: 'Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.' + metadata: { + version: '1.0.0' + category: 'Microsoft Defender for Cloud' + } + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Resources/subscriptions' + } + ] + } + then: { + effect: 'deployIfNotExists' + details: { + type: 'Microsoft.Security/pricings' + name: 'Containers' + deploymentScope: 'subscription' + existenceScope: 'subscription' + roleDefinitionIds: [ + '/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd' + ] + existenceCondition: { + field: 'Microsoft.Security/pricings/pricingTier' + equals: 'Standard' + } + deployment: { + location: location + properties: { + mode: 'incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [ + { + type: 'Microsoft.Security/pricings' + apiVersion: '2018-06-01' + name: 'Containers' + properties: { + pricingTier: 'Standard' + } + } + ] + } + } + } + } + } + } + } +} + +@description('Microsoft Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.') +resource pdEnableAkvDefender 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'EnableDefenderForAkv') + properties: { + displayName: 'Microsoft Defender for Key Vault is enabled' + policyType: 'Custom' + mode: 'All' + description: 'Microsoft Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.' + metadata: { + version: '1.0.0' + category: 'Microsoft Defender for Cloud' + } + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Resources/subscriptions' + } + ] + } + then: { + effect: 'deployIfNotExists' + details: { + type: 'Microsoft.Security/pricings' + name: 'KeyVaults' + deploymentScope: 'subscription' + existenceScope: 'subscription' + roleDefinitionIds: [ + '/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd' + ] + existenceCondition: { + field: 'Microsoft.Security/pricings/pricingTier' + equals: 'Standard' + } + deployment: { + location: location + properties: { + mode: 'incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [ + { + type: 'Microsoft.Security/pricings' + apiVersion: '2018-06-01' + name: 'KeyVaults' + properties: { + pricingTier: 'Standard' + } + } + ] + } + } + } + } + } + } + } +} + +@description('Ensures Microsoft Defender is enabled for select resources.') +resource psdEnableDefender 'Microsoft.Authorization/policySetDefinitions@2021-06-01' = { + name: guid(subscription().id, 'EnableDefender') + properties: { + displayName: 'Enable Microsoft Defender Standard' + description: 'Ensures Microsoft Defender is enabled for select resources' + policyType: 'Custom' + metadata: { + version: '1.0.0' + category: 'Microsoft Defender for Cloud' + } + policyDefinitions: [ + { + policyDefinitionId: pdEnableAksDefender.id + } + { + policyDefinitionId: pdEnableAkvDefender.id + } + ] + } +} + +@description('Microsoft Defender for Containers should be enabled in the cluster.') +resource pdDenyAksWithoutDefender 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'DenyNonDefenderAks') + properties: { + description: 'This policy denies the creation of Azure Kubernetes Service cluster that is not protected with Microsoft Defender for Containers.' + displayName: 'Microsoft Defender for Containers should be enabled in the cluster.' + policyType: 'Custom' + mode: 'All' + metadata: { + version: '1.0.0' + } + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.ContainerService/managedClusters' + } + { + field: 'Microsoft.ContainerService/managedClusters/securityProfile.azureDefender.enabled' + notequals: 'true' + } + ] + } + then: { + effect: 'deny' + } + } + } +} + +@description('This policy denies the creation of Azure Kubernetes Service non-private clusters.') +resource pdDenyPublicAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'DenyPublicAks') + properties: { + description: 'This policy denies the creation of Azure Kubernetes Service non-private clusters' + displayName: 'Public network access on AKS API should be disabled' + policyType: 'Custom' + mode: 'All' + metadata: { + version: '1.0.0' + } + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.ContainerService/managedClusters' + } + { + field: 'Microsoft.ContainerService/managedClusters/apiServerAccessProfile.enablePrivateCluster' + notequals: 'true' + } + ] + } + then: { + effect: 'Deny' + } + } + } +} + +@description('This policy denies the creation of Azure Application Gateway without WAF feature.') +resource pdDenyAagWithoutWaf 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'DenyAagWithoutWaf') + properties: { + description: 'This policy denies the creation of Azure Application Gateway without WAF feature' + displayName: 'WAF SKU must be enabled on Azure Application Gateway' + policyType: 'Custom' + mode: 'All' + metadata: { + version: '1.0.0' + } + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Network/applicationGateways' + } + { + field: 'Microsoft.Network/applicationGateways/sku.name' + notequals: 'WAF_v2' + } + ] + } + then: { + effect: 'Deny' + } + } + } +} + +@description('This policy denies network interfaces with public IPs to be attached to the identified Virtual Network. Applied at the subscription level, but expected to be limited to a specific vnet.') +resource pdNoPublicIPsForNICsInVnet 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'NoPublicIPsForNICsInVnet') + properties: { + displayName: 'Virtual Network should not have NICs attached with public IPs' + description: 'This policy denies network interfaces with public IPs to be attached to the identified Virtual Network. Applied at the subscription level, but expected to be limited to a specific vnet.' + policyType: 'Custom' + mode: 'All' + metadata: { + version: '1.0.0' + category: 'Network' + } + parameters: { + vnetResourceId: { + type: 'String' + metadata: { + displayName: 'Virtual Network' + description: 'The Vnet Resource ID that cannot have public IPs' + strongType: 'Microsoft.Network/virtualNetworks' + } + } + } + policyRule: { + if: { + anyOf: [ + { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Network/networkInterfaces' + } + { + field: 'Microsoft.Network/networkInterfaces/ipConfigurations[*].publicIpAddress.id' + like: '*' + } + { + field: 'Microsoft.Network/networkInterfaces/ipConfigurations[*].subnet.id' + contains: '[parameters(\'vnetResourceId\')]' + } + ] + } + { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Compute/virtualMachineScaleSets' + } + { + field: 'Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].publicIPAddressConfiguration.name' + like: '*' + } + { + field: 'Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].subnet.id' + contains: '[parameters(\'vnetResourceId\')]' + } + ] + } + ] + } + then: { + effect: 'deny' + } + } + } +} + +@description('This policy denies the creation VM Scale Sets which are are configured with any public IPs.') +resource pdNoPublicIPsForVMScaleSets 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { + name: guid(subscription().id, 'NoPublicIPsForVMScaleSets') + properties: { + displayName: 'VM Scale Sets should not have public IPs' + description: 'This policy denies the creation VM Scale Sets which are are configured with any public IPs.' + policyType: 'Custom' + mode: 'All' + metadata: { + version: '1.0.0' + category: 'Compute' + } + parameters: {} + policyRule: { + if: { + allOf: [ + { + field: 'type' + equals: 'Microsoft.Compute/virtualMachineScaleSets' + } + { + field: 'Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].publicIPAddressConfiguration.name' + like: '*' + } + ] + } + then: { + effect: 'deny' + } + } + } +} + +@description('Hubs policies deployment') +module hubsPoliciesDeployment 'modules/hubsPoliciesDeployment.bicep' = { + name: 'Apply-${rgHubs.name}-Policies' + scope: rgHubs +} + +@description('Spokes policies deployment') +module spokesPoliciesDeployment 'modules/spokesPoliciesDeployment.bicep' = { + name: 'Apply-${rgSpokes.name}-Policies' + scope: rgSpokes +} + +@description('Network watcher\'s policies deployment') +module networkWatchersPoliciesDeployment 'modules/networkWatchersPoliciesDeployment.bicep' = { + name: 'Apply-${rgNetworkWatchers.name}-Policies' + scope: rgNetworkWatchers +} + +@description('Workload\'s policies deployment') +module workloadPoliciesDeployment 'modules/workloadPoliciesDeployment.bicep' = { + name: 'Apply-${rgbu0001a0005.name}-Policies' + scope: rgbu0001a0005 +} + +@description('Enable policy that ensures various Microsoft Defender services are enabled.') +module defenderPolicyDeployment 'modules/defenderPolicyAssignmentDeployment.bicep' = { + name: 'Apply-EnableDefender-Policy' + scope: subscription() + params: { + location: location + enableDefenderPolicyDefinitionSetName: psdEnableDefender.name + enforcementMode: enforceAzureDefenderAutoDeployPolicies ? 'Default' : 'DoNotEnforce' + } +} + +@description('Enable Microsoft Defender Standard for Key Vault. Requires Owner or Security Admin role.') +resource enableKeyVaultspricing 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { + name: 'KeyVaults' + properties: { + pricingTier: 'Standard' + } +} + +@description('Enable Microsoft Defender Standard for Container Registry. Requires Owner or Security Admin role.') +resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { + name: 'ContainerRegistry' + properties: { + pricingTier: 'Standard' + } +} + +@description('Enable Microsoft Defender Standard for Kubernetes Service. Requires Owner or Security Admin role.') +resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { + name: 'KubernetesService' + properties: { + pricingTier: 'Standard' + } +} + +@description('Enable Microsoft Defender Standard for Azure Resource Manager. Requires Owner or Security Admin role.') +resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { + name: 'Arm' + properties: { + pricingTier: 'Standard' + } +} + +@description('Enable Microsoft Defender Standard for Azure DNS. Requires Owner or Security Admin role.') +resource enableDns 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { + name: 'Dns' + properties: { + pricingTier: 'Standard' + } +} diff --git a/subscription.json b/subscription.json deleted file mode 100644 index 1a2d38e8..00000000 --- a/subscription.json +++ /dev/null @@ -1,834 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - /* Required Permissions - - Scope: Subscription - Role: Contributor - Reason: Creating resource groups, azure policy definations and assignments - - Optional Permissions - - Scope: Subscription - Role: Security Admin (or Owner) - Reason: To enable Microsoft Defender for Kubernetes, Container Registry, and Key Vault. - Notes: If unable to obtain permissions, you must pass false to the enableAzureDefender parameter or have someone else enable these for you. - */ - "parameters": { - "enforceAzureDefenderAutoDeployPolicies": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are configured to deploy via Azure Policy, use this parameter to disable that." - } - }, - "enableAzureDefender": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are enabled; use this parameter to prevent them from being enabled. Deploying these requires subscription Owner or Security Admin roles." - } - }, - "networkWatcherRGRegion": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "networkWatcherRG often times already exists in a subscription. Empty string will result in using the default resource location." - } - } - }, - "variables": { - "rgName-Hubs": "rg-enterprise-networking-hubs", - "rgName-Spokes": "rg-enterprise-networking-spokes", - "rgName-NetworkWatchers": "networkWatcherRG", - "rgName-bu0001A0005": "rg-bu0001a0005", - "policyDefinitionId-AllowedResources": "/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c", - "policyDefinitionId-DenyAksWithoutPolicy": "/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d", - "policyDefinitionId-DenyAksWithoutRbac": "/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457", - "policyDefinitionId-DenyOldAks": "/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c", - "policyDefinitionId-CustomerManagedEncryption": "/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67", - "policyDefinitionId-EncryptionAtHost": "/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c", - "policyDefinitionId-NetworkWatcherShouldBeEnabled": "/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6", - - "policyDefinitionName-EnableAksDefender": "[guid(subscription().id, 'EnableDefenderForAks')]", - "policyDefinitionName-EnableAkvDefender": "[guid(subscription().id, 'EnableDefenderForAkv')]", - "policyDefinitionName-DenyAksWithoutDefender": "[guid(subscription().id, 'DenyNonDefenderAks')]", - "policyDefinitionName-DenyPublicAks": "[guid(subscription().id, 'DenyPublicAks')]", - "policyDefinitionName-DenyAksWithoutPolicy": "[guid(subscription().id, 'DenyAksWithoutPolicy')]", - "policyDefinitionName-DenyAagWithoutWaf": "[guid(subscription().id, 'DenyAagWithoutWaf')]", - "policyDefinitionName-DenyAksWithoutRbac": "[guid(subscription().id, 'DenyAksWithoutRbac')]", - "policyDefinitionName-DenyOldAks": "[guid(subscription().id, 'DenyOldAksVersions')]", - "policyDefinitionName-CustomerManagedEncryption": "[guid(subscription().id, 'CustomerManagedEncryption')]", - "policyDefinitionName-EncryptionAtHost": "[guid(subscription().id, 'EncryptionAtHost')]", - "policyDefinitionName-NoPublicIPsForNICsInVnet": "[guid(subscription().id, 'NoPublicIPsForNICsInVnet')]", - "policyDefinitionName-NoPublicIPsForVMScaleSets": "[guid(subscription().id, 'NoPublicIPsForVMScaleSets')]", - - "policySetDefinitionName-EnableDefender": "[guid(subscription().id, 'EnableDefender')]", - "roleId-SecurityAdmin": "/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd", - "deploymentResourceRegion": "centralus" // This region is used as the default for all generic resource groups and for any additional deployment resources. No resources are actually deployed to this resource group. - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2020-10-01", - "name": "[variables('rgName-Hubs')]", - "location": "[variables('deploymentResourceRegion')]", - "comments": "This contains all of our regional hubs. Typically this would be found in your enterprise's Connectivity subscription." - }, - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2020-10-01", - "name": "[variables('rgName-Spokes')]", - "location": "[variables('deploymentResourceRegion')]", - "comments": "This contains all of our regional spokes. Typically this would be found in your enterprise's Connectivity subscription or in the workload's subscription." - }, - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2020-10-01", - "name": "[variables('rgName-bu0001A0005')]", - "location": "[variables('deploymentResourceRegion')]", - "comments": "This is the resource group for BU001A0005. Typically this would be found in your workload's subscription." - }, - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2020-10-01", - "name": "[variables('rgName-NetworkWatchers')]", - "location": "[if(empty(parameters('networkWatcherRGRegion')), variables('deploymentResourceRegion'), parameters('networkWatcherRGRegion'))]", - "comments": "This is the resource group for Azure Network Watchers. Most subscriptions already have this." - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-EnableAksDefender')]", - "properties": { - "displayName": "Microsoft Defender for Containers is enabled", - "policyType": "Custom", - "mode": "All", - "description": "Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.", - "metadata": { - "version": "1.0.0", - "category": "Microsoft Defender for Cloud" - }, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Resources/subscriptions" - } - ] - }, - "then": { - "effect": "deployIfNotExists", - "details": { - "type": "Microsoft.Security/pricings", - "name": "Containers", - "deploymentScope": "subscription", - "existenceScope": "subscription", - "roleDefinitionIds": [ - "[variables('roleId-SecurityAdmin')]" - ], - "existenceCondition": { - "field": "Microsoft.Security/pricings/pricingTier", - "equals": "Standard" - }, - "deployment": { - "location": "[variables('deploymentResourceRegion')]", - "properties": { - "mode": "incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "Containers", - "properties": { - "pricingTier": "Standard" - } - } - ] - } - } - } - } - } - } - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-EnableAkvDefender')]", - "properties": { - "displayName": "Microsoft Defender for Key Vault is enabled", - "policyType": "Custom", - "mode": "All", - "description": "Microsoft Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts.", - "metadata": { - "version": "1.0.0", - "category": "Microsoft Defender for Cloud" - }, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Resources/subscriptions" - } - ] - }, - "then": { - "effect": "deployIfNotExists", - "details": { - "type": "Microsoft.Security/pricings", - "name": "KeyVaults", - "deploymentScope": "subscription", - "existenceScope": "subscription", - "roleDefinitionIds": [ - "[variables('roleId-SecurityAdmin')]" - ], - "existenceCondition": { - "field": "Microsoft.Security/pricings/pricingTier", - "equals": "Standard" - }, - "deployment": { - "location": "[variables('deploymentResourceRegion')]", - "properties": { - "mode": "incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "KeyVaults", - "properties": { - "pricingTier": "Standard" - } - } - ] - } - } - } - } - } - } - } - }, - { - "type": "Microsoft.Authorization/policySetDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policySetDefinitionName-EnableDefender')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-EnableAksDefender'))]", - "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-EnableAkvDefender'))]" - ], - "properties": { - "displayName": "Enable Microsoft Defender Standard", - "description": "Ensures Microsoft Defender is enabled for select resources", - "policyType": "Custom", - "metadata": { - "version": "1.0.0", - "category": "Microsoft Defender for Cloud" - }, - "policyDefinitions": [ - { - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-EnableAksDefender'))]" - }, - { - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-EnableAkvDefender'))]" - } - ] - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-DenyAksWithoutDefender')]", - "properties": { - "description": "This policy denies the creation of Azure Kubernetes Service cluster that is not protected with Microsoft Defender for Containers.", - "displayName": "Microsoft Defender for Containers should be enabled in the cluster.", - "policyType": "Custom", - "mode": "All", - "metadata": { - "version": "1.0.0" - }, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.ContainerService/managedClusters" - }, - { - "field": "Microsoft.ContainerService/managedClusters/securityProfile.azureDefender.enabled", - "notequals": "true" - } - ] - }, - "then": { - "effect": "Deny" - } - } - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-DenyPublicAks')]", - "properties": { - "description": "This policy denies the creation of Azure Kubernetes Service non-private clusters", - "displayName": "Public network access on AKS API should be disabled", - "policyType": "Custom", - "mode": "All", - "metadata": { - "version": "1.0.0" - }, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.ContainerService/managedClusters" - }, - { - "field": "Microsoft.ContainerService/managedClusters/apiServerAccessProfile.enablePrivateCluster", - "notequals": "true" - } - ] - }, - "then": { - "effect": "Deny" - } - } - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-DenyAagWithoutWaf')]", - "properties": { - "description": "This policy denies the creation of Azure Application Gateway without WAF feature", - "displayName": "WAF SKU must be enabled on Azure Application Gateway", - "policyType": "Custom", - "mode": "All", - "metadata": { - "version": "1.0.0" - }, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Network/applicationGateways" - }, - { - "field": "Microsoft.Network/applicationGateways/sku.name", - "notequals": "WAF_v2" - } - ] - }, - "then": { - "effect": "Deny" - } - } - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-NoPublicIPsForNICsInVnet')]", - "properties": { - "displayName": "Virtual Network should not have NICs attached with public IPs", - "description": "This policy denies network interfaces with public IPs to be attached to the identified Virtual Network. Applied at the subscription level, but expected to be limited to a specific vnet.", - "policyType": "Custom", - "mode": "All", - "metadata": { - "version": "1.0.0", - "category": "Network" - }, - "parameters": { - "vnetResourceId": { - "type": "string", - "metadata": { - "displayName": "Virtual Network", - "description": "The Vnet Resource ID that cannot have public IPs", - "strongType": "Microsoft.Network/virtualNetworks" - } - } - }, - "policyRule": { - "if": { - "anyOf": [ - { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Network/networkInterfaces" - }, - { - "field": "Microsoft.Network/networkInterfaces/ipConfigurations[*].publicIpAddress.id", - "like": "*" - }, - { - "field": "Microsoft.Network/networkInterfaces/ipConfigurations[*].subnet.id", - "contains": "[[parameters('vnetResourceId')]" - } - ] - }, - { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Compute/virtualMachineScaleSets" - }, - { - "field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].publicIPAddressConfiguration.name", - "like": "*" - }, - { - "field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].subnet.id", - "contains": "[[parameters('vnetResourceId')]" - } - ] - } - ] - }, - "then": { - "effect": "deny" - } - } - } - }, - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2019-09-01", - "name": "[variables('policyDefinitionName-NoPublicIPsForVMScaleSets')]", - "properties": { - "displayName": "VM Scale Sets should not have public IPs", - "description": "This policy denies the creation VM Scale Sets which are are configured with any public IPs.", - "policyType": "Custom", - "mode": "All", - "metadata": { - "version": "1.0.0", - "category": "Compute" - }, - "parameters": {}, - "policyRule": { - "if": { - "allOf": [ - { - "field": "type", - "equals": "Microsoft.Compute/virtualMachineScaleSets" - }, - { - "field": "Microsoft.Compute/virtualMachineScaleSets/virtualMachineProfile.networkProfile.networkInterfaceConfigurations[*].ipConfigurations[*].publicIPAddressConfiguration.name", - "like": "*" - } - ] - }, - "then": { - "effect": "deny" - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "[concat('Apply-', variables('rgName-Hubs'), '-Policies')]", - "resourceGroup": "[variables('rgName-Hubs')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Hubs'))]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-AllowedResources'), variables('rgName-Hubs'))]", - "comments": "Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-Hubs'), '] ', reference(variables('policyDefinitionId-AllowedResources'), '2020-09-01').displayName), 125))]", - "description": "List of supported resources for our enterprise hubs resource group", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Hubs'))]", - "policyDefinitionId": "[variables('policyDefinitionId-AllowedResources')]", - "parameters": { - "listOfResourceTypesAllowed": { - "value": [ - "Microsoft.Insights/diagnosticSettings", - "Microsoft.Insights/workbooks", - "Microsoft.Network/azureFirewalls", - "Microsoft.Network/bastionHosts", - "Microsoft.Network/ipGroups", - "Microsoft.Network/networkSecurityGroups", - "Microsoft.Network/networkSecurityGroups/securityRules", - "Microsoft.Network/publicIpAddresses", - "Microsoft.Network/virtualNetworkGateways", - "Microsoft.Network/virtualNetworks", - "Microsoft.Network/virtualNetworks/subnets", - "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "Microsoft.OperationalInsights/workspaces", - "Microsoft.OperationsManagement/solutions", - "Microsoft.Storage/storageAccounts" - ] - } - } - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-NetworkWatcherShouldBeEnabled'), variables('rgName-Hubs'))]", - "comments": "Applying the 'Network Watcher Should be Enabled' policy to the Hub resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-Hubs'), '] ', reference(variables('policyDefinitionId-NetworkWatcherShouldBeEnabled'), '2020-09-01').displayName), 125))]", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Hubs'))]", - "policyDefinitionId": "[variables('policyDefinitionId-NetworkWatcherShouldBeEnabled')]" - } - } - ] - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "[concat('Apply-', variables('rgName-Spokes'), '-Policies')]", - "resourceGroup": "[variables('rgName-Spokes')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Spokes'))]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-AllowedResources'), variables('rgName-Spokes'))]", - "comments": "Allowed Resources Policy applied to the spoke resource group to only allow select networking resources.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-Spokes'), '] ', reference(variables('policyDefinitionId-AllowedResources'), '2020-09-01').displayName), 125))]", - "description": "List of supported resources for our enterprise spokes resource group", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Spokes'))]", - "policyDefinitionId": "[variables('policyDefinitionId-AllowedResources')]", - "parameters": { - "listOfResourceTypesAllowed": { - "value": [ - "Microsoft.Network/networkSecurityGroups", - "Microsoft.Network/privateDnsZones", - "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "Microsoft.Network/publicIpAddresses", - "Microsoft.Network/routeTables", - "Microsoft.Network/virtualNetworks", - "Microsoft.Network/virtualNetworks/subnets", - "Microsoft.Network/virtualNetworks/virtualNetworkPeerings" - ] - } - } - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-NetworkWatcherShouldBeEnabled'), variables('rgName-Spokes'))]", - "comments": "Applying the 'Network Watcher Should be Enabled' policy to the Spoke resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-Spokes'), '] ', reference(variables('policyDefinitionId-NetworkWatcherShouldBeEnabled'), '2020-09-01').displayName), 125))]", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-Spokes'))]", - "policyDefinitionId": "[variables('policyDefinitionId-NetworkWatcherShouldBeEnabled')]" - } - } - ] - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "[concat('Apply-', variables('rgName-NetworkWatchers'), '-Policies')]", - "resourceGroup": "[variables('rgName-NetworkWatchers')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-NetworkWatchers'))]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-AllowedResources'), variables('rgName-NetworkWatchers'))]", - "comments": "Allowed Resources Policy applied to the network watchers resource group to only allow select networking resources.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-NetworkWatchers'), '] ', reference(variables('policyDefinitionId-AllowedResources'), '2020-09-01').displayName), 125))]", - "description": "List of supported resources for our Network Watcher resource group", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-NetworkWatchers'))]", - "policyDefinitionId": "[variables('policyDefinitionId-AllowedResources')]", - "enforcementMode": "DoNotEnforce", // Since this RG may be under existing policy control in your subscription, adding this policy as audit-only. - "parameters": { - "listOfResourceTypesAllowed": { - "value": [ - "Microsoft.Network/networkWatchers", - "Microsoft.Network/networkWatchers/flowLogs" - ] - } - } - } - } - ] - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "[concat('Apply-', variables('rgName-bu0001A0005'), '-Policies')]", - "resourceGroup": "[variables('rgName-bu0001A0005')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyPublicAks'))]", - "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyAksWithoutDefender'))]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionId-AllowedResources'), variables('rgName-bu0001A0005'))]", - "comments": "Allowed Resources Policy applied to the appliction resource group to only allow select resources per workload requirements.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(variables('policyDefinitionId-AllowedResources'), '2020-09-01').displayName), 125))]", - "description": "List of supported resources for our workload resource group", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-AllowedResources')]", - "parameters": { - "listOfResourceTypesAllowed": { - "value": [ - "Microsoft.Compute/images", - "Microsoft.Compute/virtualMachineScaleSets", - "Microsoft.ContainerRegistry/registries", - "Microsoft.ContainerRegistry/registries/agentPools", - "Microsoft.ContainerRegistry/registries/replications", - "Microsoft.ContainerService/managedClusters", - "Microsoft.Insights/activityLogAlerts", - "Microsoft.Insights/metricAlerts", - "Microsoft.Insights/scheduledQueryRules", - "Microsoft.Insights/workbooks", - "Microsoft.KeyVault/vaults", - "Microsoft.ManagedIdentity/userAssignedIdentities", - "Microsoft.Network/applicationGateways", - "Microsoft.Network/networkInterfaces", - "Microsoft.Network/networkSecurityGroups", - "Microsoft.Network/networkSecurityGroups/securityRules", - "Microsoft.Network/privateDnsZones", - "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "Microsoft.Network/privateEndpoints", - "Microsoft.OperationalInsights/workspaces", - "Microsoft.OperationsManagement/solutions", - "Microsoft.VirtualMachineImages/imageTemplates" - ] - } - } - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyPublicAks'), variables('rgName-bu0001A0005'))]", - "comments": "Deny public AKS clusters policy applied to the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyPublicAks')), '2020-09-01').displayName), 125))]", - "description": "Only support private AKS clusters, deny any other.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyPublicAks'))]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyAksWithoutDefender'), variables('rgName-bu0001A0005'))]", - "comments": "Deny the creation of Azure Kubernetes Service cluster that is not protected with Microsoft Defender for Containers.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyAksWithoutDefender')), '2020-09-01').displayName), 125))]", - "description": "Microsoft Defender for Containers should be enabled in the cluster.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyAksWithoutDefender'))]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-NoPublicIPsForVMScaleSets'), variables('rgName-bu0001A0005'))]", - "comments": "Applying the 'No Public IPs on VMSS' policy to the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-NoPublicIPsForVMScaleSets')), '2020-09-01').displayName), 125))]", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-NoPublicIPsForVMScaleSets'))]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyAksWithoutPolicy'), variables('rgName-bu0001A0005'))]", - "comments": "Deny AKS clusters that do not have Azure Policy enabled in the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(variables('policyDefinitionId-DenyAksWithoutPolicy'), '2020-09-01').displayName), 125))]", - "description": "Only support AKS clusters with Azure Policy enabled, deny any other.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-DenyAksWithoutPolicy')]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyAagWithoutWaf'), variables('rgName-bu0001A0005'))]", - "comments": "Deny public AKS clusters policy applied to the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyAagWithoutWaf')), '2020-09-01').displayName), 125))]", - "description": "Only allow Azure Application Gateway SKU with WAF support.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', variables('policyDefinitionName-DenyAagWithoutWaf'))]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyAksWithoutRbac'), variables('rgName-bu0001A0005'))]", - "comments": "Deny AKS clusters without RBAC policy applied to the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(variables('policyDefinitionId-DenyAksWithoutRbac'), '2020-09-01').displayName), 125))]", - "description": "Only allow AKS with RBAC support enabled.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-DenyAksWithoutRbac')]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-DenyOldAks'), variables('rgName-bu0001A0005'))]", - "comments": "Deny AKS clusters on old version policy applied to the appliction resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'), '] ', reference(variables('policyDefinitionId-DenyOldAks'), '2020-09-01').displayName), 125))]", - "description": "Disallow older AKS versions.", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-DenyOldAks')]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-CustomerManagedEncryption'), variables('rgName-bu0001A0005'))]", - "comments": "Applying the 'Customer-Managed Disk Encryption' policy to the resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'),'] ', reference(variables('policyDefinitionId-CustomerManagedEncryption'), '2020-09-01').displayName), 125))]", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-CustomerManagedEncryption')]" - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policyDefinitionName-EncryptionAtHost'), variables('rgName-bu0001A0005'))]", - "comments": "Applying the 'Encryption at Host' policy to the resource group.", - "properties": { - "displayName": "[trim(take(concat('[', variables('rgName-bu0001A0005'),'] ', reference(variables('policyDefinitionId-EncryptionAtHost'), '2020-09-01').displayName), 125))]", - "scope": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('rgName-bu0001A0005'))]", - "policyDefinitionId": "[variables('policyDefinitionId-EncryptionAtHost')]" - } - } - ] - } - } - }, - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2020-09-01", - "name": "[guid(variables('policySetDefinitionName-EnableDefender'), subscription().id)]", - "location": "[variables('deploymentResourceRegion')]", - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', variables('policySetDefinitionName-EnableDefender'))]" - ], - "identity": { - "type": "SystemAssigned" - }, - "comments": "Ensures various Microsoft Defender services are is enabled.", - "properties": { - "displayName": "[reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', variables('policySetDefinitionName-EnableDefender')), '2020-09-01').displayName]", - "description": "Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.", - "enforcementMode": "[if(parameters('enforceAzureDefenderAutoDeployPolicies'), 'Default', 'DoNotEnforce')]", - "metadata": { - "version": "1.0.0", - "category": "Microsoft Defender for Cloud" - }, - "notScopes": [], - "scope": "[subscription().id]", - "policyDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', variables('policySetDefinitionName-EnableDefender'))]" - } - }, - { - "condition": "[parameters('enableAzureDefender')]", - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "KeyVaults", - "comments": "Enable Microsoft Defender Standard for Key Vault. Requires Owner or Security Admin role.", - "properties": { - "pricingTier": "Standard" - } - }, - { - "condition": "[parameters('enableAzureDefender')]", - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "ContainerRegistry", - "comments": "Enable Microsoft Defender Standard for Container Registry. Requires Owner or Security Admin role.", - "properties": { - "pricingTier": "Standard" - } - }, - { - "condition": "[parameters('enableAzureDefender')]", - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "KubernetesService", - "comments": "Enable Microsoft Defender Standard for Kubernetes Service. Requires Owner or Security Admin role.", - "properties": { - "pricingTier": "Standard" - } - }, - { - "condition": "[parameters('enableAzureDefender')]", - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "Arm", - "comments": "Enable Microsoft Defender Standard for Azure Resource Manager. Requires Owner or Security Admin role.", - "properties": { - "pricingTier": "Standard" // Isn't included in the Azure Policy applications above. - } - }, - { - "condition": "[parameters('enableAzureDefender')]", - "type": "Microsoft.Security/pricings", - "apiVersion": "2018-06-01", - "name": "Dns", - "comments": "Enable Microsoft Defender Standard for Azure DNS. Requires Owner or Security Admin role.", - "properties": { - "pricingTier": "Standard" // Isn't included in the Azure Policy applications above. - } - } - ] -} From d25d5c8d11ef9271820d8b8e4a50d923927b779a Mon Sep 17 00:00:00 2001 From: magrande Date: Tue, 12 Apr 2022 19:58:20 -0300 Subject: [PATCH 02/17] Modified readme subscription step --- docs/deploy/04-subscription.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/deploy/04-subscription.md b/docs/deploy/04-subscription.md index 8cde2929..fdd27c9a 100644 --- a/docs/deploy/04-subscription.md +++ b/docs/deploy/04-subscription.md @@ -98,14 +98,14 @@ Not only do we enable them in the steps below by default, but also set up an Azu ```bash # [This may take up to six minutes to run.] - az deployment sub create -f subscription.json -l centralus -p networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" + az deployment sub create -f subscription.bicep -l centralus -p networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" ``` If you do not have permissions on your subscription to enable Microsoft Defender (which requires the Azure RBAC role of _Subscription Owner_ or _Security Admin_), then instead execute the following variation of the same command. This will not enable Microsoft Defender services nor will Azure Policy attempt to enable the same (the policy will still be created, but in audit-only mode). Your final implementation should be to a subscription with these security services activated. ```bash # [This may take up to five minutes to run.] - az deployment sub create -f subscription.json -l centralus -p enableAzureDefender=false enforceAzureDefenderAutoDeployPolicies=false networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" + az deployment sub create -f subscription.bicep -l centralus -p enableAzureDefender=false enforceAzureDefenderAutoDeployPolicies=false networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" ``` ## Azure Security Benchmark From 5026366ad64ed1fe8f1172d8732c74c8451403c0 Mon Sep 17 00:00:00 2001 From: magrande Date: Wed, 13 Apr 2022 15:31:27 -0300 Subject: [PATCH 03/17] Refector policy assignment modules --- ...merManagedEncryptionPolicyAssignment.bicep | 11 -- .../DenyAagWithoutWafPolicyAssignment.bicep | 14 -- ...nyAksWithoutDefenderPolicyAssignment.bicep | 14 -- ...DenyAksWithoutPolicyPolicyAssignment.bicep | 14 -- .../DenyAksWithoutRbacPolicyAssignment.bicep | 14 -- modules/DenyOldAksPolicyAssignment.bicep | 14 -- modules/DenyPublicAksPolicyAssignment.bicep | 12 -- .../EncryptionAtHostPolicyAssignment.bicep | 13 -- ...licIPsForVMScaleSetsPolicyAssignment.bicep | 13 -- .../allowedResourcespolicyAssignment.bicep | 41 ------ .../defenderPolicyAssignmentDeployment.bicep | 51 ------- modules/hubsPoliciesDeployment.bicep | 17 +-- .../networkWatchersPoliciesDeployment.bicep | 11 +- modules/policyAssignmentDeploymentRG.bicep | 35 ----- modules/resourceGroupPolicyAssignment.bicep | 34 +++++ modules/spokesPoliciesDeployment.bicep | 17 +-- modules/subscriptionPolicyAssignment.bicep | 59 ++++++++ modules/workloadPoliciesDeployment.bicep | 134 +++++++++++++++--- subscription.bicep | 14 +- 19 files changed, 238 insertions(+), 294 deletions(-) delete mode 100644 modules/CustomerManagedEncryptionPolicyAssignment.bicep delete mode 100644 modules/DenyAagWithoutWafPolicyAssignment.bicep delete mode 100644 modules/DenyAksWithoutDefenderPolicyAssignment.bicep delete mode 100644 modules/DenyAksWithoutPolicyPolicyAssignment.bicep delete mode 100644 modules/DenyAksWithoutRbacPolicyAssignment.bicep delete mode 100644 modules/DenyOldAksPolicyAssignment.bicep delete mode 100644 modules/DenyPublicAksPolicyAssignment.bicep delete mode 100644 modules/EncryptionAtHostPolicyAssignment.bicep delete mode 100644 modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep delete mode 100644 modules/allowedResourcespolicyAssignment.bicep delete mode 100644 modules/defenderPolicyAssignmentDeployment.bicep delete mode 100644 modules/policyAssignmentDeploymentRG.bicep create mode 100644 modules/resourceGroupPolicyAssignment.bicep create mode 100644 modules/subscriptionPolicyAssignment.bicep diff --git a/modules/CustomerManagedEncryptionPolicyAssignment.bicep b/modules/CustomerManagedEncryptionPolicyAssignment.bicep deleted file mode 100644 index 2d0ac0f2..00000000 --- a/modules/CustomerManagedEncryptionPolicyAssignment.bicep +++ /dev/null @@ -1,11 +0,0 @@ -targetScope = 'resourceGroup' - -@description('\'Customer-Managed Disk Encryption\' applied to resource group - Policy Assignment.') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67', '2020-09-01').displayName}', 125)) - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/7d7be79c-23ba-4033-84dd-45e2a5ccdd67' - parameters: {} - } -} diff --git a/modules/DenyAagWithoutWafPolicyAssignment.bicep b/modules/DenyAagWithoutWafPolicyAssignment.bicep deleted file mode 100644 index 6917f195..00000000 --- a/modules/DenyAagWithoutWafPolicyAssignment.bicep +++ /dev/null @@ -1,14 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Only allow Azure Application Gateway SKU with WAF support. - Policy assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(guid(subscription().id, 'DenyAagWithoutWaf'), resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyAagWithoutWaf')), '2020-09-01').displayName}', 125)) - description: 'Only allow Azure Application Gateway SKU with WAF support.' - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyAagWithoutWaf')) - parameters: {} - } -} diff --git a/modules/DenyAksWithoutDefenderPolicyAssignment.bicep b/modules/DenyAksWithoutDefenderPolicyAssignment.bicep deleted file mode 100644 index 5c54eb77..00000000 --- a/modules/DenyAksWithoutDefenderPolicyAssignment.bicep +++ /dev/null @@ -1,14 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Microsoft Defender for Containers should be enabled in the cluster - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(guid(subscription().id, 'DenyNonDefenderAks'), resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyNonDefenderAks')), '2020-09-01').displayName}', 125)) - description: 'Microsoft Defender for Containers should be enabled in the cluster.' - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyNonDefenderAks')) - parameters: {} - } -} diff --git a/modules/DenyAksWithoutPolicyPolicyAssignment.bicep b/modules/DenyAksWithoutPolicyPolicyAssignment.bicep deleted file mode 100644 index 99fbc1be..00000000 --- a/modules/DenyAksWithoutPolicyPolicyAssignment.bicep +++ /dev/null @@ -1,14 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Only support AKS clusters with Azure Policy enabled, deny any other. - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d', '2020-09-01').displayName}', 125)) - description: 'Only support AKS clusters with Azure Policy enabled, deny any other.' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d' - parameters: {} - } -} diff --git a/modules/DenyAksWithoutRbacPolicyAssignment.bicep b/modules/DenyAksWithoutRbacPolicyAssignment.bicep deleted file mode 100644 index 230483ff..00000000 --- a/modules/DenyAksWithoutRbacPolicyAssignment.bicep +++ /dev/null @@ -1,14 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Only allow AKS with RBAC support enabled. - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457', '2020-09-01').displayName}', 125)) - description: 'Only allow AKS with RBAC support enabled.' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' - parameters: {} - } -} diff --git a/modules/DenyOldAksPolicyAssignment.bicep b/modules/DenyOldAksPolicyAssignment.bicep deleted file mode 100644 index 90e14529..00000000 --- a/modules/DenyOldAksPolicyAssignment.bicep +++ /dev/null @@ -1,14 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Disallow older AKS versions - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c', '2020-09-01').displayName}', 125)) - description: 'Disallow older AKS versions.' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/fb893a29-21bb-418c-a157-e99480ec364c' - parameters: {} - } -} diff --git a/modules/DenyPublicAksPolicyAssignment.bicep b/modules/DenyPublicAksPolicyAssignment.bicep deleted file mode 100644 index 49521cf2..00000000 --- a/modules/DenyPublicAksPolicyAssignment.bicep +++ /dev/null @@ -1,12 +0,0 @@ -targetScope = 'resourceGroup' - -@description('Only support private AKS clusters, deny any other. - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(guid(subscription().id, 'DenyPublicAks'), resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyPublicAks')), '2020-09-01').displayName}', 125)) - description: 'Only support private AKS clusters, deny any other.' - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'DenyPublicAks')) - parameters: {} - } -} diff --git a/modules/EncryptionAtHostPolicyAssignment.bicep b/modules/EncryptionAtHostPolicyAssignment.bicep deleted file mode 100644 index 914040cd..00000000 --- a/modules/EncryptionAtHostPolicyAssignment.bicep +++ /dev/null @@ -1,13 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('\'Encryption at Host\' policy applied to the resource group - Policy Assignment.') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c', '2020-09-01').displayName}', 125)) - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/41425d9f-d1a5-499a-9932-f8ed8453932c' - parameters: {} - } -} diff --git a/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep b/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep deleted file mode 100644 index 0412a392..00000000 --- a/modules/NoPublicIPsForVMScaleSetsPolicyAssignment.bicep +++ /dev/null @@ -1,13 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('\'No Public IPs on VMSS\' policy applied to the workload resource group. - Policy Assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(guid(subscription().id, 'NoPublicIPsForVMScaleSets'), resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'NoPublicIPsForVMScaleSets')), '2020-09-01').displayName}', 125)) - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policyDefinitions', guid(subscription().id, 'NoPublicIPsForVMScaleSets')) - parameters: {} - } -} diff --git a/modules/allowedResourcespolicyAssignment.bicep b/modules/allowedResourcespolicyAssignment.bicep deleted file mode 100644 index 02d46e21..00000000 --- a/modules/allowedResourcespolicyAssignment.bicep +++ /dev/null @@ -1,41 +0,0 @@ -targetScope = 'resourceGroup' - -/*** RESOURCES ***/ - -@description('Only support the a list of resources for our workload resource group - Policy assignment') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) - properties: { - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) - description: 'List of supported resources for our workload resource group' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' - parameters: { - listOfResourceTypesAllowed: { - value: [ - 'Microsoft.Compute/images' - 'Microsoft.Compute/virtualMachineScaleSets' - 'Microsoft.ContainerRegistry/registries' - 'Microsoft.ContainerRegistry/registries/agentPools' - 'Microsoft.ContainerRegistry/registries/replications' - 'Microsoft.ContainerService/managedClusters' - 'Microsoft.Insights/activityLogAlerts' - 'Microsoft.Insights/metricAlerts' - 'Microsoft.Insights/scheduledQueryRules' - 'Microsoft.Insights/workbooks' - 'Microsoft.KeyVault/vaults' - 'Microsoft.ManagedIdentity/userAssignedIdentities' - 'Microsoft.Network/applicationGateways' - 'Microsoft.Network/networkInterfaces' - 'Microsoft.Network/networkSecurityGroups' - 'Microsoft.Network/networkSecurityGroups/securityRules' - 'Microsoft.Network/privateDnsZones' - 'Microsoft.Network/privateDnsZones/virtualNetworkLinks' - 'Microsoft.Network/privateEndpoints' - 'Microsoft.OperationalInsights/workspaces' - 'Microsoft.OperationsManagement/solutions' - 'Microsoft.VirtualMachineImages/imageTemplates' - ] - } - } - } -} diff --git a/modules/defenderPolicyAssignmentDeployment.bicep b/modules/defenderPolicyAssignmentDeployment.bicep deleted file mode 100644 index 9dd9c39b..00000000 --- a/modules/defenderPolicyAssignmentDeployment.bicep +++ /dev/null @@ -1,51 +0,0 @@ -targetScope = 'subscription' - -/*** PARAMETERS ***/ - -@description('The policy assignment enforcement mode.') -param enforcementMode string = 'Default' - -@description('Subsription deployment\'s main location (centralus if not specified)') -@allowed([ - 'australiaeast' - 'canadacentral' - 'centralus' - 'eastus' - 'eastus2' - 'westus2' - 'francecentral' - 'germanywestcentral' - 'northeurope' - 'southafricanorth' - 'southcentralus' - 'uksouth' - 'westeurope' - 'japaneast' - 'southeastasia' - ]) -param location string = 'centralus' - -@description('Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled. - Policy Assignment') -param enableDefenderPolicyDefinitionSetName string - -/*** RESOURCES ***/ - -@description('Assignment of policy') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(enableDefenderPolicyDefinitionSetName, subscription().id) - identity: { - type: 'SystemAssigned' - } - location: location - properties: { - displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', enableDefenderPolicyDefinitionSetName), '2020-09-01').displayName - description: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' - notScopes: [] - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', enableDefenderPolicyDefinitionSetName) - enforcementMode: enforcementMode - metadata: { - version: '1.0.0' - category: 'Microsoft Defender for Cloud' - } - } -} diff --git a/modules/hubsPoliciesDeployment.bicep b/modules/hubsPoliciesDeployment.bicep index 9e642011..3f75eda6 100644 --- a/modules/hubsPoliciesDeployment.bicep +++ b/modules/hubsPoliciesDeployment.bicep @@ -3,15 +3,14 @@ targetScope = 'resourceGroup' /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.') -module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { +module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Hubs-allowedResourcespolicyAssignment' scope: resourceGroup() params: { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + builtIn: true + policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' policyAssignmentDescription: 'List of supported resources for our enterprise hubs resource group' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' - parameters: { + policyAssignmentParameters: { listOfResourceTypesAllowed: { value: [ 'Microsoft.Insights/diagnosticSettings' @@ -36,14 +35,12 @@ module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { } @description('Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.') -module NetworkWatcherShouldBeEnabledPolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { +module NetworkWatcherShouldBeEnabledPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Hubs-NetworkWatcherShouldBeEnabledPolicyAssignment' scope: resourceGroup() params: { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', resourceGroup().name) - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', '2020-09-01').displayName}', 125)) + builtIn: true + policyDefinitionName: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' - parameters: {} } } diff --git a/modules/networkWatchersPoliciesDeployment.bicep b/modules/networkWatchersPoliciesDeployment.bicep index 79745eba..0475907f 100644 --- a/modules/networkWatchersPoliciesDeployment.bicep +++ b/modules/networkWatchersPoliciesDeployment.bicep @@ -3,16 +3,15 @@ targetScope = 'resourceGroup' /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the network watchers resource group to only allow select networking resources.') -module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { +module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'NetworkWatchers-allowedResourcespolicyAssignment' scope: resourceGroup() params: { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + builtIn: true + policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' policyAssignmentDescription: 'List of supported resources for our Network Watcher resource group' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' - enforcementMode: 'DoNotEnforce' - parameters: { + policyAssignmentEnforcementMode: 'DoNotEnforce' + policyAssignmentParameters: { listOfResourceTypesAllowed: { value: [ 'Microsoft.Network/networkWatchers' diff --git a/modules/policyAssignmentDeploymentRG.bicep b/modules/policyAssignmentDeploymentRG.bicep deleted file mode 100644 index 1873c59e..00000000 --- a/modules/policyAssignmentDeploymentRG.bicep +++ /dev/null @@ -1,35 +0,0 @@ -targetScope = 'resourceGroup' - -/*** PARAMETERS ***/ - -@description('The definitionID of the policy to assign.') -param policyDefinitionId string - -@description('The name of the policy assignment.') -param name string - -@description('The policy assignment\'s display name.') -param displayName string - -@description('Object with parameters applied to the policy assignment. ') -param parameters object - -@description('Policy assignment\'s description') -param policyAssignmentDescription string = '' - -@description('Provides the ability to test the outcome of a policy on existing resources without initiating the policy effect') -param enforcementMode string = 'Default' - -/*** RESOURCES ***/ - -@description('Assignment of policy') -resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: name - properties: { - displayName: displayName - description: policyAssignmentDescription - enforcementMode: enforcementMode - policyDefinitionId: policyDefinitionId - parameters: parameters - } -} diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep new file mode 100644 index 00000000..9c4f83bc --- /dev/null +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -0,0 +1,34 @@ +targetScope = 'resourceGroup' + +/*** PARAMETERS ***/ + +@description('Determines whether the policy being assigned is built in or not.') +param builtIn bool = true + +@description('The name of the policy to assign.') +param policyDefinitionName string + +@description('The desciption of the policy assignment') +param policyAssignmentDescription string = '' + +@description('The desciption of the policy assignment') +param policyAssignmentParameters object = {} + +@description('This property provides the ability to test the outcome of a policy on existing resources without initiating the policy effect or triggering entries in the Azure Activity log') +param policyAssignmentEnforcementMode string = 'Default' + +/*** RESOURCES ***/ + +@description('Assigns a Policy at Resource Group level') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: builtIn ? guid('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}', resourceGroup().name) : guid(policyDefinitionName, resourceGroup().name) + properties: { + displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinitionName), '2020-09-01').displayName}', 125)) + description: policyAssignmentDescription + policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinitionName) + parameters: policyAssignmentParameters + enforcementMode: policyAssignmentEnforcementMode + } +} + + diff --git a/modules/spokesPoliciesDeployment.bicep b/modules/spokesPoliciesDeployment.bicep index c0164aa7..8ca70b6b 100644 --- a/modules/spokesPoliciesDeployment.bicep +++ b/modules/spokesPoliciesDeployment.bicep @@ -3,15 +3,14 @@ targetScope = 'resourceGroup' /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the spokes RG to only allow select networking and observation resources.') -module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { +module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Spokes-allowedResourcespolicyAssignment' scope: resourceGroup() params: { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', resourceGroup().name) - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c', '2020-09-01').displayName}', 125)) + builtIn: true + policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' policyAssignmentDescription: 'List of supported resources for our enterprise spokes resource group' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c' - parameters: { + policyAssignmentParameters: { listOfResourceTypesAllowed: { value: [ 'Microsoft.Network/networkSecurityGroups' @@ -29,14 +28,12 @@ module allowedResourcespolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { } @description('Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.') -module NetworkWatcherShouldBeEnabledPolicyAssignment 'policyAssignmentDeploymentRG.bicep' = { +module NetworkWatcherShouldBeEnabledPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Spokes-NetworkWatcherShouldBeEnabledPolicyAssignment' scope: resourceGroup() params: { - name: guid('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', resourceGroup().name) - displayName: trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6', '2020-09-01').displayName}', 125)) + builtIn: true + policyDefinitionName: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Spoke resource group.' - policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' - parameters: {} } } diff --git a/modules/subscriptionPolicyAssignment.bicep b/modules/subscriptionPolicyAssignment.bicep new file mode 100644 index 00000000..927b98ed --- /dev/null +++ b/modules/subscriptionPolicyAssignment.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +/*** PARAMETERS ***/ + +@description('The policy assignment enforcement mode.') +param enforcementMode string = 'Default' + +@description('Subsription deployment\'s main location (centralus if not specified)') +@allowed([ + 'australiaeast' + 'canadacentral' + 'centralus' + 'eastus' + 'eastus2' + 'westus2' + 'francecentral' + 'germanywestcentral' + 'northeurope' + 'southafricanorth' + 'southcentralus' + 'uksouth' + 'westeurope' + 'japaneast' + 'southeastasia' + ]) +param location string = 'centralus' + + +@description('The name of the policy or policy set to assign.') +param policyDefinitionName string + +@description('This object contains the type of policy assignment identity') +param policyAssignmentIdentity object = {} + +@description('The desciption of the policy assignment') +param polcyAssignmentDescription string = '' + +@description('Policy assignment metadata; this parameter can by any object') +param polcyAssignmentMetadata object = {} + +@description('The policy\'s excluded scopes') +param notScopes array = [] + +/*** RESOURCES ***/ + +@description('Assignment of policy') +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { + name: guid(policyDefinitionName, subscription().id) + identity: policyAssignmentIdentity + location: location + properties: { + displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefinitionName), '2020-09-01').displayName + description: polcyAssignmentDescription + notScopes: notScopes + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefinitionName) + enforcementMode: enforcementMode + metadata: polcyAssignmentMetadata + } +} diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index 11a70aac..06e94b7f 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -2,61 +2,157 @@ targetScope = 'resourceGroup' /*** RESOURCES ***/ -@description('Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.') -module allowedResourcespolicyAssignment 'allowedResourcespolicyAssignment.bicep' = { +@description('Only support the a list of resources for our workload resource group - Policy assignment') +module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Hubs-allowedResourcespolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + policyAssignmentDescription: 'List of supported resources for our workload resource group' + policyAssignmentParameters: { + listOfResourceTypesAllowed: { + value: [ + 'Microsoft.Compute/images' + 'Microsoft.Compute/virtualMachineScaleSets' + 'Microsoft.ContainerRegistry/registries' + 'Microsoft.ContainerRegistry/registries/agentPools' + 'Microsoft.ContainerRegistry/registries/replications' + 'Microsoft.ContainerService/managedClusters' + 'Microsoft.Insights/activityLogAlerts' + 'Microsoft.Insights/metricAlerts' + 'Microsoft.Insights/scheduledQueryRules' + 'Microsoft.Insights/workbooks' + 'Microsoft.KeyVault/vaults' + 'Microsoft.ManagedIdentity/userAssignedIdentities' + 'Microsoft.Network/applicationGateways' + 'Microsoft.Network/networkInterfaces' + 'Microsoft.Network/networkSecurityGroups' + 'Microsoft.Network/networkSecurityGroups/securityRules' + 'Microsoft.Network/privateDnsZones' + 'Microsoft.Network/privateDnsZones/virtualNetworkLinks' + 'Microsoft.Network/privateEndpoints' + 'Microsoft.OperationalInsights/workspaces' + 'Microsoft.OperationsManagement/solutions' + 'Microsoft.VirtualMachineImages/imageTemplates' + ] + } + } + } } -module DenyPublicAksPolicyAssignment 'DenyPublicAksPolicyAssignment.bicep' = { +resource pdDenyPublicAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyPublicAks') + scope: subscription() +} + +@description('Only support private AKS clusters, deny any other. - Policy Assignment') +module DenyPublicAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyPublicAksPolicyAssignment' scope: resourceGroup() + params: { + builtIn: false + policyDefinitionName: pdDenyPublicAks.name + policyAssignmentDescription: 'Only support private AKS clusters, deny any other.' + } +} + +resource pdDenyNonDefenderAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyNonDefenderAks') + scope: subscription() } -@description('Deny the creation of Azure Kubernetes Service cluster that is not protected with Microsoft Defender for Containers.') -module DenyAksWithoutDefenderPolicyAssignment 'DenyAksWithoutDefenderPolicyAssignment.bicep' = { +@description('Microsoft Defender for Containers should be enabled in the cluster - Policy Assignment') +module DenyAksWithoutDefenderPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutDefenderPolicyAssignment' scope: resourceGroup() + params: { + builtIn: false + policyDefinitionName: pdDenyNonDefenderAks.name + policyAssignmentDescription: 'Microsoft Defender for Containers should be enabled in the cluster.' + } } -@description('Applying the \'No Public IPs on VMSS\' policy to the appliction resource group.') -module NoPublicIPsForVMScaleSetsPolicyAssignment 'NoPublicIPsForVMScaleSetsPolicyAssignment.bicep' = { +resource pdNoPublicIPsForVMScaleSets 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'NoPublicIPsForVMScaleSets') + scope: subscription() +} + +@description('\'No Public IPs on VMSS\' policy applied to the workload resource group. - Policy Assignment') +module NoPublicIPsForVMScaleSetsPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-NoPublicIPsForVMScaleSetsPolicyAssignment' scope: resourceGroup() + params: { + builtIn: false + policyDefinitionName: pdNoPublicIPsForVMScaleSets.name + } } -@description('Deny AKS clusters that do not have Azure Policy enabled in the appliction resource group.') -module DenyAksWithoutPolicyPolicyAssignment 'DenyAksWithoutPolicyPolicyAssignment.bicep' = { +@description('Only support AKS clusters with Azure Policy enabled, deny any other. - Policy Assignment') +module DenyAksWithoutPolicyPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutPolicyPolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: '0a15ec92-a229-4763-bb14-0ea34a568f8d' + policyAssignmentDescription: 'Only support AKS clusters with Azure Policy enabled, deny any other.' + } +} + +resource pdDenyAagWithoutWaf 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyAagWithoutWaf') + scope: subscription() } -@description('Deny public AKS clusters policy applied to the appliction resource group.') -module DenyAagWithoutWafPolicyAssignment 'DenyAagWithoutWafPolicyAssignment.bicep' = { +@description('Only allow Azure Application Gateway SKU with WAF support. - Policy assignment') +module DenyAagWithoutWafPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAagWithoutWafPolicyAssignment' scope: resourceGroup() + params: { + builtIn: false + policyDefinitionName: pdDenyAagWithoutWaf.name + policyAssignmentDescription: 'Only allow Azure Application Gateway SKU with WAF support.' + } } -@description('Deny AKS clusters without RBAC policy applied to the appliction resource group.') -module DenyAksWithoutRbacPolicyAssignment 'DenyAksWithoutRbacPolicyAssignment.bicep' = { +@description('Deny AKS clusters without RBAC policy applied to the appliction resource group. - Policy assignment') +module DenyAksWithoutRbacPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutRbacPolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + policyAssignmentDescription: 'Only allow AKS with RBAC support enabled.' + } } -@description('Deny AKS clusters on old version policy applied to the appliction resource group.') -module DenyOldAksPolicyAssignment 'DenyOldAksPolicyAssignment.bicep' = { +@description('Deny AKS clusters on old version policy applied to the appliction resource group. - Policy Assignment') +module DenyOldAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyOldAksPolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: 'fb893a29-21bb-418c-a157-e99480ec364c' + policyAssignmentDescription: 'Disallow older AKS versions.' + } } -@description('Applying the \'Customer-Managed Disk Encryption\' policy to the resource group.') -module CustomerManagedEncryptionPolicyAssignment 'CustomerManagedEncryptionPolicyAssignment.bicep' = { +@description('\'Customer-Managed Disk Encryption\' applied to resource group - Policy Assignment.') +module CustomerManagedEncryptionPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-CustomerManagedEncryptionPolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: '7d7be79c-23ba-4033-84dd-45e2a5ccdd67' + } } -@description('Applying the \'Encryption at Host\' policy to the resource group.') -module EncryptionAtHostPolicyAssignment 'EncryptionAtHostPolicyAssignment.bicep' = { +@description('\'Encryption at Host\' policy applied to the resource group - Policy Assignment.') +module EncryptionAtHostPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-EncryptionAtHostPolicyAssignment' scope: resourceGroup() + params: { + builtIn: true + policyDefinitionName: '41425d9f-d1a5-499a-9932-f8ed8453932c' + } } diff --git a/subscription.bicep b/subscription.bicep index b76a5ec9..915de423 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -417,13 +417,21 @@ module workloadPoliciesDeployment 'modules/workloadPoliciesDeployment.bicep' = { scope: rgbu0001a0005 } -@description('Enable policy that ensures various Microsoft Defender services are enabled.') -module defenderPolicyDeployment 'modules/defenderPolicyAssignmentDeployment.bicep' = { +@description('Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled. - Policy Assignment') +module defenderPolicyDeployment 'modules/subscriptionPolicyAssignment.bicep' = { name: 'Apply-EnableDefender-Policy' scope: subscription() params: { location: location - enableDefenderPolicyDefinitionSetName: psdEnableDefender.name + policyAssignmentIdentity: { + type: 'SystemAssigned' + } + polcyAssignmentMetadata: { + version: '1.0.0' + category: 'Microsoft Defender for Cloud' + } + policyDefinitionName: psdEnableDefender.name + polcyAssignmentDescription: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' enforcementMode: enforceAzureDefenderAutoDeployPolicies ? 'Default' : 'DoNotEnforce' } } From 92a336e1619aba754b646e75a3417810c61f8359 Mon Sep 17 00:00:00 2001 From: magrande Date: Fri, 15 Apr 2022 11:29:06 -0300 Subject: [PATCH 04/17] Using existing policy definition when assigning either custom or built in policies ar RG level --- modules/resourceGroupPolicyAssignment.bicep | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index 9c4f83bc..f27d38f4 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -17,18 +17,23 @@ param policyAssignmentParameters object = {} @description('This property provides the ability to test the outcome of a policy on existing resources without initiating the policy effect or triggering entries in the Azure Activity log') param policyAssignmentEnforcementMode string = 'Default' +resource policyDefintion 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: policyDefinitionName + scope: subscription() +} + /*** RESOURCES ***/ @description('Assigns a Policy at Resource Group level') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: builtIn ? guid('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}', resourceGroup().name) : guid(policyDefinitionName, resourceGroup().name) + name: builtIn ? guid('/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}', resourceGroup().name) : guid(policyDefintion.name, resourceGroup().name) + scope: resourceGroup() properties: { - displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinitionName), '2020-09-01').displayName}', 125)) + displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefintion.name), '2020-09-01').displayName}', 125)) description: policyAssignmentDescription - policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinitionName) + policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefintion.name) parameters: policyAssignmentParameters enforcementMode: policyAssignmentEnforcementMode } } - From 94bc3aad836d53fb13376edce30cc826fdb98d78 Mon Sep 17 00:00:00 2001 From: magrande Date: Fri, 15 Apr 2022 11:41:34 -0300 Subject: [PATCH 05/17] Using existing policy definition when assigning either custom or built in policies ar Subscription level --- modules/subscriptionPolicyAssignment.bicep | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/subscriptionPolicyAssignment.bicep b/modules/subscriptionPolicyAssignment.bicep index 927b98ed..2ece2f17 100644 --- a/modules/subscriptionPolicyAssignment.bicep +++ b/modules/subscriptionPolicyAssignment.bicep @@ -43,16 +43,21 @@ param notScopes array = [] /*** RESOURCES ***/ +resource policyDefintion 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: policyDefinitionName + scope: subscription() +} + @description('Assignment of policy') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(policyDefinitionName, subscription().id) + name: guid(policyDefintion.name, subscription().id) identity: policyAssignmentIdentity location: location properties: { - displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefinitionName), '2020-09-01').displayName + displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name), '2020-09-01').displayName description: polcyAssignmentDescription notScopes: notScopes - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefinitionName) + policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name) enforcementMode: enforcementMode metadata: polcyAssignmentMetadata } From 4a41b5726ab15c854bda9e23fbaedb4a2cfff854 Mon Sep 17 00:00:00 2001 From: magrande Date: Tue, 19 Apr 2022 14:06:24 -0300 Subject: [PATCH 06/17] Addressing comments --- modules/subscriptionPolicyAssignment.bicep | 24 ++----------- modules/workloadPoliciesDeployment.bicep | 42 ++++++++++++++++++---- subscription.bicep | 28 +++++++++------ 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/modules/subscriptionPolicyAssignment.bicep b/modules/subscriptionPolicyAssignment.bicep index 2ece2f17..728cd488 100644 --- a/modules/subscriptionPolicyAssignment.bicep +++ b/modules/subscriptionPolicyAssignment.bicep @@ -6,25 +6,7 @@ targetScope = 'subscription' param enforcementMode string = 'Default' @description('Subsription deployment\'s main location (centralus if not specified)') -@allowed([ - 'australiaeast' - 'canadacentral' - 'centralus' - 'eastus' - 'eastus2' - 'westus2' - 'francecentral' - 'germanywestcentral' - 'northeurope' - 'southafricanorth' - 'southcentralus' - 'uksouth' - 'westeurope' - 'japaneast' - 'southeastasia' - ]) -param location string = 'centralus' - +param location string @description('The name of the policy or policy set to assign.') param policyDefinitionName string @@ -33,7 +15,7 @@ param policyDefinitionName string param policyAssignmentIdentity object = {} @description('The desciption of the policy assignment') -param polcyAssignmentDescription string = '' +param policyAssignmentDescription string = '' @description('Policy assignment metadata; this parameter can by any object') param polcyAssignmentMetadata object = {} @@ -55,7 +37,7 @@ resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' location: location properties: { displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name), '2020-09-01').displayName - description: polcyAssignmentDescription + description: policyAssignmentDescription notScopes: notScopes policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name) enforcementMode: enforcementMode diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index 06e94b7f..420edef4 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -88,13 +88,19 @@ module NoPublicIPsForVMScaleSetsPolicyAssignment 'resourceGroupPolicyAssignment. } } +@description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') +resource DenyAksWithoutPolicyPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: '0a15ec92-a229-4763-bb14-0ea34a568f8d' + scope: subscription() +} + @description('Only support AKS clusters with Azure Policy enabled, deny any other. - Policy Assignment') module DenyAksWithoutPolicyPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutPolicyPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: '0a15ec92-a229-4763-bb14-0ea34a568f8d' + policyDefinitionName: DenyAksWithoutPolicyPolicyDefinition.name policyAssignmentDescription: 'Only support AKS clusters with Azure Policy enabled, deny any other.' } } @@ -115,44 +121,68 @@ module DenyAagWithoutWafPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = } } +@description('Role-Based Access Control (RBAC) should be used on Kubernetes Services - Policy definition.') +resource DenyAksWithoutRbacPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + scope: subscription() +} + @description('Deny AKS clusters without RBAC policy applied to the appliction resource group. - Policy assignment') module DenyAksWithoutRbacPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutRbacPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + policyDefinitionName: DenyAksWithoutRbacPolicyDefinition.name policyAssignmentDescription: 'Only allow AKS with RBAC support enabled.' } } +@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') +resource DenyOldAksPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'fb893a29-21bb-418c-a157-e99480ec364c' + scope: subscription() +} + @description('Deny AKS clusters on old version policy applied to the appliction resource group. - Policy Assignment') module DenyOldAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyOldAksPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'fb893a29-21bb-418c-a157-e99480ec364c' + policyDefinitionName: DenyOldAksPolicyDefinition.name policyAssignmentDescription: 'Disallow older AKS versions.' } } +@description('Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys - Policy definition') +resource CustomerManagedEncryptionPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: '7d7be79c-23ba-4033-84dd-45e2a5ccdd67' + scope: subscription() +} + @description('\'Customer-Managed Disk Encryption\' applied to resource group - Policy Assignment.') module CustomerManagedEncryptionPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-CustomerManagedEncryptionPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: '7d7be79c-23ba-4033-84dd-45e2a5ccdd67' + policyDefinitionName: CustomerManagedEncryptionPolicyDefinition.name } } -@description('\'Encryption at Host\' policy applied to the resource group - Policy Assignment.') +@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy definition') +resource EncryptionAtHostPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: '41425d9f-d1a5-499a-9932-f8ed8453932c' + scope: subscription() +} + +@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy Assignment.') module EncryptionAtHostPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-EncryptionAtHostPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: '41425d9f-d1a5-499a-9932-f8ed8453932c' + policyDefinitionName: EncryptionAtHostPolicyDefinition.name } } diff --git a/subscription.bicep b/subscription.bicep index 915de423..05b4b9b1 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -5,13 +5,13 @@ targetScope = 'subscription' @description('By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are configured to deploy via Azure Policy, use this parameter to disable that.') param enforceAzureDefenderAutoDeployPolicies bool = true -@description('By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are enabled; use this parameter to prevent them from being enabled. Deploying these requires subscription Owner or Security Admin roles.') -param enableAzureDefender bool = true +@description('By default Microsoft Defender for Containers service is enabled; use this parameter to prevent the involved pricings from being enabled. Deploying these requires subscription Owner or Security Admin roles.') +param enableMicrosoftDefenderForCloud bool = true @description('networkWatcherRG often times already exists in a subscription. Empty string will result in using the default resource location.') param networkWatcherRGRegion string = '' -@description('Subsription deployment\'s main location (centralus if not specified)') +@description('This region is used as the default for all generic resource groups and for any additional deployment resources. No resources are actually deployed to this resource group.') @allowed([ 'australiaeast' 'canadacentral' @@ -57,6 +57,11 @@ resource rgNetworkWatchers 'Microsoft.Resources/resourceGroups@2021-04-01' = { location: empty(networkWatcherRGRegion) ? 'centralus' : networkWatcherRGRegion } +@description('Security Admin Role built-in role.') +resource securityAdminRole 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = { + name: 'fb1c8493-542b-48eb-b624-b4c8fea62acd' +} + @description('Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.') resource pdEnableAksDefender 'Microsoft.Authorization/policyDefinitions@2021-06-01' = { name: guid(subscription().id, 'EnableDefenderForAks') @@ -86,7 +91,7 @@ resource pdEnableAksDefender 'Microsoft.Authorization/policyDefinitions@2021-06- deploymentScope: 'subscription' existenceScope: 'subscription' roleDefinitionIds: [ - '/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd' + securityAdminRole.id ] existenceCondition: { field: 'Microsoft.Security/pricings/pricingTier' @@ -147,7 +152,7 @@ resource pdEnableAkvDefender 'Microsoft.Authorization/policyDefinitions@2021-06- deploymentScope: 'subscription' existenceScope: 'subscription' roleDefinitionIds: [ - '/providers/Microsoft.Authorization/roleDefinitions/fb1c8493-542b-48eb-b624-b4c8fea62acd' + securityAdminRole.id ] existenceCondition: { field: 'Microsoft.Security/pricings/pricingTier' @@ -431,13 +436,14 @@ module defenderPolicyDeployment 'modules/subscriptionPolicyAssignment.bicep' = { category: 'Microsoft Defender for Cloud' } policyDefinitionName: psdEnableDefender.name - polcyAssignmentDescription: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' + policyAssignmentDescription: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' enforcementMode: enforceAzureDefenderAutoDeployPolicies ? 'Default' : 'DoNotEnforce' + notScopes: [] } } @description('Enable Microsoft Defender Standard for Key Vault. Requires Owner or Security Admin role.') -resource enableKeyVaultspricing 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { +resource enableKeyVaultspricing 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'KeyVaults' properties: { pricingTier: 'Standard' @@ -445,7 +451,7 @@ resource enableKeyVaultspricing 'Microsoft.Security/pricings@2018-06-01' = if (e } @description('Enable Microsoft Defender Standard for Container Registry. Requires Owner or Security Admin role.') -resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { +resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'ContainerRegistry' properties: { pricingTier: 'Standard' @@ -453,7 +459,7 @@ resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if ( } @description('Enable Microsoft Defender Standard for Kubernetes Service. Requires Owner or Security Admin role.') -resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { +resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'KubernetesService' properties: { pricingTier: 'Standard' @@ -461,7 +467,7 @@ resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if ( } @description('Enable Microsoft Defender Standard for Azure Resource Manager. Requires Owner or Security Admin role.') -resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { +resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'Arm' properties: { pricingTier: 'Standard' @@ -469,7 +475,7 @@ resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDef } @description('Enable Microsoft Defender Standard for Azure DNS. Requires Owner or Security Admin role.') -resource enableDns 'Microsoft.Security/pricings@2018-06-01' = if (enableAzureDefender) { +resource enableDns 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'Dns' properties: { pricingTier: 'Standard' From 568173e3b97a24ffa4b45256d484e4a92897b9bf Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Tue, 19 Apr 2022 14:36:15 -0300 Subject: [PATCH 07/17] Update modules/resourceGroupPolicyAssignment.bicep Co-authored-by: Chad Kittel --- modules/resourceGroupPolicyAssignment.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index f27d38f4..c8668d8d 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -17,7 +17,7 @@ param policyAssignmentParameters object = {} @description('This property provides the ability to test the outcome of a policy on existing resources without initiating the policy effect or triggering entries in the Azure Activity log') param policyAssignmentEnforcementMode string = 'Default' -resource policyDefintion 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: policyDefinitionName scope: subscription() } From 3ce8807a7a7f15f87433106c24a89797905f82ce Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Tue, 19 Apr 2022 14:39:18 -0300 Subject: [PATCH 08/17] Update modules/resourceGroupPolicyAssignment.bicep Co-authored-by: Chad Kittel --- modules/resourceGroupPolicyAssignment.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index c8668d8d..f3490339 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -8,7 +8,7 @@ param builtIn bool = true @description('The name of the policy to assign.') param policyDefinitionName string -@description('The desciption of the policy assignment') +@description('The description of the policy assignment.') param policyAssignmentDescription string = '' @description('The desciption of the policy assignment') From 29b2d7fdd7bcd5abea326fa364934f741c29eb4c Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Tue, 19 Apr 2022 14:39:33 -0300 Subject: [PATCH 09/17] Update modules/resourceGroupPolicyAssignment.bicep Co-authored-by: Chad Kittel --- modules/resourceGroupPolicyAssignment.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index f3490339..a6dea77e 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -2,7 +2,7 @@ targetScope = 'resourceGroup' /*** PARAMETERS ***/ -@description('Determines whether the policy being assigned is built in or not.') +@description('Indicates whether the policy being assigned is built in or not.') param builtIn bool = true @description('The name of the policy to assign.') From f3b391bc2b340cb2ca244bc53d3c3a9289d05d6d Mon Sep 17 00:00:00 2001 From: magrande Date: Tue, 19 Apr 2022 15:04:22 -0300 Subject: [PATCH 10/17] Addressing new round of comments. Missing comments added, refactoring in built-in - custom policy reference --- .../networkWatchersPoliciesDeployment.bicep | 2 +- modules/resourceGroupPolicyAssignment.bicep | 10 +- modules/workloadPoliciesDeployment.bicep | 92 ++++++++++--------- subscription.bicep | 63 +++++++------ 4 files changed, 86 insertions(+), 81 deletions(-) diff --git a/modules/networkWatchersPoliciesDeployment.bicep b/modules/networkWatchersPoliciesDeployment.bicep index 0475907f..1e75f49c 100644 --- a/modules/networkWatchersPoliciesDeployment.bicep +++ b/modules/networkWatchersPoliciesDeployment.bicep @@ -10,7 +10,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = builtIn: true policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' policyAssignmentDescription: 'List of supported resources for our Network Watcher resource group' - policyAssignmentEnforcementMode: 'DoNotEnforce' + policyAssignmentEnforcementMode: 'DoNotEnforce' // Since this RG may be under existing policy control in your subscription, adding this policy as audit-only. policyAssignmentParameters: { listOfResourceTypesAllowed: { value: [ diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index a6dea77e..92a675de 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -11,12 +11,14 @@ param policyDefinitionName string @description('The description of the policy assignment.') param policyAssignmentDescription string = '' -@description('The desciption of the policy assignment') +@description('The he policy assignment\'s parameters') param policyAssignmentParameters object = {} @description('This property provides the ability to test the outcome of a policy on existing resources without initiating the policy effect or triggering entries in the Azure Activity log') param policyAssignmentEnforcementMode string = 'Default' +/*** EXISTING RESOURCES ***/ + resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: policyDefinitionName scope: subscription() @@ -26,12 +28,12 @@ resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' @description('Assigns a Policy at Resource Group level') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: builtIn ? guid('/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}', resourceGroup().name) : guid(policyDefintion.name, resourceGroup().name) + name: guid( builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}': policyDefinition.name, resourceGroup().name) scope: resourceGroup() properties: { - displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefintion.name), '2020-09-01').displayName}', 125)) + displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinition.id), '2020-09-01').displayName}', 125)) description: policyAssignmentDescription - policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefintion.name}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefintion.name) + policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinition.name) parameters: policyAssignmentParameters enforcementMode: policyAssignmentEnforcementMode } diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index 420edef4..a64441ab 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -1,5 +1,53 @@ targetScope = 'resourceGroup' +/*** EXISTING RESOURCES ***/ + +resource pdDenyPublicAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyPublicAks') + scope: subscription() +} + + +resource pdDenyNonDefenderAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyNonDefenderAks') + scope: subscription() +} + +resource pdNoPublicIPsForVMScaleSets 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'NoPublicIPsForVMScaleSets') + scope: subscription() +} + +resource pdDenyAagWithoutWaf 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: guid(subscription().id, 'DenyAagWithoutWaf') + scope: subscription() +} + +@description('Role-Based Access Control (RBAC) should be used on Kubernetes Services - Policy definition.') +resource DenyAksWithoutRbacPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + scope: subscription() +} + + +@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') +resource DenyOldAksPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'fb893a29-21bb-418c-a157-e99480ec364c' + scope: subscription() +} + +@description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') +resource DenyAksWithoutPolicyPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: '0a15ec92-a229-4763-bb14-0ea34a568f8d' + scope: subscription() +} + +@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy definition') +resource EncryptionAtHostPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: '41425d9f-d1a5-499a-9932-f8ed8453932c' + scope: subscription() +} + /*** RESOURCES ***/ @description('Only support the a list of resources for our workload resource group - Policy assignment') @@ -41,11 +89,6 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = } } -resource pdDenyPublicAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: guid(subscription().id, 'DenyPublicAks') - scope: subscription() -} - @description('Only support private AKS clusters, deny any other. - Policy Assignment') module DenyPublicAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyPublicAksPolicyAssignment' @@ -57,11 +100,6 @@ module DenyPublicAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { } } -resource pdDenyNonDefenderAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: guid(subscription().id, 'DenyNonDefenderAks') - scope: subscription() -} - @description('Microsoft Defender for Containers should be enabled in the cluster - Policy Assignment') module DenyAksWithoutDefenderPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutDefenderPolicyAssignment' @@ -73,11 +111,6 @@ module DenyAksWithoutDefenderPolicyAssignment 'resourceGroupPolicyAssignment.bic } } -resource pdNoPublicIPsForVMScaleSets 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: guid(subscription().id, 'NoPublicIPsForVMScaleSets') - scope: subscription() -} - @description('\'No Public IPs on VMSS\' policy applied to the workload resource group. - Policy Assignment') module NoPublicIPsForVMScaleSetsPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-NoPublicIPsForVMScaleSetsPolicyAssignment' @@ -88,12 +121,6 @@ module NoPublicIPsForVMScaleSetsPolicyAssignment 'resourceGroupPolicyAssignment. } } -@description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') -resource DenyAksWithoutPolicyPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: '0a15ec92-a229-4763-bb14-0ea34a568f8d' - scope: subscription() -} - @description('Only support AKS clusters with Azure Policy enabled, deny any other. - Policy Assignment') module DenyAksWithoutPolicyPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutPolicyPolicyAssignment' @@ -105,11 +132,6 @@ module DenyAksWithoutPolicyPolicyAssignment 'resourceGroupPolicyAssignment.bicep } } -resource pdDenyAagWithoutWaf 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: guid(subscription().id, 'DenyAagWithoutWaf') - scope: subscription() -} - @description('Only allow Azure Application Gateway SKU with WAF support. - Policy assignment') module DenyAagWithoutWafPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAagWithoutWafPolicyAssignment' @@ -121,12 +143,6 @@ module DenyAagWithoutWafPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = } } -@description('Role-Based Access Control (RBAC) should be used on Kubernetes Services - Policy definition.') -resource DenyAksWithoutRbacPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' - scope: subscription() -} - @description('Deny AKS clusters without RBAC policy applied to the appliction resource group. - Policy assignment') module DenyAksWithoutRbacPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyAksWithoutRbacPolicyAssignment' @@ -138,12 +154,6 @@ module DenyAksWithoutRbacPolicyAssignment 'resourceGroupPolicyAssignment.bicep' } } -@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') -resource DenyOldAksPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: 'fb893a29-21bb-418c-a157-e99480ec364c' - scope: subscription() -} - @description('Deny AKS clusters on old version policy applied to the appliction resource group. - Policy Assignment') module DenyOldAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-DenyOldAksPolicyAssignment' @@ -171,12 +181,6 @@ module CustomerManagedEncryptionPolicyAssignment 'resourceGroupPolicyAssignment. } } -@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy definition') -resource EncryptionAtHostPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: '41425d9f-d1a5-499a-9932-f8ed8453932c' - scope: subscription() -} - @description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy Assignment.') module EncryptionAtHostPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-EncryptionAtHostPolicyAssignment' diff --git a/subscription.bicep b/subscription.bicep index 05b4b9b1..bd344df4 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -1,5 +1,17 @@ targetScope = 'subscription' +/* Required Permissions + - Scope: Subscription + Role: Contributor + Reason: Creating resource groups, azure policy definations and assignments + + Optional Permissions + - Scope: Subscription + Role: Security Admin (or Owner) + Reason: To enable Microsoft Defender for Kubernetes, Container Registry, and Key Vault. + Notes: If unable to obtain permissions, you must pass false to the enableAzureDefender parameter or have someone else enable these for you. +*/ + /*** PARAMETERS ***/ @description('By default Microsoft Defender for Kubernetes Service, Container Registry, and Key Vault are configured to deploy via Azure Policy, use this parameter to disable that.') @@ -11,55 +23,42 @@ param enableMicrosoftDefenderForCloud bool = true @description('networkWatcherRG often times already exists in a subscription. Empty string will result in using the default resource location.') param networkWatcherRGRegion string = '' +/*** VARIABLES ***/ + @description('This region is used as the default for all generic resource groups and for any additional deployment resources. No resources are actually deployed to this resource group.') -@allowed([ - 'australiaeast' - 'canadacentral' - 'centralus' - 'eastus' - 'eastus2' - 'westus2' - 'francecentral' - 'germanywestcentral' - 'northeurope' - 'southafricanorth' - 'southcentralus' - 'uksouth' - 'westeurope' - 'japaneast' - 'southeastasia' - ]) -param location string = 'centralus' +var deploymentResourceRegion = 'centralus' + +/*** EXISTING RESOURCES ***/ + +@description('Security Admin Role built-in role.') +resource securityAdminRole 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = { + name: 'fb1c8493-542b-48eb-b624-b4c8fea62acd' +} /*** RESOURCES ***/ @description('This contains all of our regional hubs. Typically this would be found in your enterprise\'s Connectivity subscription.') resource rgHubs 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'rg-enterprise-networking-hubs' - location: location + location: deploymentResourceRegion } @description('This contains all of our regional spokes. Typically this would be found in your enterprise\'s Connectivity subscription or in the workload\'s subscription.') resource rgSpokes 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'rg-enterprise-networking-spokes' - location: location + location: deploymentResourceRegion } @description('This is the resource group for BU001A0005. Typically this would be found in your workload\'s subscription.') resource rgbu0001a0005 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'rg-bu0001a0005' - location: location + location: deploymentResourceRegion } @description('This is the resource group for Azure Network Watchers. Most subscriptions already have this.') resource rgNetworkWatchers 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'networkWatcherRG' - location: empty(networkWatcherRGRegion) ? 'centralus' : networkWatcherRGRegion -} - -@description('Security Admin Role built-in role.') -resource securityAdminRole 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = { - name: 'fb1c8493-542b-48eb-b624-b4c8fea62acd' + location: networkWatcherRGRegion } @description('Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.') @@ -98,7 +97,7 @@ resource pdEnableAksDefender 'Microsoft.Authorization/policyDefinitions@2021-06- equals: 'Standard' } deployment: { - location: location + location: deploymentResourceRegion properties: { mode: 'incremental' template: { @@ -159,7 +158,7 @@ resource pdEnableAkvDefender 'Microsoft.Authorization/policyDefinitions@2021-06- equals: 'Standard' } deployment: { - location: location + location: deploymentResourceRegion properties: { mode: 'incremental' template: { @@ -427,7 +426,7 @@ module defenderPolicyDeployment 'modules/subscriptionPolicyAssignment.bicep' = { name: 'Apply-EnableDefender-Policy' scope: subscription() params: { - location: location + location: deploymentResourceRegion policyAssignmentIdentity: { type: 'SystemAssigned' } @@ -470,7 +469,7 @@ resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if ( resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'Arm' properties: { - pricingTier: 'Standard' + pricingTier: 'Standard' // Isn't included in the Azure Policy applications above. } } @@ -478,6 +477,6 @@ resource enableArm 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosof resource enableDns 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'Dns' properties: { - pricingTier: 'Standard' + pricingTier: 'Standard' // Isn't included in the Azure Policy applications above. } } From 499a08b614f410256f5c46033c6fe60ccb7abd37 Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Tue, 19 Apr 2022 16:42:00 -0300 Subject: [PATCH 11/17] Update subscription.bicep Co-authored-by: Chad Kittel --- subscription.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subscription.bicep b/subscription.bicep index bd344df4..c2207027 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -457,7 +457,7 @@ resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if ( } } -@description('Enable Microsoft Defender Standard for Kubernetes Service. Requires Owner or Security Admin role.') +@description('Enable Microsoft Defender for Kubernetes Service. Deprecated, please move to Defender for Containers. Requires Owner or Security Admin role.') resource enableKubernetesService 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'KubernetesService' properties: { From 1447e4a40f18c736985dbdc0a44f79ee0cc48b63 Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Tue, 19 Apr 2022 16:42:10 -0300 Subject: [PATCH 12/17] Update subscription.bicep Co-authored-by: Chad Kittel --- subscription.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subscription.bicep b/subscription.bicep index c2207027..1d884a6b 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -449,7 +449,7 @@ resource enableKeyVaultspricing 'Microsoft.Security/pricings@2018-06-01' = if (e } } -@description('Enable Microsoft Defender Standard for Container Registry. Requires Owner or Security Admin role.') +@description('Enable Microsoft Defender Standard for Container Registry. Deprecated, please move to Defender for Containers. Requires Owner or Security Admin role.') resource enableContainerRegistry 'Microsoft.Security/pricings@2018-06-01' = if (enableMicrosoftDefenderForCloud) { name: 'ContainerRegistry' properties: { From 7e3518db4f2f5e2683c772733fd698cdf72590e0 Mon Sep 17 00:00:00 2001 From: magrande Date: Tue, 19 Apr 2022 16:52:41 -0300 Subject: [PATCH 13/17] Some more usage of existing resources --- modules/hubsPoliciesDeployment.bicep | 18 ++++++++++++++++-- .../networkWatchersPoliciesDeployment.bicep | 10 +++++++++- modules/spokesPoliciesDeployment.bicep | 18 ++++++++++++++++-- modules/subscriptionPolicyAssignment.bicep | 5 ++++- modules/workloadPoliciesDeployment.bicep | 1 - 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/modules/hubsPoliciesDeployment.bicep b/modules/hubsPoliciesDeployment.bicep index 3f75eda6..447dab39 100644 --- a/modules/hubsPoliciesDeployment.bicep +++ b/modules/hubsPoliciesDeployment.bicep @@ -1,5 +1,19 @@ targetScope = 'resourceGroup' +/*** EXISTING RESOURCES ***/ + +@description('Allowed resource types - Policy definition') +resource allowedResourceTypespolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + scope: subscription() +} + +@description('Network Watcher should be enabled - Policy Definition') +resource NetworkWatcherShouldBeEnabledPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + scope: subscription() +} + /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the hubs RG to only allow select networking and observation resources.') @@ -8,7 +22,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + policyDefinitionName: allowedResourceTypespolicyDefinition.name policyAssignmentDescription: 'List of supported resources for our enterprise hubs resource group' policyAssignmentParameters: { listOfResourceTypesAllowed: { @@ -40,7 +54,7 @@ module NetworkWatcherShouldBeEnabledPolicyAssignment 'resourceGroupPolicyAssignm scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + policyDefinitionName: NetworkWatcherShouldBeEnabledPolicyDefinition.name policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Hub resource group.' } } diff --git a/modules/networkWatchersPoliciesDeployment.bicep b/modules/networkWatchersPoliciesDeployment.bicep index 1e75f49c..99cf9536 100644 --- a/modules/networkWatchersPoliciesDeployment.bicep +++ b/modules/networkWatchersPoliciesDeployment.bicep @@ -1,5 +1,13 @@ targetScope = 'resourceGroup' +/*** EXISTING RESOURCES ***/ + +@description('Allowed resource types - Policy definition') +resource allowedResourceTypespolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + scope: subscription() +} + /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the network watchers resource group to only allow select networking resources.') @@ -8,7 +16,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + policyDefinitionName: allowedResourceTypespolicyDefinition.name policyAssignmentDescription: 'List of supported resources for our Network Watcher resource group' policyAssignmentEnforcementMode: 'DoNotEnforce' // Since this RG may be under existing policy control in your subscription, adding this policy as audit-only. policyAssignmentParameters: { diff --git a/modules/spokesPoliciesDeployment.bicep b/modules/spokesPoliciesDeployment.bicep index 8ca70b6b..bd015fd9 100644 --- a/modules/spokesPoliciesDeployment.bicep +++ b/modules/spokesPoliciesDeployment.bicep @@ -1,5 +1,19 @@ targetScope = 'resourceGroup' + +@description('Allowed resource types - Policy definition') +resource allowedResourceTypespolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + scope: subscription() +} + +@description('Network Watcher should be enabled - Policy Definition') +resource NetworkWatcherShouldBeEnabledPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { + name: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + scope: subscription() +} + + /*** RESOURCES ***/ @description('Allowed Resources Policy applied to the spokes RG to only allow select networking and observation resources.') @@ -8,7 +22,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + policyDefinitionName: allowedResourceTypespolicyDefinition.name policyAssignmentDescription: 'List of supported resources for our enterprise spokes resource group' policyAssignmentParameters: { listOfResourceTypesAllowed: { @@ -33,7 +47,7 @@ module NetworkWatcherShouldBeEnabledPolicyAssignment 'resourceGroupPolicyAssignm scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'b6e2945c-0b7b-40f5-9233-7a5323b5cdc6' + policyDefinitionName: NetworkWatcherShouldBeEnabledPolicyDefinition.name policyAssignmentDescription: 'Applying the \'Network Watcher Should be Enabled\' policy to the Spoke resource group.' } } diff --git a/modules/subscriptionPolicyAssignment.bicep b/modules/subscriptionPolicyAssignment.bicep index 728cd488..3b29b580 100644 --- a/modules/subscriptionPolicyAssignment.bicep +++ b/modules/subscriptionPolicyAssignment.bicep @@ -23,13 +23,16 @@ param polcyAssignmentMetadata object = {} @description('The policy\'s excluded scopes') param notScopes array = [] -/*** RESOURCES ***/ +/*** EXISTING RESOURCES ***/ +@description('Existing policy definition') resource policyDefintion 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: policyDefinitionName scope: subscription() } +/*** RESOURCES ***/ + @description('Assignment of policy') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { name: guid(policyDefintion.name, subscription().id) diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index a64441ab..5095c779 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -29,7 +29,6 @@ resource DenyAksWithoutRbacPolicyDefinition 'Microsoft.Authorization/policyDefin scope: subscription() } - @description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') resource DenyOldAksPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: 'fb893a29-21bb-418c-a157-e99480ec364c' From e2b66300ff1f174aaa88cfc21bbbf09b47160a4a Mon Sep 17 00:00:00 2001 From: magrande Date: Wed, 20 Apr 2022 12:05:19 -0300 Subject: [PATCH 14/17] refactored custom-builtin policy assignments --- modules/resourceGroupPolicyAssignment.bicep | 22 +++++-- modules/subscriptionPolicyAssignment.bicep | 47 +++++++-------- modules/workloadPoliciesDeployment.bicep | 65 +++++++++------------ subscription.bicep | 8 +-- 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/modules/resourceGroupPolicyAssignment.bicep b/modules/resourceGroupPolicyAssignment.bicep index 92a675de..4fc3380d 100644 --- a/modules/resourceGroupPolicyAssignment.bicep +++ b/modules/resourceGroupPolicyAssignment.bicep @@ -6,36 +6,46 @@ targetScope = 'resourceGroup' param builtIn bool = true @description('The name of the policy to assign.') +@minLength(36) +@maxLength(36) param policyDefinitionName string @description('The description of the policy assignment.') -param policyAssignmentDescription string = '' +@minLength(1) +param policyAssignmentDescription string @description('The he policy assignment\'s parameters') param policyAssignmentParameters object = {} @description('This property provides the ability to test the outcome of a policy on existing resources without initiating the policy effect or triggering entries in the Azure Activity log') +@allowed([ + 'Default' + 'DoNotEnforce' +]) param policyAssignmentEnforcementMode string = 'Default' /*** EXISTING RESOURCES ***/ -resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { +resource customPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { name: policyDefinitionName scope: subscription() } +/*** VARIABLES ***/ + +var builtInPolicyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinitionName}' + /*** RESOURCES ***/ @description('Assigns a Policy at Resource Group level') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid( builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}': policyDefinition.name, resourceGroup().name) + name: guid( builtIn ? builtInPolicyDefinitionId : customPolicyDefinition.id, resourceGroup().name) scope: resourceGroup() properties: { - displayName: builtIn ? trim(take('[${resourceGroup().name}] ${reference('/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}', '2020-09-01').displayName}', 125)) : trim(take('[${resourceGroup().name}] ${reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinition.id), '2020-09-01').displayName}', 125)) + displayName: trim(take('[${resourceGroup().name}] ${ builtIn ? reference(builtInPolicyDefinitionId, '2021-06-01').displayName : customPolicyDefinition.properties.displayName }', 125)) description: policyAssignmentDescription - policyDefinitionId: builtIn ? '/providers/Microsoft.Authorization/policyDefinitions/${policyDefinition.id}' : subscriptionResourceId('Microsoft.Authorization/policyDefinitions', policyDefinition.name) + policyDefinitionId: builtIn ? builtInPolicyDefinitionId : customPolicyDefinition.id parameters: policyAssignmentParameters enforcementMode: policyAssignmentEnforcementMode } } - diff --git a/modules/subscriptionPolicyAssignment.bicep b/modules/subscriptionPolicyAssignment.bicep index 3b29b580..75c12330 100644 --- a/modules/subscriptionPolicyAssignment.bicep +++ b/modules/subscriptionPolicyAssignment.bicep @@ -3,46 +3,47 @@ targetScope = 'subscription' /*** PARAMETERS ***/ @description('The policy assignment enforcement mode.') +@allowed([ + 'Default' + 'DoNotEnforce' +]) param enforcementMode string = 'Default' -@description('Subsription deployment\'s main location (centralus if not specified)') +@description('Subsription deployment\'s main location.') +@minLength(4) param location string -@description('The name of the policy or policy set to assign.') -param policyDefinitionName string +@description('The name of the policy set to assign.') +@minLength(36) +@maxLength(36) +param policyDefinitionSetName string -@description('This object contains the type of policy assignment identity') -param policyAssignmentIdentity object = {} +@description('The desciption of the policy assignment.') +@minLength(1) +param policyAssignmentDescription string -@description('The desciption of the policy assignment') -param policyAssignmentDescription string = '' - -@description('Policy assignment metadata; this parameter can by any object') +@description('Policy assignment metadata; this parameter can by any object.') param polcyAssignmentMetadata object = {} -@description('The policy\'s excluded scopes') -param notScopes array = [] - -/*** EXISTING RESOURCES ***/ +/*** VARIABLES ***/ -@description('Existing policy definition') -resource policyDefintion 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: policyDefinitionName - scope: subscription() -} +var builtIntPolicyDefinitionSetId = subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefinitionSetName) /*** RESOURCES ***/ @description('Assignment of policy') resource policyAssignment 'Microsoft.Authorization/policyAssignments@2021-06-01' = { - name: guid(policyDefintion.name, subscription().id) - identity: policyAssignmentIdentity + name: guid(builtIntPolicyDefinitionSetId) + identity: { + type: 'SystemAssigned' + } location: location + scope: subscription() properties: { - displayName: reference(subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name), '2020-09-01').displayName + displayName: reference(builtIntPolicyDefinitionSetId, '2021-06-01').displayName description: policyAssignmentDescription - notScopes: notScopes - policyDefinitionId: subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', policyDefintion.name) + notScopes: [] + policyDefinitionId: builtIntPolicyDefinitionSetId enforcementMode: enforcementMode metadata: polcyAssignmentMetadata } diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index 5095c779..056fafb5 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -1,5 +1,25 @@ targetScope = 'resourceGroup' +/*** VARIABLES ***/ + +@description('Role-Based Access Control (RBAC) should be used on Kubernetes Services - Policy definition.') +var denyAksWithoutRbacPolicyDefinitionName = 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' + +@description('Only support the a list of resources for our workload resource group - Policy definition.') +var allowedResourcespolicyAssignmentName = 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + +@description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') +var DenyAksWithoutPolicyPolicyDefinitionName = '0a15ec92-a229-4763-bb14-0ea34a568f8d' + +@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') +var DenyOldAksPolicyDefinitionName = 'fb893a29-21bb-418c-a157-e99480ec364c' + +@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') +var CustomerManagedEncryptionPolicyDefinitionName = '7d7be79c-23ba-4033-84dd-45e2a5ccdd67' + +@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy definition') +var EncryptionAtHostPolicyDefinitionName = '41425d9f-d1a5-499a-9932-f8ed8453932c' + /*** EXISTING RESOURCES ***/ resource pdDenyPublicAks 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { @@ -23,30 +43,6 @@ resource pdDenyAagWithoutWaf 'Microsoft.Authorization/policyDefinitions@2021-06- scope: subscription() } -@description('Role-Based Access Control (RBAC) should be used on Kubernetes Services - Policy definition.') -resource DenyAksWithoutRbacPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' - scope: subscription() -} - -@description('Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version - Policy definition') -resource DenyOldAksPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: 'fb893a29-21bb-418c-a157-e99480ec364c' - scope: subscription() -} - -@description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') -resource DenyAksWithoutPolicyPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: '0a15ec92-a229-4763-bb14-0ea34a568f8d' - scope: subscription() -} - -@description('Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host - Policy definition') -resource EncryptionAtHostPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: '41425d9f-d1a5-499a-9932-f8ed8453932c' - scope: subscription() -} - /*** RESOURCES ***/ @description('Only support the a list of resources for our workload resource group - Policy assignment') @@ -55,7 +51,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: 'a08ec900-254a-4555-9bf5-e42af04b5c5c' + policyDefinitionName: allowedResourcespolicyAssignmentName policyAssignmentDescription: 'List of supported resources for our workload resource group' policyAssignmentParameters: { listOfResourceTypesAllowed: { @@ -117,6 +113,7 @@ module NoPublicIPsForVMScaleSetsPolicyAssignment 'resourceGroupPolicyAssignment. params: { builtIn: false policyDefinitionName: pdNoPublicIPsForVMScaleSets.name + policyAssignmentDescription: '\'No Public IPs on VMSS\' policy applied to the workload resource group.' } } @@ -126,7 +123,7 @@ module DenyAksWithoutPolicyPolicyAssignment 'resourceGroupPolicyAssignment.bicep scope: resourceGroup() params: { builtIn: true - policyDefinitionName: DenyAksWithoutPolicyPolicyDefinition.name + policyDefinitionName: DenyAksWithoutPolicyPolicyDefinitionName policyAssignmentDescription: 'Only support AKS clusters with Azure Policy enabled, deny any other.' } } @@ -148,7 +145,7 @@ module DenyAksWithoutRbacPolicyAssignment 'resourceGroupPolicyAssignment.bicep' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: DenyAksWithoutRbacPolicyDefinition.name + policyDefinitionName: denyAksWithoutRbacPolicyDefinitionName policyAssignmentDescription: 'Only allow AKS with RBAC support enabled.' } } @@ -159,24 +156,19 @@ module DenyOldAksPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { scope: resourceGroup() params: { builtIn: true - policyDefinitionName: DenyOldAksPolicyDefinition.name + policyDefinitionName: DenyOldAksPolicyDefinitionName policyAssignmentDescription: 'Disallow older AKS versions.' } } -@description('Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys - Policy definition') -resource CustomerManagedEncryptionPolicyDefinition 'Microsoft.Authorization/policyDefinitions@2021-06-01' existing = { - name: '7d7be79c-23ba-4033-84dd-45e2a5ccdd67' - scope: subscription() -} - @description('\'Customer-Managed Disk Encryption\' applied to resource group - Policy Assignment.') module CustomerManagedEncryptionPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = { name: 'Workload-CustomerManagedEncryptionPolicyAssignment' scope: resourceGroup() params: { builtIn: true - policyDefinitionName: CustomerManagedEncryptionPolicyDefinition.name + policyDefinitionName: CustomerManagedEncryptionPolicyDefinitionName + policyAssignmentDescription: '\'Customer-Managed Disk Encryption\' applied to resource group' } } @@ -186,6 +178,7 @@ module EncryptionAtHostPolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: EncryptionAtHostPolicyDefinition.name + policyDefinitionName: EncryptionAtHostPolicyDefinitionName + policyAssignmentDescription: 'Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host' } } diff --git a/subscription.bicep b/subscription.bicep index 1d884a6b..0759aa14 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -50,7 +50,7 @@ resource rgSpokes 'Microsoft.Resources/resourceGroups@2021-04-01' = { } @description('This is the resource group for BU001A0005. Typically this would be found in your workload\'s subscription.') -resource rgbu0001a0005 'Microsoft.Resources/resourceGroups@2021-04-01' = { +resource rgbu0001a0005 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'rg-bu0001a0005' location: deploymentResourceRegion } @@ -427,17 +427,13 @@ module defenderPolicyDeployment 'modules/subscriptionPolicyAssignment.bicep' = { scope: subscription() params: { location: deploymentResourceRegion - policyAssignmentIdentity: { - type: 'SystemAssigned' - } polcyAssignmentMetadata: { version: '1.0.0' category: 'Microsoft Defender for Cloud' } - policyDefinitionName: psdEnableDefender.name + policyDefinitionSetName: psdEnableDefender.name policyAssignmentDescription: 'Ensures that Microsoft Defender for Kuberentes Service, Container Service, and Key Vault are enabled.' enforcementMode: enforceAzureDefenderAutoDeployPolicies ? 'Default' : 'DoNotEnforce' - notScopes: [] } } From 028c892fe3c0a03310e9c210931dab44519c4ddb Mon Sep 17 00:00:00 2001 From: Mariano Grande Date: Thu, 21 Apr 2022 17:08:55 -0300 Subject: [PATCH 15/17] Update modules/workloadPoliciesDeployment.bicep Co-authored-by: Chad Kittel --- modules/workloadPoliciesDeployment.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index 056fafb5..d8199052 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -6,7 +6,7 @@ targetScope = 'resourceGroup' var denyAksWithoutRbacPolicyDefinitionName = 'ac4a19c2-fa67-49b4-8ae5-0b2e78c49457' @description('Only support the a list of resources for our workload resource group - Policy definition.') -var allowedResourcespolicyAssignmentName = 'a08ec900-254a-4555-9bf5-e42af04b5c5c' +var allowedResourcesPolicyAssignmentName = 'a08ec900-254a-4555-9bf5-e42af04b5c5c' @description('Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters - Policy definition') var DenyAksWithoutPolicyPolicyDefinitionName = '0a15ec92-a229-4763-bb14-0ea34a568f8d' From c61866e89815d58413c80e2af82fa601b182e5b3 Mon Sep 17 00:00:00 2001 From: magrande Date: Fri, 22 Apr 2022 10:56:06 -0300 Subject: [PATCH 16/17] Adding dependencies on workloadPolicies deployment, and other bugs fixed --- docs/deploy/04-subscription.md | 2 +- modules/workloadPoliciesDeployment.bicep | 2 +- subscription.bicep | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/deploy/04-subscription.md b/docs/deploy/04-subscription.md index fdd27c9a..d0363afe 100644 --- a/docs/deploy/04-subscription.md +++ b/docs/deploy/04-subscription.md @@ -105,7 +105,7 @@ Not only do we enable them in the steps below by default, but also set up an Azu ```bash # [This may take up to five minutes to run.] - az deployment sub create -f subscription.bicep -l centralus -p enableAzureDefender=false enforceAzureDefenderAutoDeployPolicies=false networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" + az deployment sub create -f subscription.bicep -l centralus -p enableMicrosoftDefenderForCloud=false enforceAzureDefenderAutoDeployPolicies=false networkWatcherRGRegion="${NETWORK_WATCHER_RG_REGION}" ``` ## Azure Security Benchmark diff --git a/modules/workloadPoliciesDeployment.bicep b/modules/workloadPoliciesDeployment.bicep index d8199052..36b615b4 100644 --- a/modules/workloadPoliciesDeployment.bicep +++ b/modules/workloadPoliciesDeployment.bicep @@ -51,7 +51,7 @@ module allowedResourcespolicyAssignment 'resourceGroupPolicyAssignment.bicep' = scope: resourceGroup() params: { builtIn: true - policyDefinitionName: allowedResourcespolicyAssignmentName + policyDefinitionName: allowedResourcesPolicyAssignmentName policyAssignmentDescription: 'List of supported resources for our workload resource group' policyAssignmentParameters: { listOfResourceTypesAllowed: { diff --git a/subscription.bicep b/subscription.bicep index 0759aa14..dc548569 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -9,7 +9,7 @@ targetScope = 'subscription' - Scope: Subscription Role: Security Admin (or Owner) Reason: To enable Microsoft Defender for Kubernetes, Container Registry, and Key Vault. - Notes: If unable to obtain permissions, you must pass false to the enableAzureDefender parameter or have someone else enable these for you. + Notes: If unable to obtain permissions, you must pass false to the enableMicrosoftDefenderForCloud parameter or have someone else enable these for you. */ /*** PARAMETERS ***/ @@ -58,7 +58,7 @@ resource rgbu0001a0005 'Microsoft.Resources/resourceGroups@2021-04-01' = { @description('This is the resource group for Azure Network Watchers. Most subscriptions already have this.') resource rgNetworkWatchers 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: 'networkWatcherRG' - location: networkWatcherRGRegion + location: empty(networkWatcherRGRegion) ? deploymentResourceRegion : networkWatcherRGRegion } @description('Microsoft Defender for Containers provides real-time threat protection for containerized environments and generates alerts for suspicious activities.') @@ -417,6 +417,12 @@ module networkWatchersPoliciesDeployment 'modules/networkWatchersPoliciesDeploym @description('Workload\'s policies deployment') module workloadPoliciesDeployment 'modules/workloadPoliciesDeployment.bicep' = { + dependsOn:[ + pdDenyPublicAks + pdDenyAksWithoutDefender + pdNoPublicIPsForVMScaleSets + pdDenyAagWithoutWaf + ] name: 'Apply-${rgbu0001a0005.name}-Policies' scope: rgbu0001a0005 } From 821a94f5ecb3a747da04d8085e974c91eff52258 Mon Sep 17 00:00:00 2001 From: Chad Kittel Date: Fri, 22 Apr 2022 12:03:16 -0500 Subject: [PATCH 17/17] Update subscription.bicep --- subscription.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subscription.bicep b/subscription.bicep index dc548569..40efb962 100644 --- a/subscription.bicep +++ b/subscription.bicep @@ -417,7 +417,7 @@ module networkWatchersPoliciesDeployment 'modules/networkWatchersPoliciesDeploym @description('Workload\'s policies deployment') module workloadPoliciesDeployment 'modules/workloadPoliciesDeployment.bicep' = { - dependsOn:[ + dependsOn: [ pdDenyPublicAks pdDenyAksWithoutDefender pdNoPublicIPsForVMScaleSets