tests/Test-Assessment.25419.ps1
|
<#
.SYNOPSIS Checks that Global Secure Access logs are integrated with a Log Analytics workspace for security monitoring. .DESCRIPTION Verifies that diagnostic settings are configured to send Global Secure Access log categories (NetworkAccessTrafficLogs, EnrichedOffice365AuditLogs, RemoteNetworkHealthLogs, NetworkAccessAlerts, NetworkAccessConnectionEvents, NetworkAccessGenerativeAIInsights) to a Log Analytics workspace for Microsoft Sentinel integration and threat detection. .NOTES Test ID: 25419 Category: Global Secure Access Required API: Azure Monitor Diagnostic Settings API (management.azure.com) #> function Test-Assessment-25419 { [ZtTest( Category = 'Global Secure Access', ImplementationCost = 'Low', MinimumLicense = ('AAD_PREMIUM', 'Entra_Premium_Internet_Access', 'Entra_Premium_Private_Access'), Pillar = 'Network', RiskLevel = 'Medium', SfiPillar = 'Monitor and detect cyberthreats', TenantType = ('Workforce'), TestId = 25419, Title = 'Network access activity is visible to security operations for threat detection and response', UserImpact = 'Low' )] [CmdletBinding()] param() #region Data Collection Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose $activity = 'Checking Global Secure Access diagnostic settings for security monitoring' # Check if connected to Azure Write-ZtProgress -Activity $activity -Status 'Checking Azure connection' $azContext = Get-AzContext -ErrorAction SilentlyContinue if (-not $azContext) { Write-PSFMessage 'Not connected to Azure.' -Level Warning Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure return } # Check the supported environment, 'AzureCloud' in (Get-AzContext).Environment.Name maps to 'Global' in (Get-MgContext).Environment Write-ZtProgress -Activity $activity -Status 'Checking Azure environment' if ($azContext.Environment.Name -ne 'AzureCloud') { Write-PSFMessage 'This test is only applicable to the AzureCloud environment.' -Tag Test -Level VeryVerbose Add-ZtTestResultDetail -SkippedBecause NotSupported return } # Query diagnostic settings for Microsoft Entra Write-ZtProgress -Activity $activity -Status 'Querying Microsoft Entra diagnostic settings' $resourceManagementUrl = $azContext.Environment.ResourceManagerUrl $diagnosticSettingsUri = $resourceManagementUrl + 'providers/microsoft.aadiam/diagnosticsettings?api-version=2017-04-01-preview' try { $result = Invoke-AzRestMethod -Method GET -Uri $diagnosticSettingsUri -ErrorAction Stop if ($result.StatusCode -eq 403) { Write-PSFMessage 'The signed in user does not have access to check diagnostic settings.' -Level Verbose Add-ZtTestResultDetail -SkippedBecause NoAzureAccess return } if ($result.StatusCode -ge 400) { throw "Diagnostic settings request failed with status code $($result.StatusCode)" } } catch { # Only catches actual exceptions (network errors, etc.), not HTTP status codes throw } $diagnosticSettings = ($result.Content | ConvertFrom-Json).value #endregion Data Collection #region Assessment Logic # Define required Global Secure Access log categories $requiredLogCategories = @( 'NetworkAccessTrafficLogs', 'EnrichedOffice365AuditLogs', 'RemoteNetworkHealthLogs', 'NetworkAccessAlerts', 'NetworkAccessConnectionEvents', 'NetworkAccessGenerativeAIInsights' ) $passed = $false $testResultMarkdown = '' if ($null -eq $diagnosticSettings -or $diagnosticSettings.Count -eq 0) { $testResultMarkdown = "❌ No diagnostic settings are configured for Microsoft Entra. Global Secure Access logs are not being exported to any destination.`n`n%TestResult%" } else { # Find settings that have all required categories enabled and sent to a workspace $settingsWithAllCategories = @() foreach ($setting in $diagnosticSettings) { $hasWorkspace = -not [string]::IsNullOrEmpty($setting.properties.workspaceId) $enabledLogs = $setting.properties.logs | Where-Object { $_.enabled -eq $true } | Select-Object -ExpandProperty category $hasAllCategories = ($requiredLogCategories | Where-Object { $_ -in $enabledLogs }).Count -eq $requiredLogCategories.Count if ($hasWorkspace -and $hasAllCategories) { $settingsWithAllCategories += $setting } } $passed = $settingsWithAllCategories.Count -gt 0 if ($passed) { $testResultMarkdown = "✅ All required Global Secure Access log categories are integrated with a Log Analytics workspace for security monitoring and threat detection.`n`n%TestResult%" } else { $testResultMarkdown = "❌ Global Secure Access logs are not properly integrated with a Log Analytics workspace for security operations visibility.`n`n%TestResult%" } } #endregion Assessment Logic #region Report Generation $mdInfo = '' if ($diagnosticSettings.Count -gt 0) { $mdInfo += "`n## [Diagnostic settings configuration](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/DiagnosticSettings)`n`n" # Build pivoted table: Log Categories as rows, Diagnostic Settings as columns # Header row with diagnostic setting names $headerRow = '| Log category |' $separatorRow = '| :--- |' foreach ($setting in $diagnosticSettings) { $headerRow += " $(Get-SafeMarkdown $setting.name) |" $separatorRow += ' :---: |' } $mdInfo += "$headerRow`n" $mdInfo += "$separatorRow`n" # One row per log category foreach ($category in $requiredLogCategories) { $row = "| $category |" foreach ($setting in $diagnosticSettings) { $enabledLogs = $setting.properties.logs | Where-Object { $_.enabled -eq $true } | Select-Object -ExpandProperty category $isEnabled = $category -in $enabledLogs $statusValue = if ($isEnabled) { '✅ Enabled' } else { '❌ Disabled' } $row += " $statusValue |" } $mdInfo += "$row`n" } # Workspace row at the bottom $workspaceRow = '| Workspace |' foreach ($setting in $diagnosticSettings) { $workspaceId = $setting.properties.workspaceId $hasWorkspace = -not [string]::IsNullOrEmpty($workspaceId) if ($hasWorkspace) { $workspaceName = ($workspaceId -split '/')[-1] $workspaceLink = "https://portal.azure.com/#resource$($workspaceId)/overview" $workspaceValue = "✅ [$(Get-SafeMarkdown $workspaceName)]($workspaceLink)" } else { $workspaceValue = '❌ Not configured' } $workspaceRow += " $workspaceValue |" } $mdInfo += "$workspaceRow`n" # Summary section $mdInfo += "`n**Summary:**`n`n" $mdInfo += "- Total diagnostic settings: $($diagnosticSettings.Count)`n" $mdInfo += "- Diagnostic settings passing criteria (all six categories + workspace): $($settingsWithAllCategories.Count)`n" } $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo #endregion Report Generation $params = @{ TestId = '25419' Title = 'Network access activity is visible to security operations for threat detection and response' Status = $passed Result = $testResultMarkdown } # Add test result details Add-ZtTestResultDetail @params } |