Skip to content

Commit

Permalink
Enhance AAD Provider and Rego Code to automate checks for policy MS.A…
Browse files Browse the repository at this point in the history
…AD.3.3v1 (#1014)

* Update provider json for  auth method config

* Added new json for MS auth feature settings

* Combined authentication method calls into one json object

* Updates to JSON for aad 3.4 and 3.5

* updates to aad 3.3 rego

* Include all auth method configs in json export

* Updates to aad 3.3 to check msauth settings

* Updates to unit tests for aad 3.4

* Update AADConfig.rego 3.3v1 status check

* fix N/A criticality for 3.5 and adjust unit and functional tests for new JSON structure

* changed JSON structure for 3.4, 3.5 because it had redundant objects and updated all tests

* fix run unit test

* revised 3.3 unit tests

* update 3.3 code & added unit tests

* refactored names and added comments to 3.3 policy

* refactored 3.4 to reduce redundant code and bad variable naming

* streamlined code for 3.5 to reduce redundancy and returned ActualValue which was missing

* renamed MFAPolicies to PhishingResistantMFAPolicies for accuracy

* initial version 3.3 functional test wip

* added functional test cases

* removed NotCheckedDetails import since linter complained

* made AuthenticationPolicyMigrationIsComplete shorter due to linter complaints

* changed AuthenticationPolicyMigrationIsComplete from boolean assignment to if due to linter

* removed redundant call to Get-MgBetaPolicyAuthenticationMethodPolicy which was left by mistake

---------

Co-authored-by: Ted Kolovos <[email protected]>
Co-authored-by: Sloane4 <[email protected]>
  • Loading branch information
3 people committed Apr 30, 2024
1 parent 65ee0a1 commit b6d3bbc
Show file tree
Hide file tree
Showing 6 changed files with 963 additions and 161 deletions.
26 changes: 22 additions & 4 deletions PowerShell/ScubaGear/Modules/Providers/ExportAADProvider.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,25 @@ function Export-AADProvider {
# 5.3, 5.4
$DirectorySettings = ConvertTo-Json -Depth 10 @($Tracker.TryCommand("Get-MgBetaDirectorySetting"))

# Read the properties and relationships of an authentication method policy
$AuthenticationMethodPolicy = ConvertTo-Json @($Tracker.TryCommand("Get-MgBetaPolicyAuthenticationMethodPolicy")) -Depth 5
##### This block of code below supports 3.3, 3.4, 3.5
$AuthenticationMethodPolicyRootObject = $Tracker.TryCommand("Get-MgBetaPolicyAuthenticationMethodPolicy")

# 6.1
$AuthenticationMethodFeatureSettings = @($AuthenticationMethodPolicyRootObject.AuthenticationMethodConfigurations | Where-Object { $_.Id})

# Exclude the AuthenticationMethodConfigurations so we do not duplicate it in the JSON
$AuthenticationMethodPolicy = $AuthenticationMethodPolicyRootObject | ForEach-Object {
$_ | Select-Object * -ExcludeProperty AuthenticationMethodConfigurations
}

$AuthenticationMethodObjects = @{
authentication_method_policy = $AuthenticationMethodPolicy
authentication_method_feature_settings = $AuthenticationMethodFeatureSettings
}

$AuthenticationMethod = ConvertTo-Json -Depth 10 @($AuthenticationMethodObjects)
##### End block

# 6.1
$DomainSettings = ConvertTo-Json @($Tracker.TryCommand("Get-MgBetaDomain"))

$SuccessfulCommands = ConvertTo-Json @($Tracker.GetSuccessfulCommands())
Expand All @@ -125,7 +140,7 @@ function Export-AADProvider {
"privileged_roles": $PrivilegedRoles,
"service_plans": $ServicePlans,
"directory_settings": $DirectorySettings,
"authentication_method": $AuthenticationMethodPolicy,
"authentication_method": $AuthenticationMethod,
"domain_settings": $DomainSettings,
"license_information": $LicenseInfo,
"total_user_count": $UserCount,
Expand All @@ -136,6 +151,9 @@ function Export-AADProvider {
$json
}

#"authentication_method_policy": $AuthenticationMethodPolicy,
#"authentication_method_configuration": $AuthenticationMethodConfiguration,
#"authentication_method_feature_settings": $AuthenticationMethodFeatureSettings,
function Get-AADTenantDetail {
<#
.Description
Expand Down
135 changes: 93 additions & 42 deletions PowerShell/ScubaGear/Rego/AADConfig.rego
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ tests contains {
# If policy matches basic conditions, special conditions,
# all exclusions are intentional, & none but acceptable MFA
# are allowed, save the policy name
MFAPolicies contains CAPolicy.DisplayName if {
PhishingResistantMFAPolicies contains CAPolicy.DisplayName if {
some CAPolicy in input.conditional_access_policies

"All" in CAPolicy.Conditions.Users.IncludeUsers
Expand All @@ -197,23 +197,23 @@ tests contains {
"PolicyId": "MS.AAD.3.1v1",
"Criticality": "Shall",
"Commandlet": ["Get-MgBetaIdentityConditionalAccessPolicy"],
"ActualValue": MFAPolicies,
"ReportDetails": concat(". ", [ReportFullDetailsArray(MFAPolicies, DescriptionString), CAPLINK]),
"ActualValue": PhishingResistantMFAPolicies,
"ReportDetails": concat(". ", [ReportFullDetailsArray(PhishingResistantMFAPolicies, DescriptionString), CAPLINK]),
"RequirementMet": Status
} if {
DescriptionString := "conditional access policy(s) found that meet(s) all requirements"
Status := count(MFAPolicies) > 0
Status := count(PhishingResistantMFAPolicies) > 0
}
#--

#
# MS.AAD.3.2v1
#--

# Save all policy names if MFAPolicies exist
# Save all policy names if PhishingResistantMFAPolicies exist
AlternativeMFA contains CAPolicy.DisplayName if {
some CAPolicy in input.conditional_access_policies
Count(MFAPolicies) > 0
Count(PhishingResistantMFAPolicies) > 0
}

# If policy matches basic conditions, special conditions,
Expand Down Expand Up @@ -248,75 +248,126 @@ tests contains {
# MS.AAD.3.3v1
#--

# At this time we are unable to test for X because of NEW POLICY
# If we have acceptable MFA then policy passes otherwise MS Authenticator need to be
# enabled to pass. However, we can not currently check if MS Authenticator enabled
tests contains {
"PolicyId": "MS.AAD.3.3v1",
"Criticality": "Shall",
"Commandlet": ["Get-MgBetaIdentityConditionalAccessPolicy"],
"ActualValue": MFAPolicies,
"ReportDetails": concat(". ", [ReportFullDetailsArray(MFAPolicies, DescriptionString), CAPLINK]),
"RequirementMet": Status
} if {
DescriptionString := "conditional access policy(s) found that meet(s) all requirements"
Status := count(MFAPolicies) > 0
count(MFAPolicies) > 0
# Returns the MS Authenticator configuration settings
MSAuth := auth_setting if {
some auth_method in input.authentication_method
some auth_setting in auth_method.authentication_method_feature_settings

auth_setting.Id == "MicrosoftAuthenticator"
}

# Returns true if MS Authenticator is enabled, false if it is not
default MSAuthEnabled := false
MSAuthEnabled := true if {
MSAuth.State == "enabled"
}

# Returns true if MS Authenticator is configured per the baseline, false if it is not
default MSAuthProperlyConfigured := false
MSAuthProperlyConfigured := true if {
MSAuth.State == "enabled"

# Make sure that MS Auth shows the app name and geographic location
Settings := MSAuth.AdditionalProperties.featureSettings
Settings.displayAppInformationRequiredState.state == "enabled"
Settings.displayLocationInformationRequiredState.state == "enabled"

# Make sure that the configuration applies to all users
some target in MSAuth.AdditionalProperties.includeTargets
target.id == "all_users"
}

default AAD_3_3_Not_Applicable := false
# Returns true no matter what if phishing-resistant MFA is being enforced
AAD_3_3_Not_Applicable := true if {
count(PhishingResistantMFAPolicies) > 0
}

# Returns true if phishing-resistant MFA is not being enforced but MS Auth is disabled
AAD_3_3_Not_Applicable := true if {
count(PhishingResistantMFAPolicies) == 0
MSAuthEnabled == false
}

# First test is for N/A case
tests contains {
"PolicyId": PolicyId,
"Criticality": "Shall/Not-Implemented",
"Commandlet": [],
"Commandlet": ["Get-MgBetaPolicyAuthenticationMethodPolicy"],
"ActualValue": [],
"ReportDetails": NotCheckedDetails(PolicyId),
"ReportDetails": CheckedSkippedDetails(PolicyId, Reason),
"RequirementMet": false
} if {
PolicyId := "MS.AAD.3.3v1"
count(MFAPolicies) == 0
# regal ignore:line-length
Reason := "This policy is only applicable if phishing-resistant MFA is not enforced and MS Authenticator is enabled. See %v for more info"
AAD_3_3_Not_Applicable == true
}

# If policy is not N/A then we check that the configuration matches the baseline
tests contains {
"PolicyId": "MS.AAD.3.3v1",
"Criticality": "Shall",
"Commandlet": ["Get-MgBetaPolicyAuthenticationMethodPolicy"],
"ActualValue": MSAuth,
"ReportDetails": ReportDetailsBoolean(Status),
"RequirementMet": Status
} if {
AAD_3_3_Not_Applicable == false

Status := MSAuthProperlyConfigured == true
}
#--

#
# MS.AAD.3.4v1
#--

PolicyMigrationIsComplete := Status if {
some Policy in input.authentication_method
Status := Policy.PolicyMigrationState == "migrationComplete"
# Returns the auth policy migration state object
AuthenticationPolicyMigrationState := PolicyMigrationState if {
some Setting in input.authentication_method
PolicyMigrationState := Setting.authentication_method_policy.PolicyMigrationState
}

# At this time we are unable to test for X because of NEW POLICY
# Returns true if the tenant has completed their authpolicy migration
default AuthenticationPolicyMigrationIsComplete := false
AuthenticationPolicyMigrationIsComplete if AuthenticationPolicyMigrationState == "migrationComplete"

tests contains {
"PolicyId": "MS.AAD.3.4v1",
"Criticality": "Shall",
"Commandlet": ["Get-MgBetaPolicyAuthenticationMethodPolicy"],
"ActualValue": [Policy.PolicyMigrationState],
"ActualValue": [AuthenticationPolicyMigrationState],
"ReportDetails": ReportDetailsBoolean(Status),
"RequirementMet": Status
} if {
some Policy in input.authentication_method
Status := Policy.PolicyMigrationState == "migrationComplete"
Status := AuthenticationPolicyMigrationIsComplete
}
#--

#
# MS.AAD.3.5v1
#--

GoodAuthenticationMethodConfigurations contains {
# Returns all the config states for the methods Sms, Voice, Email
LowSecurityAuthMethods contains {
"Id": Configuration.Id,
"State": Configuration.State
} if {
some Item in input.authentication_method
some Configuration in Item.AuthenticationMethodConfigurations
some Setting in input.authentication_method
some Configuration in Setting.authentication_method_feature_settings
Configuration.Id in ["Sms", "Voice", "Email"]
Configuration.State == "disabled"
}

# Returns true only when all the low security auth methods are disabled per the policy
default LowSecurityAuthMethodsDisabled := false
LowSecurityAuthMethodsDisabled := true if {
every Config in LowSecurityAuthMethods { Config.State == "disabled" }
}

# First test is for N/A case
tests contains {
"PolicyId": PolicyId,
"Criticality": "Shall",
"Criticality": "Shall/Not-Implemented",
"Commandlet": ["Get-MgBetaPolicyAuthenticationMethodPolicy"],
"ActualValue": [],
"ReportDetails": CheckedSkippedDetails("MS.AAD.3.4v1", Reason),
Expand All @@ -325,21 +376,21 @@ tests contains {
PolicyId := "MS.AAD.3.5v1"
# regal ignore:line-length
Reason := "This policy is only applicable if the tenant has their Manage Migration feature set to Migration Complete. See %v for more info"
PolicyMigrationIsComplete != true
AuthenticationPolicyMigrationIsComplete != true
}

# If policy is not N/A then we check that the configuration matches the baseline
tests contains {
"PolicyId": "MS.AAD.3.5v1",
"Criticality": "Shall",
"Commandlet": ["Get-MgBetaPolicyAuthenticationMethodPolicy"],
"ActualValue": [],
"ActualValue": [LowSecurityAuthMethods],
"ReportDetails": ReportDetailsString(Status, ErrorMessage),
"RequirementMet": Status
} if {
ErrorMessage := "Sms, Voice, and Email authentication must be disabled."
PolicyMigrationIsComplete == true
Conditions := [PolicyMigrationIsComplete == true, count(GoodAuthenticationMethodConfigurations) == 3]
Status := count(FilterArray(Conditions, false)) == 0
AuthenticationPolicyMigrationIsComplete == true
Status := LowSecurityAuthMethodsDisabled
}
#--

Expand Down Expand Up @@ -1148,4 +1199,4 @@ tests contains {
"ReportDetails": NotCheckedDetails("MS.AAD.8.3v1"),
"RequirementMet": false
}
#--
#--
Loading

0 comments on commit b6d3bbc

Please sign in to comment.