diff --git a/src/powershell/tests/Test-Assessment.21878.md b/src/powershell/tests/Test-Assessment.21878.md index 6a740c432..4aedea2ec 100644 --- a/src/powershell/tests/Test-Assessment.21878.md +++ b/src/powershell/tests/Test-Assessment.21878.md @@ -1,6 +1,4 @@ -... - -**Remediation action** - - -%TestResult% +Without expiration dates, entitlement management policies create persistent access that threat actors can exploit for initial access. When user assignments lack time bounds, compromised credentials maintain access indefinitely, allowing threat actors to establish persistence within the environment. Threat actors can leverage these perpetual assignments to conduct credential access attacks against additional resources. Once threat actors gain initial access through compromised accounts with non-expiring assignments, they can perform privilege escalation by requesting additional access packages or extending existing permissions through the same entitlement management system.Without automatic expiration, threat actors can establish long-term persistence, potentially remaining undetected for extended periods while conducting data exfiltration or further reconnaissance activities. +Risk Level: Medium - Creates persistent access that can be exploited but requires initial compromise +User Impact: Medium - Users must request access renewals when assignments expire +Implementation Cost: Medium - Organizations need to establish access review processes and renewal workflows diff --git a/src/powershell/tests/Test-Assessment.21878.ps1 b/src/powershell/tests/Test-Assessment.21878.ps1 index f2342d501..ab9aabe7d 100644 --- a/src/powershell/tests/Test-Assessment.21878.ps1 +++ b/src/powershell/tests/Test-Assessment.21878.ps1 @@ -1,35 +1,108 @@ <# .SYNOPSIS - + Assessment 21878 – Verifies that all entitlement management policies have expiration dates configured #> -function Test-Assessment-21878{ +function Test-Assessment-21878 { [ZtTest( - Category = 'Access control', - ImplementationCost = 'Medium', - Pillar = 'Identity', - RiskLevel = 'Medium', - SfiPillar = 'Protect identities and secrets', - TenantType = ('Workforce','External'), - TestId = 21878, - Title = 'All entitlement management policies have an expiration date', - UserImpact = 'Medium' + Category = 'Access control', + ImplementationCost = 'Medium', + Pillar = 'Identity', + RiskLevel = 'Medium', + SfiPillar = 'Protect identities and secrets', + TenantType = ('Workforce','External'), + TestId = 21878, + Title = 'All entitlement management policies have an expiration date', + UserImpact = 'Medium' )] [CmdletBinding()] param() Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose - $activity = "Checking All entitlement management policies have an expiration date" - Write-ZtProgress -Activity $activity -Status "Getting policy" + $activity = 'Checking entitlement management assignment policies for expiration dates' + Write-ZtProgress -Activity $activity -Status 'Getting assignment policies' + + # Query entitlement management assignment policies (do not use $select for properties not supported by API) + $policies = Invoke-ZtGraphRequest -RelativeUri 'identityGovernance/entitlementManagement/assignmentPolicies' -ApiVersion v1.0 + + $matchingPolicies = @() + $nonMatchingPolicies = @() + + foreach ($policy in $policies) { + $expiration = $policy.expiration + $hasDuration = ($expiration.duration) -and ($expiration.type -eq 'afterDuration') + $hasEndDate = ($expiration.endDateTime) -and ($expiration.type -eq 'afterDateTime') + $meetsCriteria = ($hasDuration -or $hasEndDate) + + $detail = [PSCustomObject]@{ + PolicyId = $policy.id + DisplayName = $policy.displayName + ExpirationType = $expiration.type + Duration = $expiration.duration + EndDateTime = $expiration.endDateTime + AccessPackageId= $policy.accessPackageId + CatalogId = $policy.catalogId + CatalogName = $policy.catalogName + MeetsCriteria = $meetsCriteria + } + + if ($meetsCriteria) { + $matchingPolicies += $detail + } else { + $nonMatchingPolicies += $detail + } + } + + function Get-PolicyPortalLink { + param($policy) + $catalogName = [uri]::EscapeDataString($policy.CatalogName) + $entitlementName = [uri]::EscapeDataString($policy.DisplayName) + return 'https://portal.azure.com/#view/Microsoft_Azure_ELMAdmin/EntitlementMenuBlade/~/policies/entitlementId/{0}/catalogId/{1}/catalogName/{2}/entitlementName/{3}' -f $policy.AccessPackageId, $policy.CatalogId, $catalogName, $entitlementName + } + + $passed = ($nonMatchingPolicies | Measure-Object).Count -eq 0 + $testResultMarkdown = '' + + if ($passed) { + $testResultMarkdown += '✅ All entitlement management policies have expiration dates configured.' + } else { + $testResultMarkdown += '❌ Not all entitlement management policies have expiration dates configured.' + } + + if (-not $matchingPolicies) { + $testResultMarkdown += "`nNo entitlement management policies were found with expiration dates configured." + } else { + $testResultMarkdown += "`n### Entitlement Management Assignment Policies with Expiration Dates`n" + $testResultMarkdown += '| Name | Expiration Type | Duration | End DateTime |' + "`n" + $testResultMarkdown += '| :--- | :--- | :--- | :--- |' + "`n" + foreach ($item in $matchingPolicies) { + $duration = if ($item.Duration) { $item.Duration } else { '' } + $endDateTime = if ($item.EndDateTime) { $item.EndDateTime } else { '' } + $portalLink = Get-PolicyPortalLink $item + $testResultMarkdown += '| [{0}]({1}) | {2} | {3} | {4} |' -f (Get-SafeMarkdown $item.DisplayName), $portalLink, $item.ExpirationType, $duration, $endDateTime + $testResultMarkdown += "`n" + } + } - $result = $false - $testResultMarkdown = "Planned for future release." - $passed = $result + if ($nonMatchingPolicies.Count -gt 0) { + $testResultMarkdown += "`n#### Policies missing expiration:`n" + $testResultMarkdown += '| Name | Expiration Type | Duration | End DateTime |' + "`n" + $testResultMarkdown += '| :--- | :--- | :--- | :--- |' + "`n" + foreach ($item in $nonMatchingPolicies) { + $duration = if ($item.Duration) { $item.Duration } else { '' } + $endDateTime = if ($item.EndDateTime) { $item.EndDateTime } else { '' } + $portalLink = Get-PolicyPortalLink $item + $testResultMarkdown += '| [{0}]({1}) | {2} | {3} | {4} |' -f (Get-SafeMarkdown $item.DisplayName), $portalLink, $item.ExpirationType, $duration, $endDateTime + $testResultMarkdown += "`n" + } + } + $params = @{ + TestId = '21878' + Status = $passed + Result = $testResultMarkdown + } - Add-ZtTestResultDetail -TestId '21878' -Title "All entitlement management policies have an expiration date" ` - -UserImpact Medium -Risk Medium -ImplementationCost Medium ` - -AppliesTo Identity -Tag Identity ` - -Status $passed -Result $testResultMarkdown -SkippedBecause UnderConstruction + Add-ZtTestResultDetail @params }