Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
23 changes: 23 additions & 0 deletions src/powershell/tests/Test-Assessment.25377.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Without Universal Tenant Restrictions (UTR) configured, users on corporate devices and networks can authenticate to unauthorized external Microsoft Entra tenants and access cloud applications using external identities, creating a significant data exfiltration vector. A threat actor who has compromised user credentials or established persistence on a corporate device can authenticate to a tenant they control using personal or external organizational identities, bypassing traditional network security controls that cannot inspect encrypted authentication traffic to Microsoft identity endpoints. Once authenticated to an external tenant, the actor can access Microsoft Graph APIs and cloud services, enabling data exfiltration through OneDrive, SharePoint, Teams, or any Microsoft Entra-integrated application in the external tenant. This attack path exploits the inherent trust that corporate networks and devices have with Microsoft identity services. Universal Tenant Restrictions address this by injecting tenant identity headers into authentication plane traffic via Global Secure Access, enabling Microsoft Entra ID to enforce tenant restrictions v2 policies that block authentication attempts to unauthorized external tenants.

**Remediation action**

Configure tenant restrictions v2 policies to block all external tenants by default
- [Set up tenant restrictions v2](https://learn.microsoft.com/en-us/entra/external-id/tenant-restrictions-v2)

Enable Universal Tenant Restrictions signaling in Global Secure Access
- [Turn on universal tenant restrictions](https://learn.microsoft.com/en-us/entra/global-secure-access/how-to-universal-tenant-restrictions)

Deploy Global Secure Access clients on devices
- [Global Secure Access clients overview](https://learn.microsoft.com/en-us/entra/global-secure-access/concept-clients)

Enable Microsoft traffic profile for Universal Tenant Restrictions
- [Microsoft traffic profile concept](https://learn.microsoft.com/en-us/entra/global-secure-access/concept-microsoft-traffic-profile)

**Who**: Global Secure Access Administrator (for Q1), Security Administrator or Global Administrator (for Q2)

**When**: During initial Global Secure Access deployment and before enabling production traffic forwarding

**Where**: Microsoft Entra admin center > Global Secure Access > Session Management > Universal Tenant Restrictions
<!--- Results --->
%TestResult%
179 changes: 179 additions & 0 deletions src/powershell/tests/Test-Assessment.25377.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<#
.SYNOPSIS
Validates that Universal Tenant Restrictions (UTR) are configured to block access to unauthorized external tenants.

.DESCRIPTION
This test checks if Universal Tenant Restrictions are properly configured by verifying:
1. Global Secure Access network packet tagging is enabled
2. Tenant restrictions v2 default policy blocks all users and all applications

.NOTES
Test ID: 25377
Category: Global Secure Access
Required API: networkAccess/settings/crossTenantAccess (beta), policies/crossTenantAccessPolicy/default (beta)
#>

function Test-Assessment-25377 {
[ZtTest(
Category = 'Global Secure Access',
ImplementationCost = 'Medium',
MinimumLicense = ('AAD_PREMIUM', 'Entra_Premium_Internet_Access'),
Pillar = 'Network',
RiskLevel = 'High',
SfiPillar = 'Protect networks',
TenantType = ('Workforce', 'External'),
TestId = 25377,
Title = 'Universal Tenant Restrictions block access to unauthorized external tenants',
UserImpact = 'Low'
)]
[CmdletBinding()]
param()

#region Data Collection
Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose
$activity = 'Checking Universal Tenant Restrictions configuration'
Write-ZtProgress -Activity $activity -Status 'Querying Global Secure Access network packet tagging status'

# Q1: Get Global Secure Access Universal Tenant Restrictions status
try {
$crossTenantAccessSettings = Invoke-ZtGraphRequest -RelativeUri 'networkAccess/settings/crossTenantAccess' -ApiVersion beta -ErrorAction Stop
$networkPacketTaggingStatus = $crossTenantAccessSettings.networkPacketTaggingStatus
}
catch {
Write-PSFMessage "Failed to retrieve Global Secure Access cross-tenant access settings: $_" -Tag Test -Level Warning
$networkPacketTaggingStatus = $null
}

Write-ZtProgress -Activity $activity -Status 'Querying tenant restrictions v2 default policy'

# Q2: Get default cross-tenant access policy tenant restrictions configuration
try {
$defaultCrossTenantPolicy = Invoke-ZtGraphRequest -RelativeUri 'policies/crossTenantAccessPolicy/default' -ApiVersion beta -ErrorAction Stop
$tenantRestrictions = $defaultCrossTenantPolicy.tenantRestrictions
}
catch {
Write-PSFMessage "Failed to retrieve cross-tenant access policy: $_" -Tag Test -Level Warning
$tenantRestrictions = $null
}
#endregion Data Collection

#region Assessment Logic
$testResultMarkdown = ''
$passed = $false

# Check Q1: Network packet tagging must be enabled
if ($null -eq $networkPacketTaggingStatus -or $networkPacketTaggingStatus -ne 'enabled') {
$statusText = if ($null -eq $networkPacketTaggingStatus) {
'not configured'
}
else {
$networkPacketTaggingStatus
}
$testResultMarkdown = "❌ Universal Tenant Restrictions are not fully configured. Network packet tagging is $statusText (expected: enabled). `n`n%TestResult%"
$passed = $false
}
else {
# Validate usersAndGroups configuration
$usersAndGroupsValid = $false
if ($tenantRestrictions.usersAndGroups) {
$usersAccessType = $tenantRestrictions.usersAndGroups.accessType
$usersTargets = $tenantRestrictions.usersAndGroups.targets

# Check if accessType is blocked and targets contain AllUsers
if ($usersAccessType -eq 'blocked' -and $usersTargets) {
$hasAllUsers = $usersTargets | Where-Object { $_.target -eq 'AllUsers' }
$usersAndGroupsValid = $null -ne $hasAllUsers
}
}

# Validate applications configuration
$applicationsValid = $false
if ($tenantRestrictions.applications) {
$appsAccessType = $tenantRestrictions.applications.accessType
$appsTargets = $tenantRestrictions.applications.targets

# Check if accessType is blocked and targets contain AllApplications
if ($appsAccessType -eq 'blocked' -and $appsTargets) {
$hasAllApplications = $appsTargets | Where-Object { $_.target -eq 'AllApplications' }
$applicationsValid = $null -ne $hasAllApplications
}
}

# Both must be valid for test to pass
if ($usersAndGroupsValid -and $applicationsValid) {
$testResultMarkdown = "✅ Universal Tenant Restrictions are configured. Network packet tagging is enabled and the default tenant restrictions v2 policy blocks all users from accessing all applications in unauthorized external tenants. `n`n%TestResult%"
$passed = $true
}
else {
$testResultMarkdown = "❌ Universal Tenant Restrictions are not fully configured. Tenant restrictions v2 policy does not block all users and all applications by default. `n`n%TestResult%"
$passed = $false
}
}
#endregion Assessment Logic

#region Report Generation
# Calculate all values and status icons
# Network Packet Tagging
$networkPacketDisplay = if ($null -eq $networkPacketTaggingStatus) { 'Not configured' } else { $networkPacketTaggingStatus }
$networkPacketIcon = if ($networkPacketTaggingStatus -eq 'enabled') { '✅' } else { '❌' }

# Users & Groups Access Type
$usersAccessTypeDisplay = if ($tenantRestrictions.usersAndGroups) { $tenantRestrictions.usersAndGroups.accessType } else { 'Not configured' }
$usersAccessIcon = if ($usersAccessTypeDisplay -eq 'blocked') { '✅' } else { '❌' }

# Users & Groups Target - extract targets array properly
$usersTargetsArray = @()
if ($tenantRestrictions.usersAndGroups.targets) {
$usersTargetsArray = @($tenantRestrictions.usersAndGroups.targets | ForEach-Object { $_.target })
}
$usersTargetDisplay = if ($usersTargetsArray.Count -gt 0) { $usersTargetsArray[0] } else { 'Not configured' }
$usersTargetIcon = if ($usersTargetsArray -contains 'AllUsers') { '✅' } else { '❌' }

# Applications Access Type
$appsAccessTypeDisplay = if ($tenantRestrictions.applications) { $tenantRestrictions.applications.accessType } else { 'Not configured' }
$appsAccessIcon = if ($appsAccessTypeDisplay -eq 'blocked') { '✅' } else { '❌' }

# Applications Target - extract targets array properly
$appsTargetsArray = @()
if ($tenantRestrictions.applications.targets) {
$appsTargetsArray = @($tenantRestrictions.applications.targets | ForEach-Object { $_.target })
}
$appsTargetDisplay = if ($appsTargetsArray.Count -gt 0) { $appsTargetsArray[0] } else { 'Not configured' }
$appsTargetIcon = if ($appsTargetsArray -contains 'AllApplications') { '✅' } else { '❌' }

# Build configuration table using format template
$formatTemplate = @'

## [{0}]({1})

| Setting | Current Value | Expected Value | Status |
| :------ | :------------ | :------------- | :----: |
{2}

'@

$reportTitle = 'Universal Tenant Restrictions Configuration'
$portalLink = 'https://entra.microsoft.com/#view/Microsoft_AAD_IAM/TenantRestrictions.ReactView/isDefault~/true/name//id/'

$tableRows = "| Network Packet Tagging Status | $networkPacketDisplay | enabled | $networkPacketIcon |`n"
$tableRows += "| Users & Groups Access Type | $usersAccessTypeDisplay | blocked | $usersAccessIcon |`n"
$tableRows += "| Users & Groups Target | $usersTargetDisplay | AllUsers | $usersTargetIcon |`n"
$tableRows += "| Applications Access Type | $appsAccessTypeDisplay | blocked | $appsAccessIcon |`n"
$tableRows += "| Applications Target | $appsTargetDisplay | AllApplications | $appsTargetIcon |"

$mdInfo = $formatTemplate -f $reportTitle, $portalLink, $tableRows

# Replace the placeholder with detailed information
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
#endregion Report Generation

$params = @{
TestId = '25377'
Title = 'Universal Tenant Restrictions block unauthorized external tenant access'
Status = $passed
Result = $testResultMarkdown
}

# Add test result details
Add-ZtTestResultDetail @params
}