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

[New Control] GR11 V4 Microsoft Defender for Cloud Alerts and Events Check #295

Merged
merged 15 commits into from
Dec 6, 2024
Merged
Binary file added psmodules/Check-DefenderForCloudAlerts.zip
Binary file not shown.
Binary file modified psmodules/GR-ComplianceChecks.zip
Binary file not shown.
10 changes: 10 additions & 0 deletions setup/IaC/modules/automationaccount.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,16 @@ resource guardrailsAC 'Microsoft.Automation/automationAccounts@2021-06-22' = if
}
}

resource module48 'modules' = if (newDeployment || updatePSModules) {
name: 'Check-DefenderForCloudAlerts'
properties: {
contentLink: {
uri: '${ModuleBaseURL}/Check-DefenderForCloudAlerts.zip'
version: '1.0.0'
}
}
}


resource variable1 'variables' = if (newDeployment || updateCoreResources) {
name: 'KeyvaultName'
Expand Down
15 changes: 15 additions & 0 deletions setup/modules.json
alalvi00 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,21 @@
}
]
},
{
"ModuleName": "Check-DefenderForCloudAlerts",
"Control": "Guardrails11",
"ModuleType": "Builtin",
"Status": "Enabled",
"Required": "True",
"Profiles": [2, 3, 4, 5, 6],
"Script": "Get-DefenderForCloudAlerts -ControlName $msgTable.CtrName11 -ItemName $msgTable.msDefenderChecks -MsgTable $msgTable -ReportTime $ReportTime -itsgcode $vars.itsgcode -CloudUsageProfiles $cloudUsageProfilesString -ModuleProfiles $ModuleProfilesString",
"localVariables": [
{
"Name": "itsgcode",
"Value": "AC2(11)"
}
]
},
{
"ModuleName": "Check-DocumentExistsInStorage",
"Control": "Guardrails11",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#
# Module manifest for module 'Check-DefenderForCloudConfig'
#
# Generated by: Cloud Security Compliance Team
#
# Contact Information for module : cloudsecuritycompliance-conformiteinfonuagiquesecurise@ssc-spc.gc.ca
#
# Generated on: 2024-12-04
#

@{

# Script module or binary module file associated with this manifest.
RootModule = '.\Check-DefenderForCloudAlerts.psm1'

# Version number of this module.
ModuleVersion = '1.0.0'

# Supported PSEditions
# CompatiblePSEditions = @()

# ID used to uniquely identify this module
GUID = '5adc5e4c-800d-4db6-8ba0-45f463d602e1'

# Author of this module
Author = 'Cloud Security Compliance'

# Company or vendor of this module
CompanyName = 'Shared Services Canada'

# Copyright statement for this module
Copyright = ''

# Description of the functionality provided by this module
# Description = ''

# Minimum version of the PowerShell engine required by this module
# PowerShellVersion = ''

# Name of the PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# ClrVersion = ''

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()

# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()

# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = '*'

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = '*'

# Variables to export from this module
VariablesToExport = '*'

# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = '*'

# DSC resources to export from this module
# DscResourcesToExport = @()

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
# FileList = @()

# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{

PSData = @{

# Tags applied to this module. These help with module discovery in online galleries.
Tags = 'GOC 30 days Guardrails'

# A URL to the license for this module.
# LicenseUri = ''

# A URL to the main website for this project.
# ProjectUri = ''

# A URL to an icon representing this module.
# IconUri = ''

# ReleaseNotes of this module
# ReleaseNotes = ''

# Prerelease string of this module
# Prerelease = ''

# Flag to indicate whether the module requires explicit user acceptance for install/update/save
# RequireLicenseAcceptance = $false

# External dependent modules of this module
# ExternalModuleDependencies = @()

} # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}

alalvi00 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
function Get-DefenderForCloudAlerts {
param (
[Parameter(Mandatory=$true)]
[string]$ControlName,
[Parameter(Mandatory=$true)]
[string]$ItemName,
[Parameter(Mandatory=$true)]
[string]$itsgcode,
[Parameter(Mandatory=$true)]
[hashtable]$msgTable,
[Parameter(Mandatory=$true)]
[string]$ReportTime,
[string]
$CloudUsageProfiles = "3", # Passed as a string
[string] $ModuleProfiles, # Passed as a string
[switch]
$EnableMultiCloudProfiles # New feature flag, default to false
)

$isCompliant = $false
$Comments = ""
$ErrorList = @()
$subCompliance = @()

#Get All the Subscriptions
$subs = Get-AzSubscription -ErrorAction SilentlyContinue| Where-Object {$_.State -eq "Enabled"}

foreach($subscription in $subs){
$subId = $subscription.Id
Set-AzContext -SubscriptionId $subId

$defenderPlans = Get-AzSecurityPricing
$defenderEnabled = $defenderPlans | Where-Object {$_.PricingTier -eq 'Standard'} #A paid plan should exist on the sub resource

if(-not $defenderEnabled){
$Comments += $msgTable.NotAllSubsHaveDefenderPlans -f $subscription
break
}

$azContext = Get-AzContext
$token = Get-AzAccessToken -TenantId $azContext.Subscription.TenantId

$authHeader = @{
'Content-Type' = 'application/json'
'Authorization' = 'Bearer ' + $token.Token
}

#Retrieve notifications for alert and attack paths
$restUri = "https://management.azure.com/subscriptions/$($azContext.Subscription.Id)/providers/Microsoft.Security/securityContacts/default?api-version=2023-12-01-preview"

try{
$response = Invoke-RestMethod -Uri $restUri -Method Get -Headers $authHeader
}
catch{
$Comments += $msgTable.errorRetrievingNotifications
$ErrorList += "Error invoking $restUri for notifications for the subscription: $_"
break
}

$notificationSources = $response.properties.notificationsSources
$notificationEmails = $response.properties.emails
$ownerRole = $response.properties.notificationsByRole.roles | Where-Object {$_ -eq "Owner"}
$ownerState = $response.properties.notificationsByRole.State

#Filter so we get required notification types
$alertNotification = $notificationSources | Where-Object {$_.sourceType -eq "Alert" -and $_.minimalSeverity -in @("Medium","Low")}
$attackPathNotification = $notificationSources | Where-Object {$_.sourceType -eq "AttackPath" -and $_.minimalRiskLevel -in @("Medium","Low")}

$emailCount = ($notificationEmails -split ";").Count

#Check theres minimum two emails and owner is also notified
if(($emailCount -lt 2) -or ($ownerState -ne "On" -or $ownerRole -ne "Owner")){
$Comments += $msgTable.EmailsOrOwnerNotConfigured -f $subscription
break
}

if($null -eq $alertNotification){
$Comments += $msgTable.AlertNotificationNotConfigured
break
}

if($null -eq $attackPathNotification){
$Comments += $msgTable.AttackPathNotifictionNotConfigured
break
}

#If it reaches here, then subscription is compliant
$subCompliance += $true
}

#Check if all subscriptions are compliant
if ($subCompliance -notcontains $false -and $null -ne $subCompliance -and $subCompliance.Count -eq $subs.Count){
$isCompliant = $true
$Comments += $msgTable.DefenderCompliant
}

$PsObject = [PSCustomObject]@{
ComplianceStatus = $isCompliant
ControlName = $ControlName
Comments = $Comments
ItemName = $ItemName
ReportTime = $ReportTime
itsgcode = $itsgcode
}

# Conditionally add the Profile field based on the feature flag
if ($EnableMultiCloudProfiles) {
$evalResult = Get-EvaluationProfile -CloudUsageProfiles $CloudUsageProfiles -ModuleProfiles $ModuleProfiles
if (!$evalResult.ShouldEvaluate) {
if ($evalResult.Profile -gt 0) {
$PsObject.ComplianceStatus = "Not Applicable"
$PsObject | Add-Member -MemberType NoteProperty -Name "Profile" -Value $evalResult.Profile
$PsObject.Comments = "Not evaluated - Profile $($evalResult.Profile) not present in CloudUsageProfiles"
} else {
$ErrorList.Add("Error occurred while evaluating profile configuration")
}
} else {

$PsObject | Add-Member -MemberType NoteProperty -Name "Profile" -Value $evalResult.Profile
}
}

$moduleOutput = [PSCustomObject]@{
ComplianceResults = $PsObject
Errors = $ErrorList
}

return $moduleOutput
}
8 changes: 8 additions & 0 deletions src/GuardRails-Localization/GR-ComplianceChecks-Msgs.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,14 @@ noServiceHealthAlerts = Could not retrieve any configured alerts for the subscri
nonCompliantActionGroups = All subscriptions have Service Health Alerts, but not all action groups are correctly configured. A minimum of two email addresses or subscription owners are required for the action group.
compliantServiceHealthAlerts = All subscriptions have Service Health Alerts, and the action group has at least two different contacts.

msDefenderChecks = Microsoft Defender for Cloud Alerts and Events Check
NotAllSubsHaveDefenderPlans = The following subscription(s) lack a defender plan: {0}. Enable Defender monitoring for all subscriptions.
errorRetrievingNotifications = Defender alert notifications for the subscription(s) are not configured. Ensure they match the Remediation Guidance requirements.
EmailsOrOwnerNotConfigured = Defender alert notifications for the subscription do not include at least two email addresses or subscription owners. Configure this to ensure alerts are sent correctly.
AlertNotificationNotConfigured = Defender alert notifications are incorrect. Set the severity to Medium or Low and review the Remediation Guidance.
AttackPathNotifictionNotConfigured = Defender alerts must include attack path notifications. Ensure this is configured for each subscription's alerts per the Remediation Guidance.
DefenderCompliant = MS Defender for Cloud is enabled for all subscriptions, and email notifications are properly configured.

monitoringChecklist = Monitoring Checklist: Use Cases

timezoneConsistency = Time Zone Configuration Consistency Check
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@ compliantServiceHealthAlerts = Les alertes de santé du service « Service Healt

monitoringChecklist = Liste de vérification de surveillance : Cas d'utilisation

msDefenderChecks = Alertes infonuagiques et vérification des événements de Microsoft Defender
NotAllSubsHaveDefenderPlans = Le(s) abonnement(s) suivant(s) n'a/n'ont pas de plan MS Defender : {0} . Activez la surveillance MS Defender pour tous les abonnements.
errorRetrievingNotifications = Les notifications d'alerte MS Defender pour le ou les abonnements ne sont pas configurées. Assurez-vous qu'elles correspondent aux exigences du guide de Remédiation.
EmailsOrOwnerNotConfigured = Les notifications d'alerte MS Defender pour l'abonnement n'incluent pas au moins deux adresses courriel ou propriétaires d'abonnement. Configurez les pour s'assurer que les alertes sont envoyées correctement
AlertNotificationNotConfigured = Les notifications d'alerte MS Defender sont incorrectes. Définissez la gravité à Moyen ou Faible et passez en revue le Guide de Remédiation.
AttackPathNotifictionNotConfigured = Les alertes MS Defender doivent inclure des notifications de chemin d'attaque. Assurez-vous qu'elles sont configurées pour les alertes de chaque abonnement conformément aux instructions du Guide de Remédiation
DefenderCompliant = MS Defender pour l'infonuagique est activé pour tous les abonnements et les notifications par courriel sont correctement configurées.

timezoneConsistency = Vérification de la cohérence de la configuration du fuseau horaire
noResourcesFound = Aucune ressource avec des informations de fuseau horaire trouvée.
resourcesWithoutTimezone = Il y a {0} ressources sans informations de fuseau horaire.
Expand Down
Loading