Skip to content

Commit

Permalink
Policy Refresh April 2023 (#691)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <[email protected]>
Co-authored-by: Matt White <[email protected]>
  • Loading branch information
3 people authored May 3, 2023
1 parent 1eab11d commit 2467832
Show file tree
Hide file tree
Showing 106 changed files with 5,897 additions and 1,136 deletions.
130 changes: 130 additions & 0 deletions .github/scripts/Invoke-LibraryUpdatePolicyAssignmentArchetypes.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/pwsh

#
# PowerShell Script
# - Update template library in terraform-azurerm-caf-enterprise-scale repository
#

[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter()][String]$AlzToolsPath = "$PWD/enterprise-scale/src/Alz.Tools",
[Parameter()][String]$TargetPath = "$PWD/terraform-azurerm-caf-enterprise-scale",
[Parameter()][String]$SourcePath = "$PWD/enterprise-scale",
[Parameter()][String]$LineEnding = "unix",
[Parameter()][String]$ParserToolUrl = "https://github.com/jaredfholgate/template-parser/releases/download/0.1.18"
)

$ErrorActionPreference = "Stop"

# This script relies on a custom set of classes and functions
# defined within the EnterpriseScaleLibraryTools PowerShell
# module.
Import-Module $AlzToolsPath -ErrorAction Stop

$parserPath = "$TargetPath/.github/scripts"
$parserExe = "Template.Parser.Cli"
if($IsWindows)
{
$parserExe += ".exe"
}

$parser = "$parserPath/$parserExe"

if(!(Test-Path $parser))
{
Write-Information "Downloading Template Parser." -InformationAction Continue
Invoke-WebRequest "$ParserToolUrl/$parserExe" -OutFile $parser
}

# Update the policy assignments if enabled
Write-Information "Updating Policy Assignment Archetypes." -InformationAction Continue

$eslzArmSourcePath = "$SourcePath/eslzArm/eslzArm.json"
$eslzArmParametersSourcePath = "$SourcePath/eslzArm/eslzArm.test.param.json"

$eslzArm = & $parser "-s $eslzArmSourcePath" "-f $eslzArmParametersSourcePath" "-a" | Out-String | ConvertFrom-Json

$policyAssignments = New-Object 'System.Collections.Generic.Dictionary[string,System.Collections.Generic.List[string]]'

foreach($resource in $eslzArm)
{
$scope = $resource.scope
$policyAssignment = $resource.properties.templateLink.uri

if($null -ne $policyAssignment -and $policyAssignment.StartsWith("https://deploymenturi/managementGroupTemplates/policyAssignments/"))
{
$managementGroup = $scope.Split("/")[-1]
$policyAssignmentFileName = $policyAssignment.Split("/")[-1]

if(!($policyAssignmentFileName.StartsWith("fairfax")))
{
if(!($policyAssignments.ContainsKey($managementGroup)))
{
$values = New-Object 'System.Collections.Generic.List[string]'
$values.Add($policyAssignmentFileName)
$policyAssignments.Add($managementGroup, $values)
}
else
{
$policyAssignments[$managementGroup].Add($policyAssignmentFileName)
}
}
}
}

$managementGroupMapping = @{
"testPortal" = "root"
"management" = "management"
"connectivity" = "connectivity"
"corp" = "corp"
"landingzones" = "landing_zones"
"decommissioned" = "decommissioned"
"sandboxes" = "sandboxes"
"identity" = "identity"
"platform" = "platform"
}

$finalPolicyAssignments = New-Object 'System.Collections.Generic.Dictionary[string,System.Collections.Generic.List[string]]'

$policyAssignmentSourcePath = "$SourcePath/eslzArm/managementGroupTemplates/policyAssignments"



foreach($managementGroup in $policyAssignments.Keys)
{
foreach($policyAssignmentFile in $policyAssignments[$managementGroup])
{
$parsedAssignment = & $parser "-s $policyAssignmentSourcePath/$policyAssignmentFile" | Out-String | ConvertFrom-Json
$policyAssignmentName = $parsedAssignment.name

$managementGroupNameFinal = $managementGroupMapping[$managementGroup.Replace("testPortal-", "")]

Write-Information "Got final data for $managementGroupNameFinal and $policyAssignmentName" -InformationAction Continue

if(!($finalPolicyAssignments.ContainsKey($managementGroupNameFinal)))
{
$values = New-Object 'System.Collections.Generic.List[string]'
$values.Add($policyAssignmentName)
$finalPolicyAssignments.Add($managementGroupNameFinal, $values)
}
else
{
$finalPolicyAssignments[$managementGroupNameFinal].Add($policyAssignmentName)
}
}
}

$policyAssignmentTargetPath = "$TargetPath/modules/archetypes/lib/archetype_definitions"

foreach($managementGroup in $finalPolicyAssignments.Keys)
{
$archetypeFilePath = "$policyAssignmentTargetPath/archetype_definition_es_$managementGroup.tmpl.json"
$archetypeJson = Get-Content $archetypeFilePath | ConvertFrom-Json

$archetypeJson.("es_$managementGroup").policy_assignments = @($finalPolicyAssignments[$managementGroup] | Sort-Object)

Write-Information "Writing $archetypeFilePath" -InformationAction Continue
$json = $archetypeJson | ConvertTo-Json -Depth 10
$json | Edit-LineEndings -LineEnding $LineEnding | Out-File -FilePath "$archetypeFilePath" -Force
}

166 changes: 166 additions & 0 deletions .github/scripts/Invoke-LibraryUpdatePolicyAssignments.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/usr/bin/pwsh

#
# PowerShell Script
# - Update template library in terraform-azurerm-caf-enterprise-scale repository
#

[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter()][String]$AlzToolsPath = "$PWD/enterprise-scale/src/Alz.Tools",
[Parameter()][String]$TargetPath = "$PWD/terraform-azurerm-caf-enterprise-scale",
[Parameter()][String]$SourcePath = "$PWD/enterprise-scale",
[Parameter()][String]$LineEnding = "unix",
[Parameter()][String]$ParserToolUrl = "https://github.com/jaredfholgate/template-parser/releases/download/0.1.18"
)

$ErrorActionPreference = "Stop"

# This script relies on a custom set of classes and functions
# defined within the EnterpriseScaleLibraryTools PowerShell
# module.
Import-Module $AlzToolsPath -ErrorAction Stop

$parserPath = "$TargetPath/.github/scripts"
$parserExe = "Template.Parser.Cli"
if($IsWindows)
{
$parserExe += ".exe"
}

$parser = "$parserPath/$parserExe"

if(!(Test-Path $parser))
{
Write-Information "Downloading Template Parser." -InformationAction Continue
Invoke-WebRequest "$ParserToolUrl/$parserExe" -OutFile $parser
}

# Update the policy assignments if enabled
Write-Information "Updating Policy Assignments." -InformationAction Continue
$policyAssignmentSourcePath = "$SourcePath/eslzArm/managementGroupTemplates/policyAssignments"
$policyAssignmentTargetPath = "$TargetPath/modules/archetypes/lib/policy_assignments"
$sourcePolicyAssignmentFiles = Get-ChildItem -Path $policyAssignmentSourcePath -File
$targetPolicyAssignmentFiles = Get-ChildItem -Path $policyAssignmentTargetPath -File

$temporaryNameMatches = @{
"Deny-IP-forwarding" = "Deny-IP-Forwarding"
"Deny-Priv-Esc-AKS" = "Deny-Priv-Containers-AKS"
"Deny-Privileged-AKS" = "Deny-Priv-Escalation-AKS"
}

$defaultParameterValues =@(
"-p nonComplianceMessagePlaceholder={donotchange}"
"-p logAnalyticsWorkspaceName=`${root_scope_id}-la",
"-p automationAccountName=`${root_scope_id}-automation",
"-p workspaceRegion=`${default_location}",
"-p automationRegion=`${default_location}",
"-p retentionInDays=30",
"-p rgName=`${root_scope_id}-mgmt",
"-p logAnalyticsResourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/`${root_scope_id}-mgmt/providers/Microsoft.OperationalInsights/workspaces/`${root_scope_id}-la",
"-p topLevelManagementGroupPrefix=`${temp}",
"-p dnsZoneResourceGroupId=`${private_dns_zone_prefix}",
"-p ddosPlanResourceId=/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/`${root_scope_id}-mgmt/providers/Microsoft.Network/ddosProtectionPlans/`${root_scope_id}-ddos",
"-p emailContactAsc=security_contact@replace_me"
)

$parsedAssignments = @{}
foreach($sourcePolicyAssignmentFile in $sourcePolicyAssignmentFiles)
{
$parsedAssignment = & $parser "-s $sourcePolicyAssignmentFile" $defaultParameterValues | Out-String | ConvertFrom-Json
$parsedAssignments[$parsedAssignment.name] = @{
json = $parsedAssignment
file = $sourcePolicyAssignmentFile
}
if(!(Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json.properties -Name "scope" -MemberType Properties))
{
$parsedAssignments[$parsedAssignment.name].json.properties | Add-Member -MemberType NoteProperty -Name "scope" -Value "`${current_scope_resource_id}"
}

if(!(Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json.properties -Name "notScopes" -MemberType Properties))
{
$parsedAssignments[$parsedAssignment.name].json.properties | Add-Member -MemberType NoteProperty -Name "notScopes" -Value @()
}

if(!(Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json.properties -Name "parameters" -MemberType Properties))
{
$parsedAssignments[$parsedAssignment.name].json.properties | Add-Member -MemberType NoteProperty -Name "parameters" -Value @{}
}

if(!(Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json -Name "location" -MemberType Properties))
{
$parsedAssignments[$parsedAssignment.name].json | Add-Member -MemberType NoteProperty -Name "location" -Value "`${default_location}"
}

if(!(Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json -Name "identity" -MemberType Properties))
{
$parsedAssignments[$parsedAssignment.name].json | Add-Member -MemberType NoteProperty -Name "identity" -Value @{ type = "None" }
}

$parsedAssignments[$parsedAssignment.name].json.properties.enforcementMode = $null

if($parsedAssignments[$parsedAssignment.name].json.properties.policyDefinitionId.StartsWith("/providers/Microsoft.Management/managementGroups/`${temp}"))
{
$parsedAssignments[$parsedAssignment.name].json.properties.policyDefinitionId = $parsedAssignments[$parsedAssignment.name].json.properties.policyDefinitionId.Replace("/providers/Microsoft.Management/managementGroups/`${temp}", "`${root_scope_resource_id}")
}

foreach($property in Get-Member -InputObject $parsedAssignments[$parsedAssignment.name].json.properties.parameters -MemberType NoteProperty)
{
$propertyName = $property.Name
if($parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value.StartsWith("`${private_dns_zone_prefix}/providers/Microsoft.Network/privateDnsZones/"))
{
$parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value = $parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value.Replace("`${private_dns_zone_prefix}/providers/Microsoft.Network/privateDnsZones/", "`${private_dns_zone_prefix}")
$parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value = $parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value.Replace("privatelink.batch.azure.com", "privatelink.`${connectivity_location}.batch.azure.com")
}
if($parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value.StartsWith("`${temp}"))
{
$parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value = $parsedAssignments[$parsedAssignment.name].json.properties.parameters.($propertyName).value.Replace("`${temp}", "`${root_scope_id}")
}
}
}

$originalAssignments = @{}
foreach($targetPolicyAssignmentFile in $targetPolicyAssignmentFiles)
{
$originalAssignment = Get-Content $targetPolicyAssignmentFile | ConvertFrom-Json
$originalAssignments[$originalAssignment.name] = @{
json = $originalAssignment
file = $targetPolicyAssignmentFile
}
}

foreach($key in $parsedAssignments.Keys | Sort-Object)
{
$targetPolicyAssignmentFileName = "policy_assignment_es_$($key.ToLower() -replace "-", "_").tmpl.json"

$mappedKey = $key
if($temporaryNameMatches.ContainsKey($key))
{
$mappedKey = $temporaryNameMatches[$key]
}

$sourceFileName = $parsedAssignments[$key].file.Name

if($originalAssignments.ContainsKey($mappedKey))
{
$originalFileName = $originalAssignments[$mappedKey].file.Name

Write-Information "Found match for $mappedKey $key $originalFileName $sourceFileName $targetPolicyAssignmentFileName" -InformationAction Continue
if($originalFileName -ne $targetPolicyAssignmentFileName)
{
Write-Information "Renaming $originalFileName to $targetPolicyAssignmentFileName" -InformationAction Continue
Set-Location $policyAssignmentTargetPath
git mv $originalAssignments[$mappedKey].file.FullName $targetPolicyAssignmentFileName
Set-Location $SourcePath
Set-Location ..
}
}
else
{
Write-Information "No match found for $mappedKey $key $sourceFileName $targetPolicyAssignmentFileName" -InformationAction Continue
}

Write-Information "Writing $targetPolicyAssignmentFileName" -InformationAction Continue
$json = $parsedAssignments[$key].json | ConvertTo-Json -Depth 10
$json | Edit-LineEndings -LineEnding $LineEnding | Out-File -FilePath "$policyAssignmentTargetPath/$targetPolicyAssignmentFileName" -Force
}
File renamed without changes.
16 changes: 14 additions & 2 deletions .github/workflows/update-policy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,24 @@ jobs:
uses: azure/powershell@v1
with:
inlineScript: |
Write-Information "==> Running script..." -InformationAction Continue
${{ github.repository }}/.github/scripts/Invoke-LibraryUpdate.ps1 `
Write-Information "==> Running policy definitions script..." -InformationAction Continue
${{ github.repository }}/.github/scripts/Invoke-LibraryUpdatePolicyDefinitions.ps1 `
-AlzToolsPath "${{ github.workspace }}/${{ env.remote_repository }}/src/Alz.Tools/" `
-TargetPath "${{ github.workspace }}/${{ github.repository }}" `
-SourcePath "${{ github.workspace }}/${{ env.remote_repository }}" `
-Reset
Write-Information "==> Running policy assignments script..." -InformationAction Continue
${{ github.repository }}/.github/scripts/Invoke-LibraryUpdatePolicyAssignments.ps1 `
-AlzToolsPath "${{ github.workspace }}/${{ env.remote_repository }}/src/Alz.Tools/" `
-TargetPath "${{ github.workspace }}/${{ github.repository }}" `
-SourcePath "${{ github.workspace }}/${{ env.remote_repository }}"
Write-Information "==> Running archetypes script..." -InformationAction Continue
${{ github.repository }}/.github/scripts/Invoke-LibraryUpdatePolicyAssignmentsArchetypes.ps1 `
-AlzToolsPath "${{ github.workspace }}/${{ env.remote_repository }}/src/Alz.Tools/" `
-TargetPath "${{ github.workspace }}/${{ github.repository }}" `
-SourcePath "${{ github.workspace }}/${{ env.remote_repository }}"
azPSVersion: "latest"

- name: Check for changes
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ tests/modules/test_local
**/super-linter.report
**/super-linter.report/*
**/super-linter.log
.vscode/launch.json
.github/scripts/Template.Parser.Cli.exe
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ This allows customers to address concerns around managing large state files, or

## Terraform versions

This module has been tested using Terraform `1.3.1` and AzureRM Provider `3.35.0` as a baseline, and various versions to up the latest at time of release.
This module has been tested using Terraform `1.3.1` and AzureRM Provider `3.54.0` as a baseline, and various versions to up the latest at time of release.
In some cases, individual versions of the AzureRM provider may cause errors.
If this happens, we advise upgrading to the latest version and checking our [troubleshooting](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Troubleshooting) guide before [raising an issue](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/issues).

Expand All @@ -65,7 +65,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.35.0"
version = ">= 3.54.0"
}
}
}
Expand Down Expand Up @@ -149,6 +149,7 @@ Please see the [releases](https://github.com/Azure/terraform-azurerm-caf-enterpr

For upgrade guides from previous versions, please refer to the following links:

- [Upgrade from v3.3.0 to v3.4.0](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v3.3.0-to-v3.4.0)
- [Upgrade from v2.4.1 to v3.0.0](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v2.4.1-to-v3.0.0)
- [Upgrade from v1.1.4 to v2.0.0](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v1.1.4-to-v2.0.0)
- [Upgrade from v0.4.0 to v1.0.0](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Upgrade-from-v0.4.0-to-v1.0.0)
Expand All @@ -167,7 +168,7 @@ The following requirements are needed by this module:

- <a name="requirement_azapi"></a> [azapi](#requirement\_azapi) (>= 1.3.0)

- <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) (>= 3.35.0)
- <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) (>= 3.54.0)

- <a name="requirement_random"></a> [random](#requirement\_random) (>= 3.1.0)

Expand Down Expand Up @@ -231,9 +232,9 @@ The following input variables are optional (have default values):

### <a name="input_archetype_config_overrides"></a> [archetype\_config\_overrides](#input\_archetype\_config\_overrides)

Description: If specified, will set custom Archetype configurations for the core ALZ Management Groups. Does not work for management groups specified by the 'custom\_landing\_zones' input variable.
To override the default configuration settings for any of the core Management Groups, add an entry to the archetype\_config\_overrides variable for each Management Group you want to customize.
To create a valid archetype\_config\_overrides entry, you must provide the required values in the archetype\_config\_overrides object for the Management Group you wish to re-configure.
Description: If specified, will set custom Archetype configurations for the core ALZ Management Groups. Does not work for management groups specified by the 'custom\_landing\_zones' input variable.
To override the default configuration settings for any of the core Management Groups, add an entry to the archetype\_config\_overrides variable for each Management Group you want to customize.
To create a valid archetype\_config\_overrides entry, you must provide the required values in the archetype\_config\_overrides object for the Management Group you wish to re-configure.
To do this, simply create an entry similar to the root example below for one or more of the supported core Management Group IDs:

- root
Expand Down Expand Up @@ -1174,4 +1175,4 @@ If you don't wish to send usage data to Microsoft, details on how to turn it off
- [Feature Requests](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Feature-Requests)
- [Contributing to Code](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Contributing-to-Code)
- [Contributing to Documentation](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/Contributing-to-Documentation)
<!-- END_TF_DOCS -->
<!-- END_TF_DOCS -->
Loading

0 comments on commit 2467832

Please sign in to comment.