Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/powershell/tests/Test-Assessment.21878.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
...

**Remediation action**

<!--- Results --->
%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
113 changes: 93 additions & 20 deletions src/powershell/tests/Test-Assessment.21878.ps1
Original file line number Diff line number Diff line change
@@ -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
}