Skip to content

Commit

Permalink
Merge pull request #27 from mitre/aadteam
Browse files Browse the repository at this point in the history
Integrate AAD updates into preversion1
  • Loading branch information
schrolla committed Jul 28, 2022
2 parents ca11d2b + a266f0e commit de6d044
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 2 deletions.
5 changes: 4 additions & 1 deletion PowerShellScripts/GetPrivilegedRoles.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ $RolePolicyAssignments = Get-MgPolicyRoleManagementPolicyAssignment -Filter "sco
ForEach ($Role in $AADRoles) {
$RolePolicies = @()
$RolePolicyRules = @()
$RoleTemplateId = $Role.RoleTemplateId

# Get role policy assignments
# Note: Each role can only be assigned a single policy at most
$PolicyAssignment = $RolePolicyAssignments | Where-Object -Property RoleDefinitionId -eq -Value $Role.RoleTemplateId
$PolicyAssignment = $RolePolicyAssignments | Where-Object -Property RoleDefinitionId -eq -Value $RoleTemplateId
$RoleAssignments = Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance -Filter "roleDefinitionId eq '$RoleTemplateId'"

# Append each policy assignment to the role object
if($PolicyAssignment.length -eq 1) {
Expand All @@ -23,6 +25,7 @@ ForEach ($Role in $AADRoles) {
}

$Role | Add-Member -Name "Rules" -Value $RolePolicies -MemberType NoteProperty
$Role | Add-Member -Name "Assignments" -Value $RoleAssignments -MemberType NoteProperty
}

return $AADRoles
236 changes: 236 additions & 0 deletions Rego/AADConfig.rego
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,242 @@ tests[{"Policy" : policy.DisplayName,
role_names := concat(", ", { role.DisplayName | role = input.privileged_roles[_] })
}

#
# 2.14
#

roles_with_permanent_assignment_allowed[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
rule_match := rule.Id == "Expiration_Admin_Assignment"
expiration_not_required := rule.AdditionalProperties.isExpirationRequired == false

allCases := [rule_match == true,
expiration_not_required == true,
]

# filter, only include rules that meet all the requirements
all(allCases)
}

roles_without_limited_expiration_period[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
rule_match := rule.Id == "Expiration_Admin_Assignment"
expiration_not_required := rule.AdditionalProperties.isExpirationRequired == false
maximum_duration_correct := rule.AdditionalProperties.maximumDuration == "P15D"

# Role policy does not require assignment expiration
case1 := all([rule_match == true, expiration_not_required == true])

# Role policy requires assignment expiration, but maximum duration is not 15 days
case2 := all([rule_match == true, expiration_not_required == false, maximum_duration_correct == true])

# filter, only include rules that meet one of the two cases
any([case1, case2])
}

roles_assigned_outside_pim[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
no_start_assignments := { is_null(x.StartDateTime) | x = role.Assignments[_] }
no_end_assignments := { is_null(x.EndDateTime) | x = role.Assignments[_] }

any([no_start_assignments, no_end_assignments])
}

tests[{"Policy": "Permanent active role assignments SHALL NOT be allowed for highly privileged roles",
"Control" : "AAD 2.14",
"Criticality" : "shall",
"Commandlet" : "Get-MgPolicyRoleManagementPolicyRule",
"SettingName" : "Allow permanent active assignment",
"ActualValue" : concat(" ", [allowed_count, roles]),
"ExpectedValue" : "Permanent active assignment not allowed",
"RequirementMet" : status}] {
status := count(roles_with_permanent_assignment_allowed) == 0
roles := concat(", ", roles_with_permanent_assignment_allowed)
allowed_count := concat(" ", [format_int(count(roles_with_permanent_assignment_allowed), 10), "role(s) allow permanent active assignment:"])
}

tests[{"Policy": "Active assignments SHALL have an expiration period",
"Control" : "AAD 2.14",
"Criticality" : "shall",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Role assignment EndTime expiration is set",
"ActualValue" : concat(" ", [permanent_count, roles]),
"ExpectedValue" : "No permanent active assignments",
"RequirementMet" : status}] {
status := count(roles_without_limited_expiration_period) == 0
roles := concat(", ", roles_without_limited_expiration_period)
permanent_count := concat(" ", [format_int(count(roles_without_limited_expiration_period), 10), "role(s) without expiration or expiration too long."])
}

tests[{"Policy": "Provisioning of users to highly privileged roles SHALL NOT occur outside of a PIM system",
"Control" : "AAD 2.14",
"Criticality" : "shall",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Role assignment 'Start Time' and 'End Time' are set",
"ActualValue" : concat(" ", [nonpim_count, roles]),
"ExpectedValue" : "No permanent active assignments",
"RequirementMet" : status}] {
status := count(roles_assigned_outside_pim) == 0
roles := concat(", ", roles_assigned_outside_pim)
nonpim_count := concat(" ", [format_int(count(roles_assigned_outside_pim), 10), "role(s) assigned to users outside of PIM:"])
}

#
# 2.15
#

roles_without_approval_required[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
rule_match := rule.Id == "Approval_EndUser_Assignment"
approval_not_required := rule.AdditionalProperties.Approval_EndUser_Assignment == false

allCases := [rule_match == true,
approval_not_required == true,
]

# filter, only include rules that meet all the requirements
all(allCases)
}

tests[{"Policy": "Activation of Highly Privileged Roles SHOULD Require Approval",
"Control" : "AAD 2.15",
"Criticality" : "should",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Require Approval to Activate",
"ActualValue" : concat(" ", [noapproval_count, roles]),
"ExpectedValue" : "Roles require approval to activate",
"RequirementMet" : status}] {
status := count(roles_without_approval_required) == 0
roles := concat(", ", roles_without_approval_required)
noapproval_count := concat(" ", [format_int(count(roles_without_approval_required), 10), "role(s) do not require approval to activate:"])
}

#
# 2.16
#
roles_without_active_assignment_alerts[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
active_rule_match := rule.Id == "Notification_Admin_Admin_Assignment"
no_active_assignment_alert := count(rule.AdditionalProperties.notificationRecipients) == 0

allCases := [active_rule_match == true,
no_active_assignment_alert == true
]

# filter, only include rules that meet all the requirements
all(allCases)
}

roles_without_eligible_assignment_alerts[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
eligible_rule_match := rule.Id == "Notification_Admin_Admin_Eligibility"
no_eligible_assignment_alert := count(rule.AdditionalProperties.notificationRecipients) == 0

allCases := [eligible_rule_match == true,
no_eligible_assignment_alert == true
]

# filter, only include rules that meet all the requirements
all(allCases)
}

admin_without_activation_alert[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]
eligible_rule_match := rule.Id == "Notification_Admin_Admin_Eligibility"
notification_type_email := rule.AdditionalProperties.notificationType == "Email"
no_eligible_assignment_alert := count(rule.AdditionalProperties.notificationRecipients) == 0

allCases := [eligible_rule_match == true,
notification_type_email == true,
no_eligible_assignment_alert == true
]

# filter, only include rules that meet all the requirements
all(allCases)
}

# Policy bullet 1
tests[{"Policy": "Eligible and Active highly privileged role assignments SHALL trigger an alert",
"Control" : "AAD 2.16",
"Criticality" : "shall",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Send notifications when members are assigned has 'Additional recipient textbox' configured with e-mail address",
"ActualValue" : concat(" ", [noalert_count, roles]),
"ExpectedValue" : "Roles assignments have monitoring e-mail address set",
"RequirementMet" : status}] {
roles_without_assignment_alerts = roles_without_active_assignment_alerts | roles_without_eligible_assignment_alerts
status := count(roles_without_assignment_alerts) == 0
roles := concat(", ", roles_without_assignment_alerts)
noalert_count := concat(" ", [format_int(count(roles_without_assignment_alerts), 10), "role(s) do not have notification e-mail configured for role assignments:"])
}

# Policy bullet 2
admins_without_activation_alert[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
rule := role.Rules[_]

rule_match := rule.Id == "Notification_Admin_EndUser_Assignment"
notification_type_email := rule.AdditionalProperties.notificationType == "Email"
no_activation_alert := count(rule.AdditionalProperties.notificationRecipients) == 0

allCases := [rule_match == true,
notification_type_email == true,
no_activation_alert == true
]

# filter, only include roles that meet all the requirements
all(allCases)
}

is_monitored(result) := "yes" if { result == true }
is_monitored(result) := "no" if { result == false }

tests[{"Policy": "User activation of the Global Administrator role SHALL trigger an alert",
"Control" : "AAD 2.16",
"Criticality" : "shall",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Send notifications when members are activated has 'Additional recipient textbox' configured with e-mail address",
"ActualValue" : concat("", ["Global Adminstrator role activations are monitored: ", is_monitored(status)]),
"ExpectedValue" : "Global Administrator role activations have monitoring e-mail address set",
"RequirementMet" : status}] {
global_admin_not_monitored := "Global Administrator" in admins_without_activation_alert
status := global_admin_not_monitored == false
}

roles_without_global_admin[role_name] {
role := input.privileged_roles[_]
role_name := role.DisplayName
role.DisplayName != "Global Administrator"
}

tests[{"Policy": "User activation of other highly privileged roles SHOULD trigger an alert",
"Control" : "AAD 2.16",
"Criticality" : "should",
"Commandlet" : "Get-MgRoleManagementDirectoryRoleAssignmentScheduleInstance",
"SettingName" : "Send notifications when members are activated has 'Additional recipient textbox' configured with e-mail address",
"ActualValue" : concat(" ", [noalert_count, roles]),
"ExpectedValue" : "Highly privileged role activations have monitoring e-mail address set",
"RequirementMet" : status}] {
non_global_admins_without_activation_alert = admins_without_activation_alert - {"Global Administrator"}
status := count(non_global_admins_without_activation_alert) == 0
roles := concat(", ", non_global_admins_without_activation_alert)
noalert_count := concat(" ", [format_int(count(non_global_admins_without_activation_alert), 10), "role(s) do not have notification e-mail configured for role activations:"])
}

#
# 2.17
#
Expand Down
1 change: 0 additions & 1 deletion Testing/AADConfig2_02_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ test_appsall_usersall_riskempty_p2 if {
filtered := [result | result = output[_]; result.Control == control_number]

nFailed := count([result.RequirementMet | result = filtered[_]; not result.RequirementMet; not contains(result.ActualValue, p2_warning_string)])
print(filtered)
nPassed := count(filtered) - nFailed
nFailed == 1
nPassed == 0
Expand Down

0 comments on commit de6d044

Please sign in to comment.