Skip to content
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

feat(microsoft365): add new check entra_policy_ensure_default_user_cannot_create_tenants #6918

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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": ""
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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 (
Expand All @@ -12,20 +13,20 @@


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(
Expand All @@ -35,11 +36,22 @@ def test_get_client(self):
)
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,
)
)
Loading