Skip to content

Commit

Permalink
Merge pull request #389 from maester365/jbtn-CaGroupRmau
Browse files Browse the repository at this point in the history
Added test MT.1035 for checking RMAU-protection of security groups in Conditional Access Policies
  • Loading branch information
merill authored Jul 31, 2024
2 parents 00c8f71 + 7d3fa91 commit 4ec5c20
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
1 change: 1 addition & 0 deletions powershell/Maester.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae
'Test-MtCaExclusionForDirectorySyncAccount',
'Test-MtCaLicenseUtilization', 'Test-MtCaMfaForAdmin',
'Test-MtCaMfaForAdminManagement', 'Test-MtCaMfaForAllUsers',
"Test-MtCaGroupsRestricted",
'Test-MtCaMfaForGuest', 'Test-MtCaMfaForRiskySignIn',
'Test-MtCaRequirePasswordChangeForHighUserRisk',
'Test-MtCaSecureSecurityInfoRegistration', 'Test-MtCisaDiagnosticSettings',
Expand Down
11 changes: 9 additions & 2 deletions powershell/internal/Get-GraphObjectMarkdown.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ function Get-GraphObjectMarkdown {
[ValidateSet('AuthenticationMethod', 'AuthorizationPolicy', 'ConditionalAccess', 'ConsentPolicy',
'Devices', 'Domains', 'Groups', 'IdentityProtection', 'Users', 'UserRole'
)]
[string] $GraphObjectType
[string] $GraphObjectType,

[Parameter(Mandatory = $false)]
[switch] $AsPlainTextLink
)

$markdownLinkTemplate = @{
Expand All @@ -45,7 +48,11 @@ function Get-GraphObjectMarkdown {
$result = ""
foreach ($item in $GraphObjects) {
$link = $markdownLinkTemplate[$GraphObjectType] -f $item.id
$result += " - [$($item.displayName)]($link)`n"
if ($AsPlainTextLink) {
$result += "[$($item.displayName)]($link)"
} else {
$result += " - [$($item.displayName)]($link)`n"
}
}

return $result
Expand Down
85 changes: 85 additions & 0 deletions powershell/public/Test-MtCaGroupsRestricted.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<#
.Synopsis
Checks if groups used in Conditional Access are protected by either Restricted Management Administrative Units or Role Assignable Groups.
.Description
Security Groups will be used to exclude and include users from Conditional Access Policies.
Modify group membership outside of Conditional Access Administrator or other privileged roles can lead to bypassing Conditional Access Policies.
To prevent this, you can protect these groups by using Restricted Management Administrative Units or Role Assignable Groups.
Role Assignable Group should be used in combination of assignments to Entra ID roles. Restricted Management Administrative Units should be used to protect groups by restricting management to specific users or groups.
This test checks if all groups used in Conditional Access Policies are protected.
Learn more:
https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/admin-units-restricted-management
.Example
Test-MtCaGroupsRestricted
.LINK
https://maester.dev/docs/commands/Test-MtCaGroupsRestricted
#>

Function Test-MtCaGroupsRestricted {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'Exists is not a plural.')]
[CmdletBinding()]
[OutputType([bool])]
param ()

if ( ( Get-MtLicenseInformation EntraID ) -eq "Free" ) {
Add-MtTestResultDetail -SkippedBecause NotLicensedEntraIDP1
return $null
}

$Policies = Get-MtConditionalAccessPolicy | Where-Object { $_.state -eq "enabled" }

$Groups = $Policies.conditions.users | Where-Object {
@($_.includeGroups).Count -gt 0 -or @($_.excludeGroups).Count -gt 0
} | ForEach-Object {
$_.includeGroups + $_.excludeGroups
} | Select-Object -Unique


$GroupsDetail = foreach ($Group in $Groups) {
try {
Invoke-MtGraphRequest -RelativeUri "groups/$($Group)" -ApiVersion beta | Select-Object displayName, isManagementRestricted, isAssignableToRole, id
}
catch {
Write-Verbose "Group $Group not found"
}
}

$UnrestrictedGroups = $GroupsDetail | Where-Object {
-not $_.isManagementRestricted -and -not $_.isAssignableToRole
}

$result = ($unrestrictedGroups | Measure-Object).Count -eq 0

if ( $result ) {
$ResultDescription = "Well done! All security groups with assignment in Conditional Access are protected!"
} else {
$ResultDescription = "These security groups with assignments in Conditional Access are not protected by Restricted Management Admin Units or Role Assignable groups."
$ImpactedCaGroups = "`n`n#### Impacted Conditional Access Policies`n`n | Security Group | Condition | Policy name | `n"
$ImpactedCaGroups += "| --- | --- | --- |`n"
}

foreach ($UnrestrictedGroup in $UnrestrictedGroups) {
$ImpactedPolicies = Get-MtConditionalAccessPolicy | Where-Object { $_.conditions.users.includeGroups -contains $UnrestrictedGroup.id -or $_.conditions.users.excludeGroups -contains $UnrestrictedGroup.id }
foreach ($ImpactedPolicy in $ImpactedPolicies) {
if ($ImpactedPolicy.conditions.users.includeGroups -contains $UnrestrictedGroup.id) {
$Condition = "include"
} elseif ($ImpactedPolicy.conditions.users.excludeGroups -contains $UnrestrictedGroup.id) {
$Condition = "exclude"
} else {
$Condition = "Unknown"
}
$Policy = (Get-GraphObjectMarkdown -GraphObjects $ImpactedPolicy -GraphObjectType ConditionalAccess -AsPlainTextLink)
$Group = (Get-GraphObjectMarkdown -GraphObjects $UnrestrictedGroup -GraphObjectType Groups -AsPlainTextLink)
$ImpactedCaGroups += "| $($Group) | $($Condition) | $($Policy) | `n"
}
}

$resultMarkdown = $ResultDescription + $ImpactedCaGroups
Add-MtTestResultDetail -Description $testDescription -Result $resultMarkdown

return $result
}
3 changes: 3 additions & 0 deletions tests/Maester/Entra/Test-ConditionalAccessBaseline.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
It "MT.1020: All Conditional Access policies are configured to exclude directory synchronization accounts or do not scope them. See https://maester.dev/docs/tests/MT.1020" -Tag "MT.1020" {
Test-MtCaExclusionForDirectorySyncAccount | Should -Be $true -Because "there is no policy that excludes directory synchronization accounts"
}
It "MT.1035: All security groups assigned to Conditional Access Policies should be protected by RMAU. See https://maester.dev/docs/tests/MT.1035" -Tag "MT.1035" {
Test-MtCaGroupsRestricted | Should -Be $true -Because "there is one or more policy without protection of included or excluded groups"
}
Context "License utilization" {
It "MT.1022: All users utilizing a P1 license should be licensed. See https://maester.dev/docs/tests/MT.1022" -Tag "MT.1022" {
$LicenseReport = Test-MtCaLicenseUtilization -License "P1"
Expand Down
22 changes: 22 additions & 0 deletions website/docs/tests/maester/MT.1035.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: MT.1035 - All security groups assigned to Conditional Access Policies should be protected by RMAU
description: Checks if groups used in Conditional Access are protected by either Restricted Management Administrative Units or Role Assignable Groups
slug: /tests/MT.1035
sidebar_class_name: hidden
---

# All security groups assigned to Conditional Access Policies should be protected by RMAU

## Description

Security Groups will be used to exclude and include users from Conditional Access Policies.
Modify group membership outside of Conditional Access Administrator or other privileged roles can lead to bypassing Conditional Access Policies. To prevent this, you can protect these groups by using Restricted Management Administrative Units or Role Assignable Groups. Role Assignable Group should be used in combination of assignments to Entra ID roles. Restricted Management Administrative Units should be used to protect groups by restricting management to specific users or groups. This test checks if all groups used in Conditional Access Policies are protected.

## How to fix

Assign security groups to Restricted Management Administrative Unit (RMAU).

## Learn more
- [Microsoft Learn | Restricted management administrative units in Microsoft Entra ID (Preview)](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/admin-units-restricted-management)
- [janbakker.tech | Prevent Conditional Access bypass with Restricted Management Administrative Units in Entra ID](https://janbakker.tech/prevent-conditional-access-bypass-with-restricted-management-administrative-units-in-entra-id/)
- [Cloud-Architekt.net | Protection of privileged users and groups by Azure AD Restricted Management Administrative Units](https://www.cloud-architekt.net/restricted-management-administrative-unit/)

0 comments on commit 4ec5c20

Please sign in to comment.