-
Notifications
You must be signed in to change notification settings - Fork 123
Data - 35035 - Named Entity SITs Usage in Auto-Labeling and DLP Policies #855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
aahmed-spec
wants to merge
3
commits into
main
Choose a base branch
from
test-35035
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+718
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| Container labels extend sensitivity classification beyond individual files to entire collaboration workspaces including Microsoft Teams, Microsoft 365 Groups, and SharePoint sites. These labels control container-level settings such as external sharing policies, guest access permissions, device access restrictions, and privacy (public vs private). Without container labels, organizations cannot enforce consistent security policies at the workspace level, allowing users to create Teams with external guest access enabled even when handling confidential information. This gap creates data exfiltration risks where properly labeled documents exist within improperly secured collaboration spaces. Container labels ensure that workspace security posture matches the sensitivity of content stored within, preventing scenarios where "Highly Confidential" documents reside in Teams that permit external sharing. Organizations using Microsoft Teams or Microsoft 365 Groups for collaboration require container labels to maintain governance over workspace creation and access controls. | ||
|
|
||
| **Remediation action** | ||
| - Navigate to Microsoft Purview portal → Information protection → Labels | ||
| - Create a new label or edit existing label | ||
| - Under "Define the scope for this label", enable "Groups & sites". | ||
| - Configure container protection settings: | ||
| - Privacy (Public/Private) | ||
| - External user access | ||
| - External sharing | ||
| - Unmanaged device access | ||
| - Conditional Access policy | ||
| - Publish label through label policy. | ||
| - [Use sensitivity labels with Microsoft Teams, Microsoft 365 Groups, and SharePoint sites](https://learn.microsoft.com/en-us/purview/sensitivity-labels-teams-groups-sites) | ||
| <!--- Results ---> | ||
| %TestResult% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,276 @@ | ||
| <# | ||
| .SYNOPSIS | ||
| Validates that container labels are configured for Teams, Groups, and Sites. | ||
|
|
||
| .DESCRIPTION | ||
| This test evaluates sensitivity label configuration to ensure container labels | ||
| are enabled for Microsoft Teams, Microsoft 365 Groups, and SharePoint sites. | ||
| Container labels enforce consistent security policies at the workspace level, | ||
| controlling external sharing, guest access, and device restrictions. | ||
|
|
||
| .NOTES | ||
| Test ID: 35012 | ||
| Category: Sensitivity Labels Configuration | ||
| Required APIs: Get-Label (Exchange PowerShell) | ||
| #> | ||
|
|
||
| function Test-Assessment-35012 { | ||
|
|
||
| [ZtTest( | ||
| Category = 'Sensitivity Labels Configuration', | ||
| ImplementationCost = 'Medium', | ||
| MinimumLicense = 'Microsoft_365_E5', | ||
| Pillar = 'Data', | ||
| RiskLevel = 'Medium', | ||
| SfiPillar = 'Protect tenants and production systems', | ||
| TenantType = 'Workforce', | ||
| TestId = 35012, | ||
| Title = 'Container labels are configured for Teams, Groups, and Sites', | ||
| UserImpact = 'High' | ||
| )] | ||
| [CmdletBinding()] | ||
| param() | ||
|
|
||
| #region Helper Functions | ||
|
|
||
| function Get-ContainerLabelSummary { | ||
| <# | ||
| .SYNOPSIS | ||
| Extracts container protection settings from a sensitivity label's LabelActions JSON. | ||
| .OUTPUTS | ||
| PSCustomObject with container protection details. | ||
| #> | ||
| param( | ||
| [object]$Label, | ||
| [object]$ProtectGroupAction, | ||
| [object]$ProtectSiteAction | ||
| ) | ||
|
|
||
| # Extract content types from label | ||
| $contentType = if ($Label.ContentType) { $Label.ContentType -join ', ' } else { 'Not specified' } | ||
|
|
||
| # Extract Group Privacy Setting from protectgroup action | ||
| $groupPrivacy = 'Not configured' | ||
| if ($ProtectGroupAction -and $ProtectGroupAction.Settings) { | ||
| $privacySetting = $ProtectGroupAction.Settings | Where-Object { $_.Key -eq 'privacy' } | ||
| if ($privacySetting) { | ||
| $groupPrivacy = switch ($privacySetting.Value) { | ||
| '1' { 'Public' } | ||
| '2' { 'Private' } | ||
| default { $privacySetting.Value } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| # Extract Site External Sharing from protectsite action | ||
| $siteExternalSharing = 'Not configured' | ||
| $siteGuestAccess = 'Not configured' | ||
| if ($ProtectSiteAction -and $ProtectSiteAction.Settings) { | ||
| # External sharing setting | ||
| $sharingSetting = $ProtectSiteAction.Settings | Where-Object { $_.Key -eq 'externalsharingcontrol' } | ||
| if ($sharingSetting) { | ||
| $siteExternalSharing = switch ($sharingSetting.Value) { | ||
| '0' { 'Full Access' } | ||
| '1' { 'Limited Access' } | ||
| '2' { 'Block Access' } | ||
| default { $sharingSetting.Value } | ||
| } | ||
| } | ||
|
|
||
| # Guest access setting | ||
| $guestSetting = $ProtectSiteAction.Settings | Where-Object { $_.Key -eq 'allowaccesstoguestusers' } | ||
| if ($guestSetting) { | ||
| $siteGuestAccess = switch ($guestSetting.Value) { | ||
| 'true' { 'Allowed' } | ||
| 'false' { 'Blocked' } | ||
| default { $guestSetting.Value } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return [PSCustomObject]@{ | ||
| LabelName = $Label.DisplayName | ||
| LabelId = $Label.Guid | ||
| ContentType = $contentType | ||
| GroupPrivacySetting = $groupPrivacy | ||
| SiteExternalSharing = $siteExternalSharing | ||
| SiteGuestAccess = $siteGuestAccess | ||
| } | ||
| } | ||
|
|
||
| function Test-ContainerLabel { | ||
| <# | ||
| .SYNOPSIS | ||
| Tests if a label has both protectgroup and protectsite actions in LabelActions. | ||
| .OUTPUTS | ||
| Hashtable with IsContainer boolean and parsed actions, or $null if parsing fails. | ||
| #> | ||
| param([object]$Label) | ||
|
|
||
| try { | ||
| if ([string]::IsNullOrWhiteSpace($Label.LabelActions)) { | ||
| return @{ IsContainer = $false; ProtectGroup = $null; ProtectSite = $null } | ||
| } | ||
|
|
||
| $actions = $Label.LabelActions | ConvertFrom-Json -ErrorAction Stop | ||
| $protectGroup = $actions | Where-Object { $_.Type -eq 'protectgroup' } | ||
| $protectSite = $actions | Where-Object { $_.Type -eq 'protectsite' } | ||
|
|
||
| return @{ | ||
| IsContainer = ($null -ne $protectGroup -and $null -ne $protectSite) | ||
| ProtectGroup = $protectGroup | ||
| ProtectSite = $protectSite | ||
| } | ||
| } | ||
| catch { | ||
| # Return null to indicate parsing failure | ||
| return $null | ||
| } | ||
| } | ||
|
|
||
| #endregion Helper Functions | ||
|
|
||
| #region Data Collection | ||
|
|
||
| Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose | ||
| $activity = 'Evaluating container label configuration' | ||
| Write-ZtProgress -Activity $activity -Status 'Retrieving sensitivity labels' | ||
|
|
||
| # Query Q1: Retrieve all sensitivity labels | ||
| $allLabels = $null | ||
| $containerLabels = @() | ||
| $queryError = $false | ||
|
|
||
| try { | ||
| $allLabels = Get-Label -ErrorAction Stop | ||
| } | ||
| catch { | ||
| Write-PSFMessage -Level Warning -Message "Failed to retrieve sensitivity labels: $_" | ||
| $queryError = $true | ||
| } | ||
|
|
||
| # Query Q2: Filter for container-enabled labels (both protectgroup and protectsite actions) | ||
| $parseError = $false | ||
| $containerLabelData = @() | ||
|
|
||
| if ($null -ne $allLabels -and $allLabels.Count -gt 0) { | ||
|
|
||
| Write-ZtProgress -Activity $activity -Status 'Filtering container-enabled labels' | ||
|
|
||
| foreach ($label in $allLabels) { | ||
| $result = Test-ContainerLabel -Label $label | ||
| if ($null -eq $result) { | ||
| # JSON parsing failed for at least one label | ||
| $parseError = $true | ||
| } | ||
| elseif ($result.IsContainer) { | ||
| $containerLabelData += @{ | ||
| Label = $label | ||
| ProtectGroup = $result.ProtectGroup | ||
| ProtectSite = $result.ProtectSite | ||
| } | ||
| } | ||
| } | ||
|
|
||
| $containerLabels = $containerLabelData | ||
| } | ||
|
|
||
| #endregion Data Collection | ||
|
|
||
| #region Assessment Logic | ||
|
|
||
| # Initialize evaluation containers | ||
| $passed = $false | ||
| $customStatus = $null | ||
| $testResultMarkdown = '' | ||
| $labelResults = @() | ||
|
|
||
| # Step 1: Check if query execution failed | ||
| if ($queryError) { | ||
|
|
||
| $customStatus = 'Investigate' | ||
| $testResultMarkdown = | ||
| "⚠️ Query fails or LabelActions JSON cannot be parsed due to permissions issues or service connection failure. Ensure the Security & Compliance PowerShell module is connected and the account has appropriate permissions to retrieve label properties.`n`n%TestResult%" | ||
|
|
||
| } | ||
| # Step 2: Check if LabelActions JSON parsing failed for any label | ||
| elseif ($parseError) { | ||
|
|
||
| $customStatus = 'Investigate' | ||
| $testResultMarkdown = | ||
| "⚠️ Query fails or LabelActions JSON cannot be parsed due to permissions issues or service connection failure. Some labels could not be evaluated.`n`n%TestResult%" | ||
|
|
||
| } | ||
| # Step 3: Check if container labels exist (count >= 1) - Pass | ||
| elseif ($containerLabels.Count -ge 1) { | ||
|
|
||
| # Container labels are configured - Pass | ||
| $passed = $true | ||
| $testResultMarkdown = | ||
| "✅ Container labels are configured for Teams, Groups, and SharePoint sites.`n`n%TestResult%" | ||
|
|
||
| # Build label results for reporting | ||
| foreach ($data in $containerLabels) { | ||
| $labelResults += Get-ContainerLabelSummary -Label $data.Label -ProtectGroupAction $data.ProtectGroup -ProtectSiteAction $data.ProtectSite | ||
| } | ||
|
|
||
| } | ||
| # Step 4: Count = 0 - Fail | ||
| else { | ||
|
|
||
| # No container labels configured | ||
| # Per spec: "Fail: No container labels are configured (acceptable if Teams/Groups not used; may be a gap if collaboration workspaces exist)" | ||
| $passed = $false | ||
| $testResultMarkdown = | ||
| "❌ No container labels are configured (acceptable if Teams/Groups not used; may be a gap if collaboration workspaces exist).`n`n%TestResult%" | ||
|
|
||
| } | ||
|
|
||
| #endregion Assessment Logic | ||
|
|
||
| #region Report Generation | ||
|
|
||
| $mdInfo = "`n## Summary`n`n" | ||
| $mdInfo += "| Metric | Value |`n|---|---|`n" | ||
| $mdInfo += "| Total sensitivity labels | $(if ($allLabels) { $allLabels.Count } else { 0 }) |`n" | ||
| $mdInfo += "| Container-protected labels | $($containerLabels.Count) |`n`n" | ||
|
|
||
| if ($labelResults.Count -gt 0) { | ||
| $tableRows = "" | ||
| $formatTemplate = @' | ||
| ## [Container label details](https://purview.microsoft.com/informationprotection/informationprotectionlabels/sensitivitylabels) | ||
|
|
||
| | Label name | Content type | Group privacy setting | Site external sharing | Site guest access | | ||
| |---|---|---|---|---| | ||
| {0} | ||
|
|
||
| '@ | ||
| foreach ($r in $labelResults) { | ||
| $labelLink = "https://purview.microsoft.com/informationprotection/informationprotectionlabels/sensitivitylabels" | ||
| $linkedLabelName = "[{0}]({1})" -f (Get-SafeMarkdown $r.LabelName), $labelLink | ||
|
|
||
| $tableRows += "| $linkedLabelName | $($r.ContentType) | $($r.GroupPrivacySetting) | $($r.SiteExternalSharing) | $($r.SiteGuestAccess) |`n" | ||
| } | ||
| $mdInfo += $formatTemplate -f $tableRows | ||
| } | ||
|
|
||
| # Replace the placeholder with detailed information | ||
| $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo | ||
|
|
||
| #endregion Report Generation | ||
|
|
||
| $params = @{ | ||
| TestId = '35012' | ||
| Title = 'Container labels are configured for Teams, Groups, and Sites' | ||
| Status = $passed | ||
| Result = $testResultMarkdown | ||
| } | ||
|
|
||
| # Add CustomStatus if status is 'Investigate' | ||
| if ($null -ne $customStatus) { | ||
| $params.CustomStatus = $customStatus | ||
| } | ||
|
|
||
| # Add test result details | ||
| Add-ZtTestResultDetail @params | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| Named Entity Sensitive Information Types (SITs) are pre-built, Microsoft-managed classifiers designed to detect common sensitive entities like people's names, physical addresses, and medical terminology. Unlike custom SITs that organizations create for specific business needs, Named Entity SITs are provided by Microsoft and enable organizations to implement sophisticated data protection without requiring custom development. By configuring Named Entity SITs in auto-labeling policies and DLP rules, organizations can automatically classify and protect content containing sensitive personal information, employee data, and domain-specific terminology. This transforms data protection from purely technical pattern-matching (like detecting credit card numbers or social security numbers) into intelligent, semantically-aware classification systems that understand context. Organizations handling content with sensitive entity information—executive communications, customer data, medical records, or other high-sensitivity content—should deploy at least one Named Entity SIT in their protection policies. Demonstrating Named Entity SIT deployment shows sophisticated, context-aware information protection beyond basic generic SIT detection. | ||
|
|
||
| **Remediation action** | ||
|
|
||
| To deploy Named Entity SITs in your policies: | ||
|
|
||
| **Option 1: Deploy via DLP Policy** | ||
| 1. Sign in as Global Administrator or Compliance Administrator to the [Microsoft Purview portal](https://purview.microsoft.com) | ||
| 2. Navigate to [DLP Policies](https://purview.microsoft.com/datalossprevention/policies) | ||
| 3. Create a new DLP policy or edit an existing one | ||
| 4. Add a rule with condition: "Content contains sensitive information" | ||
| 5. Select Named Entity SITs from the dropdown: | ||
| - **All Full Names** - Detects common and uncommon full names worldwide | ||
| - **All Physical Addresses** - Detects addresses in various formats | ||
| - **All Medical Terms and Conditions** - Detects medical terminology and conditions | ||
| - **Country/Region-Specific Variants** - e.g., "Austria Physical Addresses", "Canada Physical Addresses" | ||
| 6. Configure the action (notify user, restrict access, send alert, etc.) | ||
| 7. Specify the workload scope (Exchange, SharePoint, OneDrive, Teams, Power BI) | ||
| 8. Enable and deploy the policy | ||
|
|
||
| **Option 2: Deploy via Auto-Labeling Policy** | ||
| 1. Navigate to [Auto-Labeling Policies](https://purview.microsoft.com/informationprotection/autolabeling) | ||
| 2. Create a new auto-labeling policy or edit an existing one | ||
| 3. In the rule configuration, add a condition: "Content contains sensitive information" | ||
| 4. From the sensitive information types list, select Named Entity SITs (e.g., "All Full Names") | ||
| 5. Configure the sensitivity label to apply when content matches | ||
| 6. Set the policy scope (Exchange, SharePoint, OneDrive, Teams, Power BI, or All) | ||
| 7. Enable and deploy the policy | ||
|
|
||
| **View Available Named Entity SITs:** | ||
| - Navigate to [Sensitive Information Types](https://purview.microsoft.com/informationprotection/dataclassification/multicloudsensitiveinfotypes) | ||
| - Named Entity SITs have `Classifier: EntityMatch` in their properties | ||
|
|
||
| **Query via PowerShell:** | ||
| ```powershell | ||
| Connect-IPPSSession | ||
| Get-DlpSensitiveInformationType | Where-Object { $_.Classifier -eq "EntityMatch" } | Select-Object Name, Classifier, Capability | ||
| ``` | ||
|
|
||
| **Example Scenarios:** | ||
| - **Protect Executive Communications**: Auto-label emails containing "All Full Names" with "Executive Communications" label | ||
| - **Protect Healthcare Records**: DLP rule blocking external sharing of content with "All Medical Terms and Conditions" | ||
| - **Address Data Protection**: DLP rule restricting content with "All Physical Addresses" to internal sharing only | ||
|
|
||
| <!--- Results ---> | ||
| %TestResult% |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The MinimumLicense value 'Microsoft_365_E5' uses underscores instead of spaces, which is inconsistent with the license naming convention used throughout the codebase. Other similar tests use 'Microsoft 365 E5' with spaces (as seen in Test-Assessment.35032.ps1 line 26 and other files). This inconsistency could cause issues with license checking logic.