-
Notifications
You must be signed in to change notification settings - Fork 198
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
Enhanced Defender license warnings for policy groups 2 and 4 #929
base: main
Are you sure you want to change the base?
Enhanced Defender license warnings for policy groups 2 and 4 #929
Conversation
1e35219
to
dc3dc6e
Compare
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 licensing relationship to policy group 4, particularly 4.2 is a bit more granular and tricky than just adding a warning. This might require some additional thinking about how best to report status on a policy item that contains a mix of both license required and non-license required items. Technically, without the license a tenant cannot meet the requirement, but without details about specific locations the admin doesn't have sufficient feedback to determine if the issue is due to license, DLP policy config, or a combination of both. See full comments below.
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.
Getting closer, but recommend additional code to better delineate which locations are not meeting the baseline rather than a generic message. See comments below.
@@ -972,9 +917,10 @@ test_Locations_Incorrect_V6 if { | |||
"defender_license": true | |||
} | |||
|
|||
ReportDetailString := "No DLP policy matching all types found for evaluation." | |||
ReportDetailString := "No enabled policy found that applies to: Devices, Exchange, OneDrive, SharePoint, Teams" |
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.
As is, I don't believe this string provides the necessary additional details. It lists all the locations from the baseline policy, regardless of those in a current DLP policy. The goal is to provide the specific locations not present in an otherwise matching DLP policy. For example, if a tenant had a DLP policy with all the sensitive info types for 4.1, but only set to locations Exchange, OneDrive, and SharePoint, then the report details should indicate the policy name that matches 4.1 and which locations it is missing (Devices, Teams). Additionally, there could be multiple DLP policies matching 4.1 but missing locations. So it might be a set of DLP policies and listing the missing locations for each. Although at least a set of locations, even it if doesn't call out specific policies.
Not easy, but those are the details that would be useful to the user.
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.
While I agree, there is also the complexity of the number of policies. There could be multiple policies covering different parts or multiple policies covering one part like teams. De tangling that and accounting for that in the code can become complex & result in to long of a string fast. So I believe we opted for putting the additional information about policies, their state, & relation to the products in the results json under ActualValue
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.
That's a good point. I think the missing bit here in the report details then is a string that tells them where to look for additional details and confirming those details are present in ActualValue. So I'm going to rework this accordingly.
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.
@Sloane4 Updated error message to include a line pointing users to the ActualValue
field in the TestResults.json file. The filename and path are taken from the scuba_config key so they will be correct for any given invocation.
PowerShell/ScubaGear/Testing/Unit/Rego/Defender/DefenderConfig_04_test.rego
Outdated
Show resolved
Hide resolved
PowerShell/ScubaGear/Testing/Unit/Rego/Defender/DefenderConfig_04_test.rego
Outdated
Show resolved
Hide resolved
"your tenant does not have a license for Microsoft Defender", | ||
"for Office 365 Plan 1 or Plan 2, which is required for this feature.**" |
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.
This utility method was intentionally vague about licenses because it is used by both policy group 1 (which relies on Office365 Plan 1 or 2) and policy group 4 (which relies on either DLP for Teams and DLP for Endpoint). So you can't replace the generic string directly with Office365 Plan 1 or 2. To provide more specific messaging, you would need to have the function take the policy ID and change the string based on the policy group, perhaps with the old generic default for groups other than 1 and 4 as a backup.
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.
You can chain the functions, you just have to update the previous uses of the functions
# If a defender license is not present, assume failure and
# replace the message with the warning for Office 365 license
ApplyLicenseWarning(_, "Office") := concat(" ", [FAIL, LicenseWarning]) if {
input.defender_license == false
LicenseWarning := concat(" ", [
"**NOTE: Either you do not have sufficient permissions or",
"your tenant does not have a license for Microsoft Defender",
"for Office 365 Plan 1, which is required for this feature.**"
])
}
# If a defender license is not present, assume failure and
# replace the message with the warning for DLP license
ApplyLicenseWarning(_, "Dlp") := concat(" ", [FAIL, LicenseWarning]) if {
input.defender_license == false
LicenseWarning := concat(" ", [
"**NOTE: Either you do not have sufficient permissions or",
"your tenant does not have a license for Microsoft Defender",
"for DLP for Teams or DLP for Endpoint, which is required for this feature.**"
])
}
This way you don't have to make another method for every license.
Example use case: "ReportDetails": ApplyLicenseWarning(Status, "Office")
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.
It got a bit more complex than that given the variety of scenarios. But the updated results are such that the error message ends up including just the right information for any given scenario and only points out the specific license requirement for the specific missing locations. See implementation in the DefenderConfig.rego for 4.2.
PowerShell/ScubaGear/Testing/Unit/Rego/Defender/DefenderConfig_02_test.rego
Outdated
Show resolved
Hide resolved
PowerShell/ScubaGear/Testing/Unit/Rego/Defender/DefenderConfig_04_test.rego
Show resolved
Hide resolved
Also added fix for powershell bugs #976 |
1a644f8
to
9b00f72
Compare
f996684
to
81f2021
Compare
$Tracker.AddUnSuccessfulCommand("Get-DlpCompliancePolicy") | ||
$Tracker.AddUnSuccessfulCommand("Get-DlpComplianceRule") | ||
$Tracker.AddUnSuccessfulCommand("Get-ProtectionAlert") | ||
$Tracker.AddSuccessfulCommand("Get-DlpCompliancePolicy") | ||
$Tracker.AddSuccessfulCommand("Get-DlpComplianceRule") | ||
$Tracker.AddSuccessfulCommand("Get-ProtectionAlert") |
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.
If this is triggered for unsuccessful commands, why are they added to successful commands as well?
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.
Similar to the section above it for ATP related commands, it is a case where we don't want the auto-generated error in the report about the unsuccessful commands because we handle this case with the dlp_license flag instead and have the Rego provide a more detailed DLP license warning error instead. The missing commands are how we detect the condition. By adding it to both unsuccessful and successful, we prevent the CreateReport module from adding a generic warning about missing commands that would indicate a code bug.
# Show matching policies | ||
has_policies contains "Exchange" if count(Policies.Exchange) > 0 | ||
|
||
DefenderErrorMessage4_2 := ErrorMessage if { | ||
count(PoliciesWithFullProtection) == 0 | ||
ErrorMessage := "No DLP policy matching all types found for evaluation." | ||
} | ||
has_policies contains "SharePoint" if count(Policies.SharePoint) > 0 | ||
|
||
has_policies contains "OneDrive" if count(Policies.OneDrive) > 0 | ||
|
||
has_policies contains "Teams" if count(Policies.Teams) > 0 | ||
|
||
has_policies contains "Devices" if count(Policies.Devices) > 0 |
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.
could this be shortened to simple set arithmetic? We already have error_policies to work off of, so we can just subtract a set of all names form the resulting error_policies set.
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.
Yes, see the assignment to PresentLocations on line 631 in the 4.2 test. Uses set arithmetic as you indicated.
"your tenant does not have a license for Microsoft Defender", | ||
"for Office 365 Plan 1 or Plan 2, which is required for this feature.**" |
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.
You can chain the functions, you just have to update the previous uses of the functions
# If a defender license is not present, assume failure and
# replace the message with the warning for Office 365 license
ApplyLicenseWarning(_, "Office") := concat(" ", [FAIL, LicenseWarning]) if {
input.defender_license == false
LicenseWarning := concat(" ", [
"**NOTE: Either you do not have sufficient permissions or",
"your tenant does not have a license for Microsoft Defender",
"for Office 365 Plan 1, which is required for this feature.**"
])
}
# If a defender license is not present, assume failure and
# replace the message with the warning for DLP license
ApplyLicenseWarning(_, "Dlp") := concat(" ", [FAIL, LicenseWarning]) if {
input.defender_license == false
LicenseWarning := concat(" ", [
"**NOTE: Either you do not have sufficient permissions or",
"your tenant does not have a license for Microsoft Defender",
"for DLP for Teams or DLP for Endpoint, which is required for this feature.**"
])
}
This way you don't have to make another method for every license.
Example use case: "ReportDetails": ApplyLicenseWarning(Status, "Office")
@@ -972,9 +917,10 @@ test_Locations_Incorrect_V6 if { | |||
"defender_license": true | |||
} | |||
|
|||
ReportDetailString := "No DLP policy matching all types found for evaluation." | |||
ReportDetailString := "No enabled policy found that applies to: Devices, Exchange, OneDrive, SharePoint, Teams" |
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.
While I agree, there is also the complexity of the number of policies. There could be multiple policies covering different parts or multiple policies covering one part like teams. De tangling that and accounting for that in the code can become complex & result in to long of a string fast. So I believe we opted for putting the additional information about policies, their state, & relation to the products in the results json under ActualValue
b952bc7
to
ccafb10
Compare
ccafb10
to
6d0ab73
Compare
* Add DLP license warning details for Teams and Devices * Update unit tests to handle message changes
* Add tests that show fail when license not present in G3
* Remove invalid test test_Locations_Incorrect_V9
32e0145
to
9567336
Compare
π£ Description
Add licenses check for policy groups 2 and 4 in addition to the current check, make the report details more precise. And let user be more aware of the missing licenses.
π Motivation and context
closes #599
π§ͺ Testing
Run Scuba for Defender
Change the json file mainly "defender_license" to "false"
Run Scuba for Defender again
Will see warning about Defender license missing during the run
Will see notes on reports indicates license missing
Note: the check for policy group 2 and 4 will still pass or fail based on the environment setting because we are modifying the json file from an tenant with required licenses. The result is still be accurate based on the environment information. Note that, normally it will fail if they don't have license due to missing information from the provider JSON.
β Pre-approval checklist
β Pre-merge checklist
PR passed smoke test check.
Feature branch has been rebased against changes from parent branch, as needed
Use
Rebase branch
button below or use this reference to rebase from the command line.Resolved all merge conflicts on branch
Notified merge coordinator that PR is ready for merge via comment mention
β Post-merge checklist