diff --git a/prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.py b/prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.py index c4db014bc3..9804ce283c 100644 --- a/prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.py +++ b/prowler/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges.py @@ -41,9 +41,15 @@ class app_function_identity_without_admin_privileges(Check): USER_ACCESS_ADMINISTRATOR_ROLE_ID, ] ): - for role in iam_client.roles[subscription_name]: - if role.id.split("/")[-1] == role_assignment.role_id: - admin_roles_assigned.append(role.name) + admin_roles_assigned.append( + getattr( + iam_client.roles[subscription_name].get( + f"/subscriptions/{iam_client.subscriptions[subscription_name]}/providers/Microsoft.Authorization/roleDefinitions/{role_assignment.role_id}" + ), + "name", + "", + ) + ) if admin_roles_assigned: report.status = "FAIL" diff --git a/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py b/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py index 9a6283e1c6..ad3b6819ae 100644 --- a/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py +++ b/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py @@ -17,7 +17,7 @@ class entra_user_with_vm_access_has_mfa(Check): findings = [] for users in entra_client.users.values(): - for user_domain_name, user in users.items(): + for user in users.values(): for ( subscription_name, role_assigns, diff --git a/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py b/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py index 2abbf40510..c6c16326a3 100644 --- a/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py +++ b/prowler/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks.py @@ -10,7 +10,7 @@ class iam_custom_role_has_permissions_to_administer_resource_locks(Check): for subscription, roles in iam_client.custom_roles.items(): exits_role_with_permission_over_locks = False - for custom_role in roles: + for custom_role in roles.values(): if exits_role_with_permission_over_locks: break report = Check_Report_Azure( diff --git a/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/__init__.py b/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json b/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json new file mode 100644 index 0000000000..ff5825e971 --- /dev/null +++ b/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "iam_role_user_access_admin_restricted", + "CheckTitle": "Ensure 'User Access Administrator' role is restricted", + "CheckType": [], + "ServiceName": "iam", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "AzureIAMRoleassignment", + "Description": "Checks for active assignments of the highly privileged 'User Access Administrator' role in Azure subscriptions.", + "Risk": "Persistent assignment of this role can lead to privilege escalation and unauthorized access, increasing the risk of security breaches.", + "RelatedUrl": "https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/privileged#user-access-administrator", + "Remediation": { + "Code": { + "CLI": "az role assignment delete --role 'User Access Administrator' --scope '/subscriptions/'", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Remove 'User Access Administrator' role assignments immediately after use to minimize security risks.", + "Url": "https://learn.microsoft.com/en-us/azure/role-based-access-control/elevate-access-global-admin?tabs=azure-portal%2Centra-audit-logs" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.py b/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.py new file mode 100644 index 0000000000..4880880cb0 --- /dev/null +++ b/prowler/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted.py @@ -0,0 +1,29 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.iam.iam_client import iam_client + + +class iam_role_user_access_admin_restricted(Check): + def execute(self): + findings = [] + + for subscription_name, assignments in iam_client.role_assignments.items(): + for assignment in assignments.values(): + role_assignment_name = getattr( + iam_client.roles[subscription_name].get( + f"/subscriptions/{iam_client.subscriptions[subscription_name]}/providers/Microsoft.Authorization/roleDefinitions/{assignment.role_id}" + ), + "name", + "", + ) + report = Check_Report_Azure( + metadata=self.metadata(), resource=assignment + ) + report.subscription = subscription_name + if role_assignment_name == "User Access Administrator": + report.status = "FAIL" + report.status_extended = f"Role assignment {assignment.name} in subscription {subscription_name} grants User Access Administrator role to {getattr(assignment, 'agent_type', '')} {getattr(assignment, 'agent_id', '')}." + else: + report.status = "PASS" + report.status_extended = f"Role assignment {assignment.name} in subscription {subscription_name} does not grant User Access Administrator role." + findings.append(report) + return findings diff --git a/prowler/providers/azure/services/iam/iam_service.py b/prowler/providers/azure/services/iam/iam_service.py index 657921eb4f..55f1eb7e71 100644 --- a/prowler/providers/azure/services/iam/iam_service.py +++ b/prowler/providers/azure/services/iam/iam_service.py @@ -20,45 +20,40 @@ class IAM(AzureService): custom_roles = {} for subscription, client in self.clients.items(): try: - builtin_roles.update({subscription: []}) - custom_roles.update({subscription: []}) + builtin_roles.update({subscription: {}}) + custom_roles.update({subscription: {}}) all_roles = client.role_definitions.list( scope=f"/subscriptions/{self.subscriptions[subscription]}", ) for role in all_roles: if role.role_type == "CustomRole": - custom_roles[subscription].append( - Role( - id=role.id, - name=role.role_name, - type=role.role_type, - assignable_scopes=role.assignable_scopes, - permissions=[ - Permission( - condition=getattr(permission, "condition", ""), - condition_version=getattr( - permission, "condition_version", "" - ), - actions=getattr(permission, "actions", []), - ) - for permission in getattr(role, "permissions", []) - ], - ) + custom_roles[subscription][role.id] = Role( + id=role.id, + name=role.role_name, + type=role.role_type, + assignable_scopes=role.assignable_scopes, + permissions=[ + Permission( + condition=getattr(permission, "condition", ""), + condition_version=getattr( + permission, "condition_version", "" + ), + actions=getattr(permission, "actions", []), + ) + for permission in getattr(role, "permissions", []) + ], ) else: - builtin_roles[subscription].append( - Role( - id=role.id, - name=role.role_name, - type=role.role_type, - assignable_scopes=role.assignable_scopes, - permissions=role.permissions, - ) + builtin_roles[subscription][role.id] = Role( + id=role.id, + name=role.role_name, + type=role.role_type, + assignable_scopes=role.assignable_scopes, + permissions=role.permissions, ) except Exception as error: - logger.error(f"Subscription name: {subscription}") logger.error( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) return builtin_roles, custom_roles @@ -75,6 +70,9 @@ class IAM(AzureService): role_assignments[subscription].update( { role_assignment.id: RoleAssignment( + id=role_assignment.id, + name=role_assignment.name, + scope=role_assignment.scope, agent_id=role_assignment.principal_id, agent_type=role_assignment.principal_type, role_id=role_assignment.role_definition_id.split("/")[ @@ -84,9 +82,8 @@ class IAM(AzureService): } ) except Exception as error: - logger.error(f"Subscription name: {subscription}") logger.error( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + f"Subscription name: {subscription} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) return role_assignments @@ -109,6 +106,21 @@ class Role: @dataclass class RoleAssignment: + """ + Represents an Azure Role Assignment. + + Attributes: + id: The unique identifier of the role assignment. + name: The name of the role assignment. + scope: The scope at which the role assignment applies. + agent_id: The principal (user, group, service principal, etc.) ID assigned the role. + agent_type: The type of the principal. Known values: "User", "Group", "ServicePrincipal", "ForeignGroup", and "Device". + role_id: The ID of the role definition assigned. + """ + + id: str + name: str + scope: str agent_id: str agent_type: str role_id: str diff --git a/prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.py b/prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.py index df73516252..8580a3aab7 100644 --- a/prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.py +++ b/prowler/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created.py @@ -8,7 +8,7 @@ class iam_subscription_roles_owner_custom_not_created(Check): def execute(self) -> Check_Report_Azure: findings = [] for subscription, roles in iam_client.custom_roles.items(): - for custom_role in roles: + for custom_role in roles.values(): report = Check_Report_Azure( metadata=self.metadata(), resource=custom_role ) diff --git a/tests/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges_test.py b/tests/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges_test.py index 68dc5293a7..c4761099b9 100644 --- a/tests/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges_test.py +++ b/tests/providers/azure/services/app/app_function_identity_without_admin_privileges/app_function_identity_without_admin_privileges_test.py @@ -144,24 +144,29 @@ class Test_app_function_identity_without_admin_privileges: iam_client.role_assignments = { AZURE_SUBSCRIPTION_ID: { - "1": RoleAssignment( - role_id="1", + "role-assignment-id-1": RoleAssignment( + id="role-assignment-id-1", + name="role-assignment-name-1", + scope="/subscriptions/{}/resourceGroups/rg/providers/Microsoft.Web/sites/function1".format( + AZURE_SUBSCRIPTION_ID + ), agent_id="123", agent_type="User", + role_id="role-id-1", ) } } iam_client.roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id="1", + AZURE_SUBSCRIPTION_ID: { + "role-id-1": Role( + id="role-id-1", name="role1", - type="User", + type="BuiltInRole", assignable_scopes=[], permissions=[], ) - ] + } } check = app_function_identity_without_admin_privileges() @@ -205,9 +210,9 @@ class Test_app_function_identity_without_admin_privileges: ) function_id = str(uuid4()) - + function_scope = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/rg/providers/Microsoft.Web/sites/function1" app_client.functions = { - AZURE_SUBSCRIPTION_ID: { + "subscription-name-1": { function_id: FunctionApp( id=function_id, name="function1", @@ -223,26 +228,33 @@ class Test_app_function_identity_without_admin_privileges: } } + iam_client.subscriptions = { + "subscription-name-1": AZURE_SUBSCRIPTION_ID, + } + iam_client.role_assignments = { - AZURE_SUBSCRIPTION_ID: { - "1": RoleAssignment( - role_id=USER_ACCESS_ADMINISTRATOR_ROLE_ID, + "subscription-name-1": { + "role-assignment-id-2": RoleAssignment( + id="role-assignment-id-2", + name="role-assignment-name-2", + scope=function_scope, agent_id="123", agent_type="User", + role_id=USER_ACCESS_ADMINISTRATOR_ROLE_ID, ) } } iam_client.roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=USER_ACCESS_ADMINISTRATOR_ROLE_ID, + "subscription-name-1": { + f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/providers/Microsoft.Authorization/roleDefinitions/{USER_ACCESS_ADMINISTRATOR_ROLE_ID}": Role( + id=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/providers/Microsoft.Authorization/roleDefinitions/{USER_ACCESS_ADMINISTRATOR_ROLE_ID}", name="User Access Administrator", - type="User", + type="BuiltInRole", assignable_scopes=[], permissions=[], - ) - ] + ), + } } check = app_function_identity_without_admin_privileges() @@ -255,5 +267,5 @@ class Test_app_function_identity_without_admin_privileges: ) assert result[0].resource_id == function_id assert result[0].resource_name == "function1" - assert result[0].subscription == AZURE_SUBSCRIPTION_ID + assert result[0].subscription == "subscription-name-1" assert result[0].location == "West Europe" diff --git a/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py b/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py index 53ab5d8b3e..a02995c45b 100644 --- a/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py +++ b/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py @@ -75,6 +75,9 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: iam_client.role_assignments = { AZURE_SUBSCRIPTION_ID: { role_assigment_id: RoleAssignment( + id=role_assigment_id, + name="test", + scope=AZURE_SUBSCRIPTION_ID, role_id=VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN_ROLE_ID, agent_type="User", agent_id=user_id, @@ -149,6 +152,9 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: iam_client.role_assignments = { AZURE_SUBSCRIPTION_ID: { role_assigment_id: RoleAssignment( + id=role_assigment_id, + name="test", + scope=AZURE_SUBSCRIPTION_ID, role_id=VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN_ROLE_ID, agent_type="User", agent_id=user_id, @@ -216,6 +222,9 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: iam_client.role_assignments = { AZURE_SUBSCRIPTION_ID: { role_assigment_id: RoleAssignment( + id=role_assigment_id, + name="test", + scope=AZURE_SUBSCRIPTION_ID, role_id=VIRTUAL_MACHINE_ADMINISTRATOR_LOGIN_ROLE_ID, agent_type="User", agent_id=user_id, @@ -269,6 +278,9 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: iam_client.role_assignments = { AZURE_SUBSCRIPTION_ID: { role_assigment_id: RoleAssignment( + id=role_assigment_id, + name="test", + scope=AZURE_SUBSCRIPTION_ID, role_id=str(uuid4()), agent_type="User", agent_id=user_id, diff --git a/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py b/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py index 760015e6a1..eaa59eff14 100644 --- a/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py +++ b/tests/providers/azure/services/iam/iam_custom_role_has_permissions_to_administer_resource_locks/iam_custom_role_has_permissions_to_administer_resource_locks_test.py @@ -1,5 +1,4 @@ from unittest import mock -from uuid import uuid4 from azure.mgmt.authorization.v2022_04_01.models import Permission @@ -39,9 +38,9 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: defender_client = mock.MagicMock role_name = "test-role" defender_client.custom_roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=str(uuid4()), + AZURE_SUBSCRIPTION_ID: { + "test-role-id": Role( + id="test-role-id", name=role_name, type="CustomRole", assignable_scopes=["/.*", "/test"], @@ -54,7 +53,7 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: ) ], ) - ] + } } with ( @@ -82,7 +81,9 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert ( result[0].resource_id - == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id + == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][ + "test-role-id" + ].id ) assert result[0].resource_name == role_name @@ -92,15 +93,15 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: defender_client = mock.MagicMock role_name = "test-role" defender_client.custom_roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=str(uuid4()), + AZURE_SUBSCRIPTION_ID: { + "test-role-id": Role( + id="test-role-id", name=role_name, type="CustomRole", assignable_scopes=["/*"], permissions=[Permission(actions=["*"])], ) - ] + } } with ( @@ -128,7 +129,9 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert ( result[0].resource_id - == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id + == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][ + "test-role-id" + ].id ) assert result[0].resource_name == role_name @@ -139,9 +142,9 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: role_name = "test-role" role_name2 = "test-role2" defender_client.custom_roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=str(uuid4()), + AZURE_SUBSCRIPTION_ID: { + "test-role-id": Role( + id="test-role-id", name=role_name, type="CustomRole", assignable_scopes=["/.*", "/test"], @@ -154,8 +157,8 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: ) ], ), - Role( - id=str(uuid4()), + "test-role-id2": Role( + id="test-role-id2", name=role_name2, type="CustomRole", assignable_scopes=["/.*", "/test"], @@ -168,7 +171,7 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: ) ], ), - ] + } } with ( @@ -196,12 +199,14 @@ class Test_iam_custom_role_has_permissions_to_administer_resource_locks: assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert ( result[0].resource_id - == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id + == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][ + "test-role-id" + ].id ) def test_iam_custom_roles_empty_list_but_with_key(self): defender_client = mock.MagicMock - defender_client.custom_roles = {AZURE_SUBSCRIPTION_ID: []} + defender_client.custom_roles = {AZURE_SUBSCRIPTION_ID: {}} with ( mock.patch( diff --git a/tests/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted_test.py b/tests/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted_test.py new file mode 100644 index 0000000000..dbf842d589 --- /dev/null +++ b/tests/providers/azure/services/iam/iam_role_user_access_admin_restricted/iam_role_user_access_admin_restricted_test.py @@ -0,0 +1,153 @@ +from unittest import mock +from uuid import uuid4 + +from prowler.providers.azure.services.iam.iam_service import Role, RoleAssignment +from tests.providers.azure.azure_fixtures import ( + AZURE_SUBSCRIPTION_ID, + set_mocked_azure_provider, +) + + +class Test_iam_role_user_access_admin_restricted: + def test_iam_no_role_assignments(self): + iam_client = mock.MagicMock + iam_client.role_assignments = {} + iam_client.roles = {} + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted.iam_client", + new=iam_client, + ), + ): + from prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted import ( + iam_role_user_access_admin_restricted, + ) + + check = iam_role_user_access_admin_restricted() + result = check.execute() + assert len(result) == 0 + + def test_iam_user_access_administrator_role_assigned(self): + iam_client = mock.MagicMock + role_id = str(uuid4()) + role_assignment_id = str(uuid4()) + agent_id = str(uuid4()) + role_name = "User Access Administrator" + + iam_client.subscriptions = { + "subscription-name-1": AZURE_SUBSCRIPTION_ID, + } + + iam_client.role_assignments = { + "subscription-name-1": { + role_assignment_id: RoleAssignment( + id=role_assignment_id, + name="test-assignment", + scope=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}", + agent_id=agent_id, + agent_type="User", + role_id=role_id, + ) + } + } + iam_client.roles = { + "subscription-name-1": { + f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/providers/Microsoft.Authorization/roleDefinitions/{role_id}": Role( + id=role_id, + name=role_name, + type="BuiltInRole", + assignable_scopes=[f"/subscriptions/{AZURE_SUBSCRIPTION_ID}"], + permissions=[], + ) + } + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted.iam_client", + new=iam_client, + ), + ): + from prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted import ( + iam_role_user_access_admin_restricted, + ) + + check = iam_role_user_access_admin_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Role assignment test-assignment in subscription subscription-name-1 grants User Access Administrator role to User {agent_id}." + ) + assert result[0].subscription == "subscription-name-1" + assert result[0].resource_id == role_assignment_id + + def test_iam_non_user_access_administrator_role_assigned(self): + iam_client = mock.MagicMock + role_id = str(uuid4()) + role_assignment_id = str(uuid4()) + agent_id = str(uuid4()) + role_name = "Reader" + + iam_client.subscriptions = { + "subscription-name-1": AZURE_SUBSCRIPTION_ID, + } + + iam_client.role_assignments = { + "subscription-name-1": { + role_assignment_id: RoleAssignment( + id=role_assignment_id, + name="test-assignment", + scope=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}", + agent_id=agent_id, + agent_type="User", + role_id=role_id, + ) + } + } + iam_client.roles = { + "subscription-name-1": { + f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/providers/Microsoft.Authorization/roleDefinitions/{role_id}": Role( + id=role_id, + name=role_name, + type="BuiltInRole", + assignable_scopes=[f"/subscriptions/{AZURE_SUBSCRIPTION_ID}"], + permissions=[], + ) + } + } + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted.iam_client", + new=iam_client, + ), + ): + from prowler.providers.azure.services.iam.iam_role_user_access_admin_restricted.iam_role_user_access_admin_restricted import ( + iam_role_user_access_admin_restricted, + ) + + check = iam_role_user_access_admin_restricted() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Role assignment test-assignment in subscription subscription-name-1 does not grant User Access Administrator role." + ) + assert result[0].subscription == "subscription-name-1" + assert result[0].resource_id == role_assignment_id diff --git a/tests/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created_test.py b/tests/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created_test.py index 52f824829d..7f15b69466 100644 --- a/tests/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created_test.py +++ b/tests/providers/azure/services/iam/iam_subscription_roles_owner_custom_not_created/iam_subscription_roles_owner_custom_not_created_test.py @@ -1,5 +1,4 @@ from unittest import mock -from uuid import uuid4 from azure.mgmt.authorization.v2022_04_01.models import Permission @@ -37,15 +36,15 @@ class Test_iam_subscription_roles_owner_custom_not_created: defender_client = mock.MagicMock role_name = "test-role" defender_client.custom_roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=str(uuid4()), + AZURE_SUBSCRIPTION_ID: { + "test-role-id": Role( + id="test-role-id", name=role_name, type="CustomRole", assignable_scopes=["/*"], permissions=[Permission(actions="*")], ) - ] + } } with ( @@ -73,7 +72,9 @@ class Test_iam_subscription_roles_owner_custom_not_created: assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert ( result[0].resource_id - == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id + == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][ + "test-role-id" + ].id ) assert result[0].resource_name == role_name @@ -81,15 +82,15 @@ class Test_iam_subscription_roles_owner_custom_not_created: defender_client = mock.MagicMock role_name = "test-role" defender_client.custom_roles = { - AZURE_SUBSCRIPTION_ID: [ - Role( - id=str(uuid4()), + AZURE_SUBSCRIPTION_ID: { + "test-role-id": Role( + id="test-role-id", name=role_name, type="type-role", assignable_scopes=[""], permissions=[Permission()], ) - ] + } } with ( @@ -117,6 +118,8 @@ class Test_iam_subscription_roles_owner_custom_not_created: assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert ( result[0].resource_id - == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][0].id + == defender_client.custom_roles[AZURE_SUBSCRIPTION_ID][ + "test-role-id" + ].id ) assert result[0].resource_name == role_name