Back to Checks
Conditional Access policy enforces sign-in frequency for all users
entra_conditional_access_policy_sign_in_frequency_all_users
Service: entraSeverity: medium
OfficialBuilt-inVerified
Categories:identity-accesse3
Resource Type:NotDefined
At least one enabled Conditional Access policy should target all users and all resources and enforce a sign-in frequency of 7 days or less. Sign-in frequency defines how long an authenticated session remains valid before the user must reauthenticate. The Microsoft Entra default is a rolling 90-day window, which is too permissive.
Risk
Long-lived sessions increase the window in which a stolen token or hijacked session can be used. Without an enforced reauthentication interval, a compromised session can remain valid for up to 90 days, extending an attacker's access.
Run this check with Prowler
Run in Prowler CloudRun
prowler m365 --checks entra_conditional_access_policy_sign_in_frequency_all_usersRecommendation
Create a Conditional Access policy that enforces a sign-in frequency of 7 days or less for all users and all resources, excluding only documented break-glass accounts.
Remediation
Other
1Navigate to the Microsoft Entra admin center at https://entra.microsoft.com/
2Go to **Protection** > **Conditional Access** > **Policies** > **New policy**
3Under **Users**, include **All users** (exclude only documented break-glass accounts)
4Under **Target resources**, select **All resources**
5Under **Session**, enable **Sign-in frequency** and set it to **7 days** or less
6Set the policy to **On** and click **Create**
Check Code
from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.entra.entra_client import entra_client
from prowler.providers.m365.services.entra.entra_service import (
ClientAppType,
ConditionalAccessPolicyState,
SignInFrequencyInterval,
SignInFrequencyType,
)
# Maximum allowed reauthentication window (CIS: 7 days or less).
MAX_SIGN_IN_FREQUENCY_DAYS = 7
MAX_SIGN_IN_FREQUENCY_HOURS = MAX_SIGN_IN_FREQUENCY_DAYS * 24
class entra_conditional_access_policy_sign_in_frequency_all_users(Check):
"""Check if a Conditional Access policy enforces sign-in frequency for all users.
This check ensures that at least one enabled Conditional Access policy targets
all users and all resources and enforces a sign-in frequency of 7 days or less,
limiting how long an authenticated session remains valid before reauthentication.
- PASS: An enabled Conditional Access policy enforces sign-in frequency of 7 days
or less for all users.
- FAIL: No Conditional Access policy enforces sign-in frequency of 7 days or less
for all users.
"""
def _is_within_limit(self, sign_in_frequency) -> bool:
"""Return True if the sign-in frequency is 7 days or less."""
if not sign_in_frequency or not sign_in_frequency.is_enabled:
return False
if sign_in_frequency.interval == SignInFrequencyInterval.EVERY_TIME:
return True
if sign_in_frequency.frequency is None:
return False
if sign_in_frequency.type == SignInFrequencyType.DAYS:
return sign_in_frequency.frequency <= MAX_SIGN_IN_FREQUENCY_DAYS
if sign_in_frequency.type == SignInFrequencyType.HOURS:
return sign_in_frequency.frequency <= MAX_SIGN_IN_FREQUENCY_HOURS
return False
def _has_restricted_scope(self, conditions) -> bool:
"""Return True when policy conditions exclude part of the session scope."""
platforms = conditions.platform_conditions
platform_restricted = bool(
platforms
and (
platforms.exclude_platforms
or (
platforms.include_platforms
and "all" not in platforms.include_platforms
)
)
)
client_app_types = conditions.client_app_types or []
client_app_restricted = bool(
client_app_types and ClientAppType.ALL not in client_app_types
)
locations = conditions.locations
location_restricted = bool(
locations
and (
locations.exclude_locations
or (
locations.include_locations
and "All" not in locations.include_locations
)
)
)
device_conditions = conditions.device_conditions
device_restricted = bool(
device_conditions
and (
device_conditions.device_filter_mode
or device_conditions.device_filter_rule
)
)
authentication_flows = conditions.authentication_flows
authentication_flow_restricted = bool(
authentication_flows and authentication_flows.transfer_methods
)
user_conditions = conditions.user_conditions
user_restricted = bool(
user_conditions.excluded_users
or user_conditions.excluded_groups
or user_conditions.excluded_roles
or user_conditions.excluded_guests_or_external_users
)
application_restricted = bool(
conditions.application_conditions.included_user_actions
)
return bool(
platform_restricted
or client_app_restricted
or location_restricted
or device_restricted
or authentication_flow_restricted
or conditions.insider_risk_levels
or user_restricted
or application_restricted
)
def execute(self) -> list[CheckReportM365]:
"""Execute the check to verify sign-in frequency is enforced for all users.
Returns:
A list of reports containing the result of the check.
"""
findings = []
for policy in entra_client.conditional_access_policies.values():
report = CheckReportM365(
metadata=self.metadata(),
resource=policy,
resource_name=policy.display_name,
resource_id=policy.id,
)
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' does not enforce a sign-in frequency of 7 days or less for all users."
enforces_sign_in_frequency = (
policy.state != ConditionalAccessPolicyState.DISABLED
and "All" in policy.conditions.user_conditions.included_users
and "All"
in policy.conditions.application_conditions.included_applications
and not policy.conditions.application_conditions.excluded_applications
and not policy.conditions.sign_in_risk_levels
and not policy.conditions.user_risk_levels
and not self._has_restricted_scope(policy.conditions)
and self._is_within_limit(policy.session_controls.sign_in_frequency)
)
if enforces_sign_in_frequency:
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces sign-in frequency but is in report-only mode."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces a sign-in frequency of 7 days or less for all users."
findings.append(report)
return findings