Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created a new remediation script that will work with sovereign clouds #373

Closed
wants to merge 6 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions patterns/alz/scripts/Start-AMBA-ALZ-Remediation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# The below copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

<#
.DESCRIPTION
This script is used to trigger remediation on a specific policy or policy set at management group scope.
It first calls the Azure REST API to get the policy assignments in the management group scope, then it iterates through the policy assignments, checking by name whether it's a policy set or an individual policy.
Depending on the result the script will either enumerate the policy set and trigger remediation for each individual policy in the set or trigger remediation for the individual policy.

.LINK
https://azure.github.io/azure-monitor-baseline-alerts/patterns/alz/deploy/Remediate-Policies/

.PARAMETER -azureEnvironment
The Azure environment the customer is using. This parameter only allows for hard-coded values corresponding to the ppublic and sovereign clouds available today.

.PARAMETER managementGroupName
The management group name where the policy assignments are located.

.PARAMETER policyName
The name of the policy or policy set to remediate.

.EXAMPLE
Modify the following variables to match your environment:

$pseudoRootManagementGroup = "The pseudo root management group id parenting the Platform and Landing Zones management groups"
$identityManagementGroup = "The management group id for Identity"
$managementManagementGroup = "The management group id for Management"
$connectivityManagementGroup = "The management group id for Connectivity"
$LZManagementGroup = "The management group id for Landing Zones"

Run the following commands to initiate remediation:

.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $pseudoRootManagementGroup -policyName Notification-Assets
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $pseudoRootManagementGroup -policyName Alerting-ServiceHealth
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $connectivityManagementGroup -policyName Alerting-Connectivity
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $identityManagementGroup -policyName Alerting-Identity
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $managementManagementGroup -policyName Alerting-Management
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-KeyManagement
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-LoadBalancing
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-NetworkChanges
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-HybridVM
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-Storage
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-VM
.\patterns\alz\scripts\Start-AMBARemediation.ps1 -azureEnvironment "AzureCloud" -managementGroupName $LZManagementGroup -policyName Alerting-Web

#>

# The following SuppressMessageAttribute entries are used to surpress PSScriptAnalyzer tests against known exceptions as per:
# https://github.com/powershell/psscriptanalyzer#suppressing-rules
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'False positive')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False positive')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseApprovedVerbs', '', Justification = 'Approved verbs are not available for this scenario')]

Param(
[Parameter(Mandatory = $true)] [ValidateSet("AzureCloud", "AzureUSGovernment", "AzureChinaCloud", IgnoreCase = $true)] [string] $azureEnvironment,
[Parameter(Mandatory = $true)] [string] $managementGroupName,
[Parameter(Mandatory = $true)] [string] $policyName
)

#region general functions

# Function to trigger remediation for a single policy
Function Start-PolicyRemediation {
Param(
[Parameter(Mandatory = $true)] [string] $azureEnvironmentURI,
[Parameter(Mandatory = $true)] [string] $managementGroupName,
[Parameter(Mandatory = $true)] [string] $policyAssignmentName,
[Parameter(Mandatory = $true)] [string] $polassignId,
[Parameter(Mandatory = $false)] [string] $policyDefinitionReferenceId
)
$guid = New-Guid

# Create remediation for the individual policy
$uri = "https://$($azureEnvironmentURI)/providers/Microsoft.Management/managementGroups/$($managementGroupName)/providers/Microsoft.PolicyInsights/remediations/$($policyName)-$($guid)?api-version=2021-10-01"
$body = @{
properties = @{
policyAssignmentId = "$polassignId"
}
}
if ($policyDefinitionReferenceId) {
$body.properties.policyDefinitionReferenceId = $policyDefinitionReferenceId
}
$body = $body | ConvertTo-Json -Depth 10
Invoke-AzRestMethod -Uri $uri -Method PUT -Payload $body
}

#Function to get the policy assignments in the management group scope
function Get-PolicyType {
Param (
[Parameter(Mandatory = $true)] [string] $azureEnvironmentURI,
[Parameter(Mandatory = $true)] [string] $managementGroupName,
[Parameter(Mandatory = $true)] [string] $policyName
)

# Validate that the management group exists through the Azure REST API
$uri = "https://$($azureEnvironmentURI)/providers/Microsoft.Management/managementGroups/$($managementGroupName)?api-version=2021-04-01"
$result = (Invoke-AzRestMethod -Uri $uri -Method GET).Content | ConvertFrom-Json -Depth 100
if ($result.error) {
throw "Management group $managementGroupName does not exist, please specify a valid management group name"
}

# Getting custom policySetDefinitions
$uri = "https://$($azureEnvironmentURI)/providers/Microsoft.Management/managementGroups/$($managementGroupName)/providers/Microsoft.Authorization/policySetDefinitions?&api-version=2023-04-01"
$initiatives = (Invoke-AzRestMethod -Uri $uri -Method GET).Content | ConvertFrom-Json -Depth 100

# Get policy assignments at management group scope
$assignmentFound = $false
$uri = "https://$($azureEnvironmentURI)/providers/Microsoft.Management/managementGroups/$($managementGroupName)/providers/Microsoft.Authorization/policyAssignments?`$filter=atScope()&api-version=2022-06-01"
$result = (Invoke-AzRestMethod -Uri $uri -Method GET).Content | ConvertFrom-Json -Depth 100

# Iterate through the policy assignments
$result.value | ForEach-Object {

#check if the policy assignment is for the specified policy set definition
If ($($PSItem.properties.policyDefinitionId) -match "/providers/Microsoft.Authorization/policySetDefinitions/$policyName") {

# Go to enumerating policy set
$assignmentFound = $true
Enumerate-PolicySet -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentObject $PSItem
}
Elseif ($($PSItem.properties.policyDefinitionId) -match "/providers/Microsoft.Authorization/policyDefinitions/$policyName") {

# Go to handling individual policy
$assignmentFound = $true
Enumerate-Policy -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentObject $PSItem
}
Else {

# Getting parent initiative for unassigned individual policies
If ($initiatives) {
$parentInitiative = $initiatives.value | Where-Object { ($_.properties.policyType -eq 'Custom') -and ($_.properties.metadata -like '*_deployed_by_amba*') } | Where-Object { $_.properties.policyDefinitions.policyDefinitionReferenceId -eq $policyname }

# Getting the assignment of the parent initiative
If ($parentInitiative) {
If ($($PSItem.properties.policyDefinitionId) -match "/providers/Microsoft.Authorization/policySetDefinitions/$($parentInitiative.name)") {

# Invoking policy remediation
$assignmentFound = $true
Start-PolicyRemediation -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentName $PSItem.name -polassignId $PSItem.id -policyDefinitionReferenceId $policyName
}
}
}
}
}

# If no policy assignments were found for the specified policy name, throw an error
If (!$assignmentFound) {
throw "No policy assignments found for policy $policyName at management group scope $managementGroupName"
}
}

# Function to enumerate the policies in the policy set and trigger remediation for each individual policy
function Enumerate-PolicySet {
param (
[Parameter(Mandatory = $true)] [string] $azureEnvironmentURI,
[Parameter(Mandatory = $true)] [string] $managementGroupName,
[Parameter(Mandatory = $true)] [object] $policyAssignmentObject
)

# Extract policy assignment information
$policyAssignmentObject
$polassignId = $policyAssignmentObject.id
$name = $policyAssignmentObject.name
$policySetId = $policyAssignmentObject.properties.policyDefinitionId
$policySetId
$psetUri = "https://$($azureEnvironmentURI)$($policySetId)?api-version=2021-06-01"
$policySet = (Invoke-AzRestMethod -Uri $psetUri -Method GET).Content | ConvertFrom-Json -Depth 100
$policySet
$policies = $policySet.properties.policyDefinitions

# Iterate through the policies in the policy set
If ($policyAssignmentObject.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/Alerting-ServiceHealth") {
$policyDefinitionReferenceId = "Deploy_ServiceHealth_ActionGroups"
Start-PolicyRemediation -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentName $name -polassignId $polassignId -policyDefinitionReferenceId $policyDefinitionReferenceId
Write-Host " Waiting for 5 minutes while remediating the 'Deploy Service Health Action Group' policy before continuing." -ForegroundColor Cyan
Start-Sleep -Seconds 360
}
Foreach ($policy in $policies) {
$policyDefinitionId = $policy.policyDefinitionId
$policyDefinitionReferenceId = $policy.policyDefinitionReferenceId

# Trigger remediation for the individual policy
Start-PolicyRemediation -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentName $name -polassignId $polassignId -policyDefinitionReferenceId $policyDefinitionReferenceId
}
}

#Function to get specific information about a policy assignment for a single policy and trigger remediation
function Enumerate-Policy {
param (
[Parameter(Mandatory = $true)] [string] $azureEnvironmentURI,
[Parameter(Mandatory = $true)] [string] $managementGroupName,
[Parameter(Mandatory = $true)] [object] $policyAssignmentObject
)

# Extract policy assignment information
$polassignId = $policyAssignmentObject.id
$name = $policyAssignmentObject.name
$policyDefinitionId = $policyAssignmentObject.properties.policyDefinitionId
Start-PolicyRemediation -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyAssignmentName $name -polassignId $polassignId
}

#endregion

#Main script
switch ($azureEnvironment) {
"AzureCloud" {
$azureEnvironmentURI = "management.azure.com"
}

"AzureUSGovernment" {
$azureEnvironmentURI = "management.usgovcloudapi.net" # See API Endpoints for Azure US Government at https://learn.microsoft.com/en-us/azure/azure-government/compare-azure-government-global-azure#guidance-for-developers
}

"AzureChinaCloud" {
$azureEnvironmentURI = "management.chinacloudapi.cn" # See API Endpoints for Azure China at https://learn.microsoft.com/en-us/azure/reliability/sovereign-cloud-china#azure-in-china-rest-endpoints
}

Default {azureEnvironmentURI = "management.azure.com"}
}
Get-PolicyType -azureEnvironmentURI $azureEnvironmentURI -managementGroupName $managementGroupName -policyName $policyName