diff --git a/src/Maester.psd1 b/src/Maester.psd1 index 54c3e673..d108f569 100644 --- a/src/Maester.psd1 +++ b/src/Maester.psd1 @@ -84,7 +84,8 @@ 'Test-MtCaMfaForGuests', 'Test-MtCaMfaForRiskySignIns', 'Test-MtCaRequirePasswordChangeForHighUserRisk', 'Test-MtCaSecureSecurityInfoRegistration', - 'Test-MtConditionalAccessWhatIf' + 'Test-MtConditionalAccessWhatIf', + 'Test-MtCaExclusionForDirectorySyncAccounts' # 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 = @() diff --git a/src/public/Test-MtCaExclusionForDirectorySyncAccounts.ps1 b/src/public/Test-MtCaExclusionForDirectorySyncAccounts.ps1 new file mode 100644 index 00000000..639d9532 --- /dev/null +++ b/src/public/Test-MtCaExclusionForDirectorySyncAccounts.ps1 @@ -0,0 +1,70 @@ +<# + .Synopsis + Checks if all conditional access policies scoped to all cloud apps exclude the directory synchronization accounts + + .Description + The directory synchronization accounts are used to synchronize the on-premises directory with Entra ID. + These accounts should be excluded from all conditional access policies scoped to all cloud apps. + Entra ID connect does not support multifactor authentication. + Restrict access with these accounts to trusted networks. + + Learn more: + https://learn.microsoft.com/entra/identity/conditional-access/howto-conditional-access-policy-admin-mfa + + .Example + Test-MtCaExclusionForDirectorySyncAccounts +#> + +Function Test-MtCaExclusionForDirectorySyncAccounts { + [CmdletBinding()] + [OutputType([bool])] + param () + + Set-StrictMode -Off + $DirectorySynchronizationAccountRoleTemplateId = "d29b2b05-8046-44ba-8758-1e26182fcf32" + $DirectorySynchronizationAccountRoleId = Invoke-MtGraphRequest -RelativeUri "directoryRoles(roleTemplateId='$DirectorySynchronizationAccountRoleId')" -Select id | Select-Object -ExpandProperty id + $DirectorySynchronizationAccounts = Invoke-MtGraphRequest -RelativeUri "directoryRoles/$DirectorySynchronizationAccountRoleId/members" -Select id | Select-Object -ExpandProperty id + + $policies = Get-MtConditionalAccessPolicies | Where-Object { $_.state -eq "enabled" } + + $result = $true + foreach ($policy in ( $policies | Sort-Object -Property displayName ) ) { + if ( $policy.conditions.applications.includeApplications -ne "All" ) { + # Skip this policy, because it does not apply to all applications + $currentresult = $true + Write-Verbose "Skipping $($policy.displayName) - $currentresult" + continue + } + + $PolicyIncludesAllUsers = $false + $PolicyIncludesRole = $false + $DirectorySynchronizationAccounts | ForEach-Object { + if ( $_ -in $policy.conditions.users.includeUsers ) { + $PolicyIncludesAllUsers = $true + } + } + if ( $DirectorySynchronizationAccountRoleTemplateId -in $policy.conditions.users.includeRoles ) { + $PolicyIncludesRole = $true + } + + if ( $PolicyIncludesAllUsers -or $PolicyIncludesRole ) { + # Skip this policy, because all directory synchronization accounts are included and therefor must not be excluded + $currentresult = $true + Write-Verbose "Skipping $($policy.displayName) - $currentresult" + } else { + if ( $DirectorySynchronizationAccountRoleTemplateId -in $policy.conditions.users.excludeRoles ) { + # Directory synchronization accounts are excluded + $currentresult = $true + } else { + # Directory synchronization accounts are not excluded + $currentresult = $false + $result = $false + } + } + + Write-Verbose "$($policy.displayName) - $currentresult" + } + Set-StrictMode -Version Latest + + return $result +} \ No newline at end of file diff --git a/tests/Identity/Test-ConditionalAccessBaseline.Tests.ps1 b/tests/Identity/Test-ConditionalAccessBaseline.Tests.ps1 index 2f90f5cb..86c8d725 100644 --- a/tests/Identity/Test-ConditionalAccessBaseline.Tests.ps1 +++ b/tests/Identity/Test-ConditionalAccessBaseline.Tests.ps1 @@ -54,4 +54,7 @@ Describe "Conditional Access Baseline Policies" -Tag "CA", "Security", "All" { It "ID1019: At least one Conditional Access policy is configured to enable application enforced restrictions. See https://maester.dev/t/ID1019" { Test-MtCaApplicationEnforcedRestrictions | Should -Be $true -Because "there is no policy that enables application enforced restrictions" } + It "ID1020: All Conditional Access policies are configured to exclude directory synchronization accounts or do not scope them. See https://maester.dev/t/ID1020" { + Test-MtCaExclusionForDirectorySyncAccounts | Should -Be $true -Because "there is no policy that excludes directory synchronization accounts" + } }