-
Notifications
You must be signed in to change notification settings - Fork 231
Added MDE Support #1017
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
Open
bdrogja
wants to merge
5
commits into
maester365:main
Choose a base branch
from
bdrogja:feature/mde-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Added MDE Support #1017
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
28b940a
Comprehensive MDE policy validation with 46 automated organized based…
bdrogja f9eae31
Added "Defender" Tag to all Defender Tests
bdrogja ebbbbff
Unintentionally increased ModuleVersion Number, reverted
bdrogja 859f972
Fixed for consistency reasons
bdrogja 614d8ab
Remove duplicate 'Defender' tag from tests
SamErde File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,197 @@ | ||
| # Microsoft Defender for Endpoint (MDE) Extension for Maester | ||
|
|
||
| ## Feature Summary | ||
|
|
||
| This feature branch extends the Maester security testing framework with comprehensive Microsoft Defender for Endpoint (MDE) policy validation capabilities. The extension includes 46 automated tests covering antivirus configurations, global settings, and policy design quality - all based on real-world MDE deployment experience. | ||
|
|
||
| ### Key Components | ||
| - **26 Antivirus Policy Tests** (MDE.AV01-26): Validate core security settings | ||
| - **16 Global Configuration Tests** (MDE.GC01-16): Check tenant-wide advanced features | ||
| - **4 Policy Design Tests** (MDE.PD01-04): Ensure consistent naming and structure | ||
| - **ASR Rules Category** (WIP): Attack Surface Reduction rules validation (planned) | ||
| - **Unified Configuration System**: Single JSON file controls all test behavior | ||
| - **Automatic Test Skipping**: Smart logic handles missing dependencies gracefully | ||
|
|
||
| ## Configuration System | ||
|
|
||
| The extension uses a centralized configuration file at `/tests/Maester/Defender/defender-config.json` that controls all MDE test behavior. | ||
|
|
||
| ### Configuration Structure | ||
|
|
||
| ```json | ||
| { | ||
| "ComplianceLogic": "AllPolicies", | ||
| "PolicyFiltering": "OnlyAssigned", | ||
| "DeviceFiltering": { | ||
| "OperatingSystems": ["Windows"], | ||
| "ManagementAgents": ["msSense", "mdm"], | ||
| "ComplianceStates": ["Compliant", "NonCompliant", "Unknown"] | ||
| }, | ||
| "TestSpecific": { | ||
| "MDE.AV01": { | ||
| "ComplianceLogic": "AtLeastOne" | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Configuration Options | ||
|
|
||
| #### ComplianceLogic | ||
| - **`AllPolicies`** (default): All applicable policies must be compliant | ||
| - **`AtLeastOne`**: At least one policy must be compliant (useful for optional features) | ||
|
|
||
| #### PolicyFiltering | ||
| - **`OnlyAssigned`** (default): Only test policies with device assignments | ||
| - **`All`**: Test all policies regardless of assignments | ||
| - **`None`**: Skip policy filtering entirely | ||
|
|
||
| #### DeviceFiltering | ||
| Controls which devices are considered when evaluating policies: | ||
|
|
||
| - **`OperatingSystems`**: `["Windows", "macOS", "iOS", "Android"]` | ||
| - **`ManagementAgents`**: `["msSense", "mdm", "configurationManager", "sccm"]` | ||
| - **`ComplianceStates`**: `["Compliant", "NonCompliant", "Unknown", "NotApplicable"]` | ||
|
|
||
| #### TestSpecific Overrides | ||
| Individual tests can override global settings: | ||
| ```json | ||
| "TestSpecific": { | ||
| "MDE.AV01": { | ||
| "ComplianceLogic": "AtLeastOne", | ||
| "PolicyFiltering": "All" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Architecture Complexity - Why Not Individual Files? | ||
|
|
||
| Initially, we considered creating separate test files for each antivirus setting (26 individual files). However, this approach became impractical due to Microsoft Graph API limitations: | ||
|
|
||
| ### API Response Challenges | ||
| - **Inconsistent Naming**: Settings don't follow predictable patterns (`_1`, `_2`, etc.) | ||
| - **Nested Structures**: Configuration policies use complex JSON with varying paths | ||
| - **Bulk Responses**: APIs return all settings together, not individually | ||
| - **Performance**: 26 separate API calls would be inefficient and hit rate limits | ||
|
|
||
| ### Unified Engine Benefits | ||
| Instead, we implemented a unified test engine that: | ||
| - Makes a single API call to retrieve all antivirus policies | ||
| - Processes 26 different settings from the same response | ||
| - Applies consistent compliance logic across all tests | ||
| - Reduces code duplication by 90% | ||
| - Handles skip conditions uniformly | ||
|
|
||
| ```powershell | ||
| # Single function handles all 26 antivirus tests | ||
| Invoke-MtMdeUnifiedTest -TestId "MDE.AV01" -ConfigKey "allowArchiveScanning" | ||
| Invoke-MtMdeUnifiedTest -TestId "MDE.AV02" -ConfigKey "allowBehaviorMonitoring" | ||
| # ... etc | ||
| ``` | ||
|
|
||
| ## Test Categories and Baseline | ||
|
|
||
| All tests are based on practical experience from real-world MDE deployments and industry best practices. The test categories reflect common security challenges: | ||
|
|
||
| ### 1. Antivirus Baseline (MDE.AV01-26) | ||
| Core protection settings that form the foundation of endpoint security: | ||
|
|
||
| | Test ID | Setting | Expected Value | Severity | Rationale | | ||
| |---------|---------|---------------|----------|-----------| | ||
| | MDE.AV01 | Archive Scanning | Enabled | 🟡 Medium | Malware often hides in compressed files | | ||
| | MDE.AV02 | Behavior Monitoring | Enabled | 🟠 High | Required for EDR capabilities | | ||
| | MDE.AV03 | Cloud Protection | Enabled | 🟠 High | Zero-day protection via cloud intelligence | | ||
| | MDE.AV06 | Realtime Monitoring | Enabled | 🔴 Critical | Core protection mechanism | | ||
| | MDE.AV17 | PUA Protection | Block Mode | 🟠 High | Prevents unwanted software installations | | ||
| | MDE.AV19 | Disable Local Admin Merge | Enabled | 🔴 Critical | Prevents local policy bypasses | | ||
| | MDE.AV20 | Tamper Protection | Enabled | 🔴 Critical | Protects against malicious disabling | | ||
|
|
||
| *Complete list includes 26 settings covering scan engines, cloud protection, scheduling, and remediation* | ||
|
|
||
| ### 2. Global Configuration (MDE.GC01-16) | ||
| Tenant-wide advanced features that enhance security posture: | ||
|
|
||
| | Test ID | Feature | Expected | Severity | Note | | ||
| |---------|---------|----------|----------|------| | ||
| | MDE.GC02 | Tamper Protection (Global) | On | 🟠 High | Tenant-wide enforcement | | ||
| | MDE.GC03 | EDR in Block Mode | On | 🟠 High | Only for Defender AV devices | | ||
| | MDE.GC07 | Custom Network Indicators | On | 🟠 High | IOC-based blocking | | ||
| | MDE.GC08 | Web Content Filtering | On | 🟠 High | Requires P2 licensing | | ||
|
|
||
| **Important**: Global configuration settings cannot currently be validated via Microsoft Graph API. Microsoft has not exposed these tenant-level settings through programmatic access. These tests are included but will be automatically skipped, serving as documentation of recommended settings that must be verified manually through the Microsoft 365 Defender portal. | ||
|
|
||
| ### 3. Policy Design Quality (MDE.PD01-04) | ||
| Governance and organizational best practices: | ||
|
|
||
| | Test ID | Check | Purpose | Severity | | ||
| |---------|-------|---------|----------| | ||
| | MDE.PD01 | Consistent Naming Convention | Policy organization | 🟢 Low | | ||
| | MDE.PD02 | Dedicated Exclusion Profiles | Separation of concerns | 🟡 Medium | | ||
| | MDE.PD03 | Granular Device Targeting | Least privilege principle | 🟡 Medium | | ||
| | MDE.PD04 | Staging Groups (Pilot→Prod) | Change management | 🟡 Medium | | ||
|
|
||
| ## Test Execution and Results | ||
|
|
||
| ### Severity Levels | ||
| - **🔴 Critical**: Core security functions that must never be disabled | ||
| - **🟠 High**: Important security features with significant impact | ||
| - **🟡 Medium**: Standard features that improve security posture | ||
| - **🟢 Low**: Performance optimizations and nice-to-have features | ||
|
|
||
| ### Skip Logic | ||
| Tests are automatically skipped when: | ||
| - No Graph connection available | ||
| - No MDE-enrolled devices found | ||
| - No relevant policies configured | ||
| - API permissions insufficient | ||
|
|
||
| ### Sample Usage | ||
| ```powershell | ||
| # Connect to required services | ||
| Connect-Maester -Service Graph | ||
|
|
||
| # Run all MDE tests with Maester | ||
| Invoke-Maester -Path "./tests/Maester/Defender/" | ||
|
|
||
| # Generate HTML report using Maester | ||
| Invoke-Maester -Path "./tests/Maester/Defender/" -OutputHtml "mde-report.html" | ||
| ``` | ||
|
|
||
| ## Test Tags and Organization | ||
|
|
||
| All MDE tests use consistent Pester tags for easy filtering and organization: | ||
|
|
||
| ### Tag Structure | ||
| - **`MDE`**: Applied to all MDE-related tests (universal tag) | ||
| - **`MDE-Antivirus`**: Antivirus policy content tests (MDE.AV01-26) | ||
| - **`MDE-GlobalConfig`**: Global configuration tests (MDE.GC01-16) | ||
| - **`MDE-PolicyDesign`**: Policy design quality tests (MDE.PD01-04) | ||
| - **`MDE-ASR`**: Attack Surface Reduction rules (planned/WIP) | ||
|
|
||
| ### Usage Examples | ||
| ```powershell | ||
| # Run all MDE tests | ||
| Invoke-Maester -Tag "MDE" | ||
|
|
||
| # Run only antivirus policy tests | ||
| Invoke-Maester -Tag "MDE-Antivirus" | ||
|
|
||
| # Run specific test by ID | ||
| Invoke-Maester -Tag "MDE.AV01" | ||
|
|
||
| # Exclude global config tests (since they skip anyway) | ||
| Invoke-Maester -Tag "MDE" -ExcludeTag "MDE-GlobalConfig" | ||
| ``` | ||
|
|
||
| ## Roadmap and Future Development | ||
|
|
||
| ### Work in Progress | ||
| - **ASR Rules Category**: Implementation of Attack Surface Reduction rules validation is planned and will follow the same unified engine pattern established for antivirus tests. | ||
|
|
||
| ## Integration with Maester Framework | ||
|
|
||
| This extension follows Maester's architectural principles: | ||
| - Uses existing connection management (`Connect-Maester`) | ||
| - Leverages framework helpers (`Add-MtTestResultDetail`, `Invoke-MtGraphRequest`) | ||
| - Maintains consistent test patterns and result formatting | ||
| - Preserves compatibility with framework updates |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| <# | ||
| .SYNOPSIS | ||
| Gets MDE configuration from defender-config.json | ||
|
|
||
| .DESCRIPTION | ||
| Loads test settings like compliance logic and device filtering from the config file. | ||
| Falls back to defaults if file isn't found. | ||
|
|
||
| .PARAMETER Path | ||
| Path to config file or directory. Defaults to tests/Maester/Defender. | ||
|
|
||
| .EXAMPLE | ||
| $config = Get-MtMdeConfig | ||
| Loads from default location | ||
|
|
||
| .EXAMPLE | ||
| $config = Get-MtMdeConfig -Path 'C:\custom' | ||
| Loads from custom path | ||
| #> | ||
|
|
||
| function Get-MtMdeConfig { | ||
| [CmdletBinding()] | ||
| [OutputType([object])] | ||
| param( | ||
| # Config file path or directory | ||
| [Parameter(Mandatory = $false)] | ||
| $Path | ||
| ) | ||
|
|
||
| # Use default location if none specified | ||
| if (-not $Path) { | ||
| $Path = Join-Path (Get-Location) "tests/Maester/Defender" | ||
| } | ||
|
|
||
| Write-Verbose "Getting MDE config from $Path" | ||
|
|
||
| try { | ||
| # Look for config file in directory or parent directories | ||
| if (Test-Path $Path -PathType Container) { | ||
| $ConfigFilePath = Join-Path -Path $Path -ChildPath 'defender-config.json' | ||
| if (-not (Test-Path -Path $ConfigFilePath)) { | ||
| Write-Verbose "Config file not found in $Path. Checking parent directories." | ||
| $defenderDir = Join-Path -Path $Path -ChildPath 'tests/Maester/Defender/defender-config.json' | ||
| if (Test-Path -Path $defenderDir) { | ||
| $ConfigFilePath = $defenderDir | ||
| } else { | ||
| # Search up to 5 parent directories | ||
| for ($i = 1; $i -le 5; $i++) { | ||
| if (Test-Path -Path $ConfigFilePath) { | ||
| break | ||
| } | ||
| $parentDir = Split-Path -Path $Path -Parent | ||
| if ($parentDir -eq $Path -or [string]::IsNullOrEmpty($parentDir)) { | ||
| break | ||
| } | ||
| $Path = $parentDir | ||
| $ConfigFilePath = Join-Path -Path $Path -ChildPath 'tests/Maester/Defender/defender-config.json' | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| # Use file path directly | ||
| $ConfigFilePath = $Path | ||
| } | ||
|
|
||
| if (-not (Test-Path -Path $ConfigFilePath)) { | ||
| Write-Verbose "MDE config file not found at $ConfigFilePath. Using default configuration." | ||
| # Use defaults when config file missing | ||
| return @{ | ||
| ComplianceLogic = "AllPolicies" | ||
| PolicyFiltering = "OnlyAssigned" | ||
| DeviceFiltering = @{ | ||
| OperatingSystems = @("Windows") | ||
| ManagementAgents = @("msSense", "mdm") | ||
| ComplianceStates = @("Compliant", "NonCompliant", "Unknown") | ||
| } | ||
| TestSpecific = @{} | ||
| } | ||
| } | ||
|
|
||
| Write-Verbose "Loading MDE config from $ConfigFilePath" | ||
| $configContent = Get-Content -Path $ConfigFilePath -Raw | ConvertFrom-Json | ||
|
|
||
| # Merge config with defaults | ||
| $config = @{ | ||
| ComplianceLogic = if ($configContent.ComplianceLogic) { $configContent.ComplianceLogic } else { "AllPolicies" } | ||
| PolicyFiltering = if ($configContent.PolicyFiltering) { $configContent.PolicyFiltering } else { "OnlyAssigned" } | ||
| DeviceFiltering = @{ | ||
| OperatingSystems = if ($configContent.DeviceFiltering.OperatingSystems) { $configContent.DeviceFiltering.OperatingSystems } else { @("Windows") } | ||
| ManagementAgents = if ($configContent.DeviceFiltering.ManagementAgents) { $configContent.DeviceFiltering.ManagementAgents } else { @("msSense", "mdm") } | ||
| ComplianceStates = if ($configContent.DeviceFiltering.ComplianceStates) { $configContent.DeviceFiltering.ComplianceStates } else { @("Compliant", "NonCompliant", "Unknown") } | ||
| } | ||
| TestSpecific = if ($configContent.TestSpecific) { $configContent.TestSpecific } else { @{} } | ||
| } | ||
|
|
||
| Write-Verbose "MDE config loaded successfully" | ||
| return $config | ||
|
|
||
| } catch { | ||
| Write-Warning "Failed to load MDE config from $ConfigFilePath`: $($_.Exception.Message). Using default configuration." | ||
| # Fall back to defaults on error | ||
| return @{ | ||
| ComplianceLogic = "AllPolicies" | ||
| PolicyFiltering = "OnlyAssigned" | ||
| DeviceFiltering = @{ | ||
| OperatingSystems = @("Windows") | ||
| ManagementAgents = @("msSense", "mdm") | ||
| ComplianceStates = @("Compliant", "NonCompliant", "Unknown") | ||
| } | ||
| TestSpecific = @{} | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.