Skip to content

Commit

Permalink
Enhancement to warn on deprecated policies
Browse files Browse the repository at this point in the history
  • Loading branch information
apybar committed Jun 21, 2024
1 parent ee3f2fb commit 364db53
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 64 deletions.
5 changes: 5 additions & 0 deletions Docs/settings-desired-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ Desired State strategy enables you to adjust the default behavior to fit more co
- `full`: EPAC manages all Policy resources in the `deploymentRootScope` and its children. EPAC deletes any Policy resources not defined in the EPAC repo.
- `ownedOnly`: EPAC manages only Policy resources defined in the EPAC repo. EPAC does not delete any Policy resources not defined in the EPAC repo.
- `keepDfcSecurityAssignments`: It is recommended that Security and Compliance Initiatives are managed at management group levels with EPAC. Please read [Managing Defender for Cloud Assignments](settings-dfc-assignments.md).

- Optional:
- `excludedScopes`: An array of scopes to exclude from management by EPAC. The default is an empty array. Wild cards are supported.
- `excludedPolicyDefinitions`: An array of Policy Definitions to exclude from management by EPAC. The default is an empty array. Wild cards are supported.
- `excludedPolicySetDefinitions`: An array of Policy Set Definitions to exclude from management by EPAC. The default is an empty array. Wild cards are supported.
- `excludedPolicyAssignments`: An array of Policy Assignments to exclude from management by EPAC. The default is an empty array. Wild cards are supported.
- `doNotDisableDeprecatedPolicies`: Automatically set deprecated policies' policy effect to "Disabled"

The following example shows the `desiredState` element with all properties set:

```json
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false,
"excludedScopes": [],
"excludedPolicyDefinitions": [],
"excludedPolicySetDefinitions": [],
Expand Down Expand Up @@ -148,6 +151,8 @@ You can exclude any combination of `excludedScopes`, `excludedPolicyDefinitions`
```json
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false,
"excludedScopes": [ // Management Groups, Subscriptions, Resource Groups
"/providers/Microsoft.Management/managementGroups/mg-policy-as-code/childScope"
],
Expand Down
15 changes: 10 additions & 5 deletions Docs/settings-global-setting-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Epac-Dev",
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false
},
"managedIdentityLocation": "eastus2"
},
Expand All @@ -33,7 +34,8 @@
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/mg-Enterprise",
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false
},
"managedIdentityLocation": "eastus2",
"globalNotScopes": [
Expand Down Expand Up @@ -146,7 +148,8 @@ Resource Group patterns allow us to exclude "special" managed Resource Groups. T
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/PAC-Heinrich-Dev",
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false
},
"mangedIdentityLocation": "eastus2"
},
Expand All @@ -157,7 +160,8 @@ Resource Group patterns allow us to exclude "special" managed Resource Groups. T
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root",
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false
},
"globalNotScopes": [
"/providers/Microsoft.Management/managementGroups/PAC-Heinrich-Dev"
Expand All @@ -178,7 +182,8 @@ Resource Group patterns allow us to exclude "special" managed Resource Groups. T
"deploymentRootScope": "/providers/Microsoft.Management/managementGroups/Contoso-Root",
"desiredState": {
"strategy": "full",
"keepDfcSecurityAssignments": false
"keepDfcSecurityAssignments": false,
"doNotDisableDeprecatedPolicies": false
},
"managedIdentityLocation": "eastus2"
}
Expand Down
3 changes: 3 additions & 0 deletions Schemas/global-settings-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
"keepDfcSecurityAssignments": {
"type": "boolean"
},
"doNotDisableDeprecatedPolicies": {
"type": "boolean"
},
"excludedScopes": {
"type": "array",
"items": [
Expand Down
62 changes: 61 additions & 1 deletion Scripts/Helpers/Build-AssignmentDefinitionNode.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ function Build-AssignmentDefinitionNode {
}
#endregion definitionEntry or definitionEntryList (required exactly once per branch)

#region Process Deprecated
$deprecatedHash = @{}
foreach ($key in $CombinedPolicyDetails.policies.keys) {
if ($true -eq $CombinedPolicyDetails.policies.$key.isDeprecated) {
$deprecatedHash[$CombinedPolicyDetails.policies.$key.name] = $CombinedPolicyDetails.policies.$key
}
}

#region metadata
if ($DefinitionNode.metadata) {
# merge metadata
Expand All @@ -166,13 +174,36 @@ function Build-AssignmentDefinitionNode {
#endregion metadata

#region parameters in JSON; parameters defined at a deeper level override previous parameters (union operator)

# create parameter Hash to Policy Def
$parameterHash = @{}
foreach ($key in $flatPolicyList.keys) {
foreach ($paramKey in $flatPolicyList.$key.parameters.keys) {
$parameterHash.$paramKey = $flatPolicyList.$key
}
}

$deprecatedInJSON = [System.Collections.ArrayList]::new()
if ($DefinitionNode.parameters) {
$allParameters = $definition.parameters
$addedParameters = $DefinitionNode.parameters
foreach ($parameterName in $addedParameters.Keys) {
$rawParameterValue = $addedParameters.$parameterName
$currentParameterHash = $parameterHash.$parameterName
if ($deprecatedHash.ContainsKey($($currentParameterHash.name)) -and $currentParameterHash.parameters.$parameterName.isEffect) {
$null = $deprecatedInJSON.Add("Assignment: '$($assignment.name)' with Parameter: '$parameterName' ($($currentParameterHash))")
if (!$PacEnvironment.desiredState.doNotDisableDeprecatedPolicies) {
$rawParameterValue = "Disabled"
}
}
$parameterValue = Get-DeepCloneAsOrderedHashtable $rawParameterValue
$allParameters[$parameterName] = $parameterValue
$allParameters.$parameterName = $parameterValue
}
}
if ($deprecatedInJSON.Count -gt 0) {
Write-Warning "Node $($nodeName): Assignment contains JSON effect parameter for Policies that has been deprecated in the Policy Sets. Update Policy Sets."
foreach ($deprecated in $deprecatedInJSON) {
Write-Information " $($deprecated)"
}
}
#endregion parameters in JSON; parameters defined at a deeper level override previous parameters (union operator)
Expand All @@ -184,13 +215,36 @@ function Build-AssignmentDefinitionNode {
$definition.effectColumn = "$($parameterSelector)Effect"
$definition.parametersColumn = "$($parameterSelector)Parameters"
}
$deprecatedInCSV = [System.Collections.ArrayList]::new()
if ($DefinitionNode.parameterFile) {
$parameterFileName = $DefinitionNode.parameterFile
if ($ParameterFilesCsv.ContainsKey($parameterFileName)) {
$fullName = $ParameterFilesCsv.$parameterFileName
$content = Get-Content -Path $fullName -Raw -ErrorAction Stop
$xlsArray = @() + ($content | ConvertFrom-Csv -ErrorAction Stop)
$csvParameterArray = Get-DeepCloneAsOrderedHashtable $xlsArray
# Replace CSV effect with Disabled if Deprecated
foreach ($entry in $csvParameterArray) {
# If policy in csv is found to be deprecated
if ($deprecatedHash.ContainsKey($entry.name)) {
# For each child in the assignment
foreach ($child in $DefinitionNode.children) {
# If that child is using a parameterSelector with the CSV
if ($child.ContainsKey('parameterSelector')) {
$key = "$($child.parameterSelector)" + "Effect"
# If the parameter is not set to Disabled already
if ($entry.$key -ne "Disabled") {
if (!$PacEnvironment.desiredState.doNotDisableDeprecatedPolicies) {
$entry.$key = 'Disabled'
}
$null = $deprecatedInCSV.Add("$($entry.displayName) ($($entry.name))")
}
}
}
break
}
}

$definition.parameterFileName = $parameterFileName
$definition.csvParameterArray = $csvParameterArray
$definition.csvRowsValidated = $false
Expand Down Expand Up @@ -272,6 +326,12 @@ function Build-AssignmentDefinitionNode {
Write-Information " $($missing)"
}
}
if ($deprecatedInCSV.Count -gt 0) {
Write-Warning "Node $($nodeName): CSV parameterFile '$parameterFileName' contains rows for Policies that have been deprecated in the Policy Sets. Update Policy Sets."
foreach ($deprecated in $deprecatedInCSV) {
Write-Information " $($deprecated)"
}
}
}
#endregion validate CSV rows

Expand Down
10 changes: 10 additions & 0 deletions Scripts/Helpers/Get-GlobalSettings.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ function Get-GlobalSettings {
excludedPolicyDefinitions = @()
excludedPolicySetDefinitions = @()
excludedPolicyAssignments = @()
doNotDisableDeprecatedPolicies = $false
}

$desired = $pacEnvironment.desiredState
Expand Down Expand Up @@ -311,6 +312,15 @@ function Get-GlobalSettings {
if ($null -ne $deleteOrphaned) {
Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "Global settings error: pacEnvironment $pacSelector field desiredState.deleteOrphanedExemptions is deprecated. Remove it!"
}
$doNotDisableDeprecatedPolicies = $desired.doNotDisableDeprecatedPolicies
if ($null -ne $doNotDisableDeprecatedPolicies) {
if ($doNotDisableDeprecatedPolicies -is [bool]) {
$desiredState.doNotDisableDeprecatedPolicies = $doNotDisableDeprecatedPolicies
}
else {
Add-ErrorMessage -ErrorInfo $errorInfo -ErrorString "Global settings error: pacEnvironment $pacSelector field desiredState.doNotDisableDeprecatedPolicies ($doNotDisableDeprecatedPolicies) must be a boolean value."
}
}
}

$pacEnvironmentDefinition = @{
Expand Down
122 changes: 66 additions & 56 deletions Scripts/Helpers/Out-DocumentationForPolicyAssignments.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ function Out-DocumentationForPolicyAssignments {
[switch] $WindowsNewLineCells,
$DocumentationSpecification,
[hashtable] $AssignmentsByEnvironment,
[switch] $IncludeManualPolicies
[switch] $IncludeManualPolicies,
[bool] $doNotDisableDeprecatedPolicies
)

[string] $fileNameStem = $DocumentationSpecification.fileNameStem
Expand Down Expand Up @@ -150,6 +151,13 @@ function Out-DocumentationForPolicyAssignments {
}
}

#region Process Deprecated
$deprecatedHash = @{}
foreach ($key in $CombinedPolicyDetails.policies.keys) {
if ($true -eq $CombinedPolicyDetails.policies.$key.isDeprecated) {
$deprecatedHash[$CombinedPolicyDetails.policies.$key.name] = $CombinedPolicyDetails.policies.$key
}
}
#region Review Duplicates

# Iterate over each key-value pair in the hashtable
Expand Down Expand Up @@ -441,67 +449,69 @@ function Out-DocumentationForPolicyAssignments {

# Process the table
$flatPolicyListAcrossEnvironments.Values | Sort-Object -Property { $_.category }, { $_.displayName } | ForEach-Object -Process {
# If statement to skip over duplicates
# If statement to skip over duplicates and ensure not to include Deprecated Policies
if ( $true -ne $_.isReferencePathMatch) {
# Initialize row - with empty strings
$rowObj = [ordered]@{}
foreach ($key in $columnHeaders) {
$null = $rowObj.Add($key, "")
}
if (!$deprecatedHash.ContainsKey($_.name) -or $doNotDisableDeprecatedPolicies) {
# Initialize row - with empty strings
$rowObj = [ordered]@{}
foreach ($key in $columnHeaders) {
$null = $rowObj.Add($key, "")
}

# Cache loop values
# $effectAllowedValues = $_.effectAllowedValues
# $groupNames = $_.groupNames
# $policySetEffectStrings = $_.policySetEffectStrings
$effectAllowedValues = $_.effectAllowedValues
$isEffectParameterized = $_.isEffectParameterized
$effectAllowedOverrides = $_.effectAllowedOverrides
$groupNames = $_.groupNames
$effectDefault = $_.effectDefault
$policySetEffectStrings = $_.policySetEffectStrings

# Build common columns
$rowObj.name = $_.name
$rowObj.referencePath = $_.referencePath
$rowObj.policyType = $_.policyType
$rowObj.category = $_.category
$rowObj.displayName = $_.displayName
$rowObj.description = $_.description
$groupNames = $_.groupNames
if ($groupNames.Count -gt 0) {
$sortedGroupNameList = $groupNames | Sort-Object -Unique
$rowObj.groupNames = $sortedGroupNameList -join $inCellSeparator3
}
if ($policySetEffectStrings.Count -gt 0) {
$rowObj.policySets = $policySetEffectStrings -join $inCellSeparator3
}
$rowObj.allowedEffects = Convert-AllowedEffectsToCsvString `
-DefaultEffect $effectDefault `
-IsEffectParameterized $isEffectParameterized `
-EffectAllowedValues $effectAllowedValues.Keys `
-EffectAllowedOverrides $effectAllowedOverrides `
-InCellSeparator1 $inCellSeparator1 `
-InCellSeparator2 $inCellSeparator2
# Cache loop values
# $effectAllowedValues = $_.effectAllowedValues
# $groupNames = $_.groupNames
# $policySetEffectStrings = $_.policySetEffectStrings
$effectAllowedValues = $_.effectAllowedValues
$isEffectParameterized = $_.isEffectParameterized
$effectAllowedOverrides = $_.effectAllowedOverrides
$groupNames = $_.groupNames
$effectDefault = $_.effectDefault
$policySetEffectStrings = $_.policySetEffectStrings

# Build common columns
$rowObj.name = $_.name
$rowObj.referencePath = $_.referencePath
$rowObj.policyType = $_.policyType
$rowObj.category = $_.category
$rowObj.displayName = $_.displayName
$rowObj.description = $_.description
$groupNames = $_.groupNames
if ($groupNames.Count -gt 0) {
$sortedGroupNameList = $groupNames | Sort-Object -Unique
$rowObj.groupNames = $sortedGroupNameList -join $inCellSeparator3
}
if ($policySetEffectStrings.Count -gt 0) {
$rowObj.policySets = $policySetEffectStrings -join $inCellSeparator3
}
$rowObj.allowedEffects = Convert-AllowedEffectsToCsvString `
-DefaultEffect $effectDefault `
-IsEffectParameterized $isEffectParameterized `
-EffectAllowedValues $effectAllowedValues.Keys `
-EffectAllowedOverrides $effectAllowedOverrides `
-InCellSeparator1 $inCellSeparator1 `
-InCellSeparator2 $inCellSeparator2

$environmentList = $_.environmentList
# Build environmentCategory columns
foreach ($environmentCategory in $environmentCategories) {
if ($environmentList.ContainsKey($environmentCategory)) {
$perEnvironment = $environmentList.$environmentCategory
if ($null -ne $perEnvironment.effectValue) {
$rowObj["$($environmentCategory)Effect"] = Convert-EffectToCsvString $perEnvironment.effectValue
}
else {
$rowObj["$($environmentCategory)Effect"] = Convert-EffectToCsvString $_.effectDefault
}
$environmentList = $_.environmentList
# Build environmentCategory columns
foreach ($environmentCategory in $environmentCategories) {
if ($environmentList.ContainsKey($environmentCategory)) {
$perEnvironment = $environmentList.$environmentCategory
if ($null -ne $perEnvironment.effectValue) {
$rowObj["$($environmentCategory)Effect"] = Convert-EffectToCsvString $perEnvironment.effectValue
}
else {
$rowObj["$($environmentCategory)Effect"] = Convert-EffectToCsvString $_.effectDefault
}

$text = Convert-ParametersToString -Parameters $perEnvironment.parameters -OutputType "csvValues"
$rowObj["$($environmentCategory)Parameters"] = $text
$text = Convert-ParametersToString -Parameters $perEnvironment.parameters -OutputType "csvValues"
$rowObj["$($environmentCategory)Parameters"] = $text
}
}
}

# Add row to spreadsheet
$null = $allRows.Add($rowObj)
# Add row to spreadsheet
$null = $allRows.Add($rowObj)
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions Scripts/Operations/Build-PolicyDocumentation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,9 @@ foreach ($file in $files) {
}
)
}

# Build documents
$doNotDisableDeprecatedPolicies = $pacEnvironments[$($globalSettings.pacEnvironmentPrompt)].'doNotDisableDeprecatedPolicies'
$documentationSpecifications = $documentAssignments.documentationSpecifications
foreach ($documentationSpecification in $documentationSpecifications) {
$documentationType = $documentationSpecification.type
Expand All @@ -312,7 +313,8 @@ foreach ($file in $files) {
-WindowsNewLineCells:$WindowsNewLineCells `
-DocumentationSpecification $documentationSpecification `
-AssignmentsByEnvironment $assignmentsByEnvironment `
-IncludeManualPolicies:$IncludeManualPolicies
-IncludeManualPolicies:$IncludeManualPolicies `
-doNotDisableDeprecatedPolicies:$doNotDisableDeprecatedPolicies
# Out-DocumentationForPolicyAssignments `
# -OutputPath $outputPath `
# -WindowsNewLineCells:$true `
Expand Down

0 comments on commit 364db53

Please sign in to comment.