feat(microsoft365): add new check entra_policy_ensure_default_user_cannot_create_tenants (#6918)

Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
Hugo Pereira Brito
2025-02-27 10:31:02 +01:00
committed by GitHub
parent 1180522725
commit 0f414e451e
5 changed files with 259 additions and 18 deletions
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "entra_policy_ensure_default_user_cannot_create_tenants",
"CheckTitle": "Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes'",
"CheckType": [],
"ServiceName": "entra",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "#microsoft.graph.authorizationPolicy",
"Description": "Require administrators or appropriately delegated users to create new tenants.",
"Risk": "It is recommended to only allow an administrator to create new tenants. This prevent users from creating new Azure AD or Azure AD B2C tenants and ensures that only authorized users are able to do so.",
"RelatedUrl": "https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions",
"Remediation": {
"Code": {
"CLI": "Update-MgPolicyAuthorizationPolicy -DefaultUserRolePermissions @{ AllowedToCreateTenants = $false }",
"NativeIaC": "",
"Other": "1. Navigate to Microsoft Entra admin center https://entra.microsoft.com 2. Click to expand Identity > Users > User settings 3. Set 'Restrict non-admin users from creating tenants' to 'Yes' then 'Save'",
"Terraform": ""
},
"Recommendation": {
"Text": "Enforcing this setting will ensure that only authorized users are able to create new tenants.",
"Url": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#tenant-creator"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,50 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.entra.entra_client import entra_client
class entra_policy_ensure_default_user_cannot_create_tenants(Check):
"""Check if default users are restricted from creating tenants.
This check verifies whether the authorization policy prevents non-admin users
from creating new tenants in Microsoft Entra ID.
Attributes:
metadata: Metadata associated with the check (inherited from Check).
"""
def execute(self) -> List[CheckReportMicrosoft365]:
"""Execute the check for tenant creation restrictions.
This method examines the authorization policy settings to determine if
non-admin users are allowed to create new tenants. If tenant creation is
restricted, the check passes.
Returns:
List[Check_Report_Microsoft365]: A list containing the result of the check.
"""
findings = []
auth_policy = entra_client.authorization_policy
report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource=auth_policy if auth_policy else {},
resource_name=auth_policy.name if auth_policy else "Authorization Policy",
resource_id=auth_policy.id if auth_policy else "authorizationPolicy",
)
report.status = "FAIL"
report.status_extended = "Tenant creation is not disabled for non-admin users."
if getattr(
entra_client.authorization_policy, "default_user_role_permissions", None
) and not getattr(
entra_client.authorization_policy.default_user_role_permissions,
"allowed_to_create_tenants",
True,
):
report.status = "PASS"
report.status_extended = "Tenant creation is disabled for non-admin users."
findings.append(report)
return findings
@@ -0,0 +1,149 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.microsoft365.services.entra.entra_service import (
AuthorizationPolicy,
DefaultUserRolePermissions,
)
from tests.providers.microsoft365.microsoft365_fixtures import (
set_mocked_microsoft365_provider,
)
class Test_entra_policy_ensure_default_user_cannot_create_tenants:
def test_entra_empty_tenant(self):
entra_client = mock.MagicMock
entra_client.authorization_policy = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import (
entra_policy_ensure_default_user_cannot_create_tenants,
)
check = entra_policy_ensure_default_user_cannot_create_tenants()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Tenant creation is not disabled for non-admin users."
)
assert result[0].resource == {}
assert result[0].resource_name == "Authorization Policy"
assert result[0].resource_id == "authorizationPolicy"
assert result[0].location == "global"
def test_entra_default_user_role_permissions_allowed_to_create_tenants(self):
id = str(uuid4())
entra_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import (
entra_policy_ensure_default_user_cannot_create_tenants,
)
entra_client.authorization_policy = AuthorizationPolicy(
id=id,
name="Test",
description="Test",
default_user_role_permissions=DefaultUserRolePermissions(
allowed_to_create_tenants=True
),
)
check = entra_policy_ensure_default_user_cannot_create_tenants()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Tenant creation is not disabled for non-admin users."
)
assert result[0].resource == {
"id": id,
"name": "Test",
"description": "Test",
"default_user_role_permissions": {
"allowed_to_create_apps": None,
"allowed_to_create_security_groups": None,
"allowed_to_create_tenants": True,
"allowed_to_read_bitlocker_keys_for_owned_device": None,
"allowed_to_read_other_users": None,
"odata_type": None,
"permission_grant_policies_assigned": None,
},
}
assert result[0].resource_name == "Test"
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_default_user_role_permissions_not_allowed_to_create_tenants(self):
id = str(uuid4())
entra_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import (
entra_policy_ensure_default_user_cannot_create_tenants,
)
entra_client.authorization_policy = AuthorizationPolicy(
id=id,
name="Test",
description="Test",
default_user_role_permissions=DefaultUserRolePermissions(
allowed_to_create_tenants=False
),
)
check = entra_policy_ensure_default_user_cannot_create_tenants()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "Tenant creation is disabled for non-admin users."
)
assert result[0].resource == {
"id": id,
"name": "Test",
"description": "Test",
"default_user_role_permissions": {
"allowed_to_create_apps": None,
"allowed_to_create_security_groups": None,
"allowed_to_create_tenants": False,
"allowed_to_read_bitlocker_keys_for_owned_device": None,
"allowed_to_read_other_users": None,
"odata_type": None,
"permission_grant_policies_assigned": None,
},
}
assert result[0].resource_name == "Test"
assert result[0].resource_id == id
assert result[0].location == "global"
@@ -3,6 +3,7 @@ from unittest.mock import patch
from prowler.providers.microsoft365.models import Microsoft365IdentityInfo
from prowler.providers.microsoft365.services.entra.entra_service import (
AuthorizationPolicy,
DefaultUserRolePermissions,
Entra,
)
from tests.providers.microsoft365.microsoft365_fixtures import (
@@ -12,20 +13,20 @@ from tests.providers.microsoft365.microsoft365_fixtures import (
async def mock_entra_get_authorization_policy(_):
return {
"id-1": AuthorizationPolicy(
id="id-1",
name="Name 1",
description="Description 1",
default_user_role_permissions=None,
)
}
return AuthorizationPolicy(
id="id-1",
name="Name 1",
description="Description 1",
default_user_role_permissions=DefaultUserRolePermissions(
allowed_to_create_apps=True,
allowed_to_create_security_groups=True,
allowed_to_create_tenants=True,
allowed_to_read_bitlocker_keys_for_owned_device=True,
allowed_to_read_other_users=True,
),
)
@patch(
"prowler.providers.microsoft365.services.entra.entra_service.Entra._get_authorization_policy",
new=mock_entra_get_authorization_policy,
)
class Test_Entra_Service:
def test_get_client(self):
admincenter_client = Entra(
@@ -35,11 +36,22 @@ class Test_Entra_Service:
)
assert admincenter_client.client.__class__.__name__ == "GraphServiceClient"
@patch(
"prowler.providers.microsoft365.services.entra.entra_service.Entra._get_authorization_policy",
new=mock_entra_get_authorization_policy,
)
def test_get_authorization_policy(self):
entra_client = Entra(set_mocked_microsoft365_provider())
assert entra_client.authorization_policy["id-1"].id == "id-1"
assert entra_client.authorization_policy["id-1"].name == "Name 1"
assert entra_client.authorization_policy["id-1"].description == "Description 1"
assert not entra_client.authorization_policy[
"id-1"
].default_user_role_permissions
assert entra_client.authorization_policy.id == "id-1"
assert entra_client.authorization_policy.name == "Name 1"
assert entra_client.authorization_policy.description == "Description 1"
assert (
entra_client.authorization_policy.default_user_role_permissions
== DefaultUserRolePermissions(
allowed_to_create_apps=True,
allowed_to_create_security_groups=True,
allowed_to_create_tenants=True,
allowed_to_read_bitlocker_keys_for_owned_device=True,
allowed_to_read_other_users=True,
)
)