Open table of contents
Cloudflare Zero Trust and Microsoft Entra ID can use MFA, device compliance, groups and connection paths as access conditions. Requiring the same Intune compliance result in both products does not necessarily add an independent defense. Different refresh and session behavior can instead make a denial harder to explain.
This article assigns identity assurance to Entra, resource admission and access-path enforcement to Cloudflare, and domain authorization to the application. Entra Authentication Context connects the first two boundaries. This is an architectural choice, not a limitation of either product: Entra controls resource access, and Cloudflare also supports MFA and risk signals.
We develop the boundaries introduced in Zero Trust Beyond Remote Access into an example for a self-hosted HTTP application. These are design and review materials. Tenant configuration, authentication, revocation exercises and OpenTofu execution have not been performed.
1. Separate three decisions
Consider an infrastructure administration portal. Successful Entra authentication does not by itself entitle a person to enter the portal. Being admitted to the portal does not permit deleting every cluster.
| Boundary | Question assigned in this design | Primary operator |
|---|---|---|
| Entra | Is this the user, with the required authentication strength and device compliance? | Identity team |
| Cloudflare Access | May this user reach this application with the required assurance and path? | Platform / Security team |
| Application | May this principal perform this operation on this tenant and resource? | Application team |
Scroll horizontally to view the complete diagram.
Read the diagram as text
Entra evaluates authentication strength and device compliance. Cloudflare requires the context, group and Gateway for application admission. The application authorizes tenant and resource operations.
Entra owns group membership; Cloudflare consumes it for application admission. Keep domain RBAC in the application instead of copying every business permission into an access proxy. The application still authorizes individual operations.
2. Assign signal ownership and evaluation timing together
For every overlapping feature, record the decision source, its consumer and what triggers reevaluation. Our baseline places Microsoft-native authentication strength, sign-in risk and Intune compliance in Entra. Cloudflare selects the required assurance and adds Cloudflare-specific path conditions. [1][2]
| Signal or decision | Primary responsibility | Evaluation or update boundary |
|---|---|---|
| Authentication strength, sign-in risk, device compliance | Entra | Authentication, token acquisition and supported reevaluation involving Entra |
| Group membership | Entra owns; Access consumes | IdP information during Access authentication; change propagation requires a separate design |
| Required authentication context | Cloudflare requests; Entra evaluates | Context-aware authentication flow and Access sessions |
| Gateway, WARP and supported posture | Cloudflare | Evaluation on new HTTP requests, subject to source refresh timing |
| Application token and Access session | Cloudflare | Policy, application, global and One Client settings |
| Business-resource operations | Application | Each protected operation |
This table does not reduce every Entra feature to login-time evaluation. It avoids assuming that capabilities such as Continuous Access Evaluation automatically extend to an arbitrary external application or Cloudflare session.
Requiring Intune compliance in both systems can be intentional. Document the shared source, refresh delays and behavior when one system cannot retrieve it. Combining Intune compliance with a separate EDR health check or organizational Gateway requirement answers different questions and can provide additional controls.
3. Treat Authentication Context as an assurance contract
Authentication Context gives an application a way to request particular Conditional Access requirements. Create a context in Entra and associate CA policies targeting that context. A Cloudflare Access policy then requires the Azure AD - Auth context selector. Cloudflare documents this integration explicitly. [3][4]
For example, define Privileged Infrastructure v1 as the following contract. AC3 is an organizational shorthand, not an API identifier.
# Design contract; not a deployed Entra resource.
name: Privileged Infrastructure v1
alias: AC3
owner: identity-team
required_controls:
operator: AND
authentication_strength: phishing-resistant MFA
device: Intune compliant
consumers:
- admin.example.com
context_identifiers: RECORD_FROM_APPROVED_TENANT
policy_state: MUST_BE_ENFORCED_FOR_TARGET_USERS
execution_status: NOT_RUN
A context’s name does not establish assurance. Review user targeting, exclusions, enabled policies, AND/OR grant semantics and other applicable CA policies. A report-only result does not establish enforced assurance. [5]
Entra context IDs use identifiers such as c1 through c99. Check Publish to apps so downstream applications can select the context. Do not infer mappings between the organizational name AC3, the Entra identifier and synchronized Cloudflare fields from their names. [4]
Scroll horizontally to view the complete diagram.
Read the diagram as text
Publish the Entra context, associate CA policies and synchronize discovery. Separately require it in an Access policy and attach the policy to an application. Discovery alone does not enforce assurance; review report-only state and exclusions.
Review every consuming application before changing the contract. Weakening a shared context to accommodate one application also changes the requirement for other administration tools. Where necessary, create a separate context and migrate explicitly selected consumers. Authentication-method changes also require reviewing the methods and configuration allowed by the selected strength; “any passkey” is not a sufficient specification. [2]
4. Separate synchronization, enforcement and rollout
Establish the base Entra IdP integration first, then the context and CA policy, and finally the Cloudflare application’s requirement. The integration uses an Entra app registration. Review group-support permissions separately from Policy Sync. Cloudflare’s instructions require Microsoft Graph Policy.Read.ConditionalAccess as an application permission, followed by admin consent. Delegated permission does not work for this feature. [3][6]
Enabling Policy Sync is not equivalent to requiring a context for an application. Make the context available, add it to an Access policy’s Require rules and attach that policy to the application. This integration does not require manually translating each CA rule into a Cloudflare condition.
The Entra-side design could be written as follows. This is a review specification, not a JSON payload for Microsoft Graph.
Context: Privileged Infrastructure v1
Publish to apps: Yes
Users: Platform Engineers (pilot scope first)
Target resources: Authentication context
Grant: Require ALL selected controls
- Require phishing-resistant MFA authentication strength
- Require device to be marked as compliant
Session: Evaluate an appropriate sign-in frequency
Risk: Review applicable organization-wide risk policies
Exclusions: Explicitly reviewed emergency identities
Rollout: Report-only -> enforced pilot -> reviewed expansion
For multiple grant controls, explicitly select the intention represented by Require all the selected controls. If an organization-wide risk policy and a context-specific policy have different scopes, check that the intended users are covered by both. Conditional Access requires P1 licensing; risk-based CA includes P2 capabilities. Verify the actual licenses and covered users, as well as Intune and Cloudflare entitlements. [1]
Use report-only evaluation to inspect impact, enforce a limited pilot, exercise negative cases and then expand. Report-only device compliance evaluation can still cause certificate-selection prompts on some platforms; do not describe it as having no user impact. [5]
5. Narrow Cloudflare admission and path requirements
An Allow policy uses Include to establish eligible users, Require to add conditions and Exclude to remove matches. Multiple Include rules are OR; Require rules are AND. Placing the engineer group and Gateway in Include can accidentally mean “member of the group or using Gateway.” [7]
Here we Include Platform Engineers and Require both the context and Gateway. Gateway requires the organizational Zero Trust / One Client path. WARP alone includes the consumer client, so the two checks are not interchangeable. Gateway membership also does not establish corporate device ownership or Intune compliance. [8]
Separate Allow policies do not automatically accumulate their requirements. Bypass and Service Auth policies are evaluated first, followed by ordered Allow / Block policies. A more permissive Allow or Bypass elsewhere can defeat the intended application-wide assurance. Review the hostname and path scope together with the complete policy set. [7]
6. Include application attachment in OpenTofu examples
The following example was compared with the published schema for Cloudflare Provider 5.23.0. It has not been executed. Gateway is represented by a device posture rule with type = "gateway", referenced through device_posture.integration_uid. Including that rule makes the relationship between the dashboard selector and API representation explicit. [9]
resource "cloudflare_zero_trust_device_posture_rule" "gateway" {
account_id = var.cloudflare_account_id
name = "Organization Gateway"
type = "gateway"
}
resource "cloudflare_zero_trust_access_policy" "infra_admin" {
account_id = var.cloudflare_account_id
name = "ACCESS-Admin-Require-AC3-Gateway"
decision = "allow"
session_duration = "1h"
include = [{
azure_ad = {
id = var.platform_engineers_group_id
identity_provider_id = var.entra_identity_provider_id
}
}]
# Entra owns authentication strength and Intune compliance.
# Cloudflare requires the context and organizational path.
require = [
{
auth_context = {
id = var.synced_auth_context_id
ac_id = var.synced_auth_context_ac_id
identity_provider_id = var.entra_identity_provider_id
}
},
{
device_posture = {
integration_uid = cloudflare_zero_trust_device_posture_rule.gateway.id
}
}
]
}
auth_context.id, ac_id and identity_provider_id are all required. Provider documentation calls the first two the context ID and ACID, but does not define a conversion from a display name. Inspect the synchronized context and policy API representation in the intended environment, record the corresponding values and supply them separately. Do not assume they are identical or enter the shorthand AC3 as either value.
Creating a reusable policy does not attach it to an application. Include that association:
resource "cloudflare_zero_trust_access_application" "infra_admin" {
account_id = var.cloudflare_account_id
name = "Infrastructure administration"
type = "self_hosted"
domain = "admin.example.com"
allowed_idps = [var.entra_identity_provider_id]
auto_redirect_to_identity = true
allow_authenticate_via_warp = false
session_duration = "1h"
policies = [{
id = cloudflare_zero_trust_access_policy.infra_admin.id
precedence = 1
}]
}
allow_authenticate_via_warp = false disables using the One Client authentication session as the alternative authentication path for this example. Requiring Gateway and authenticating with a One Client session are different choices. Access global-session reuse still matters; this setting does not send every request to Entra.
Download the configuration and review bundle. It includes a pinned versions.tf, variables, the context contract and revocation / acceptance records. It does not create the IdP registration, Entra CA policies, SCIM provisioning, DNS, Tunnel or origin. Existing resources, state ownership and possible duplication require review before adoption.
OpenTofu’s dependency lock file is named .terraform.lock.hcl. No lock file is supplied because init was not run. Resolve the provider in the chosen OpenTofu environment, review the resulting lock file and manage it with the configuration. Supply secrets through the designated secret system; do not embed them in examples or shared state-review material.
7. A short session does not guarantee fresh authentication
Access has a global session token and an application token. A policy session duration controls the application token’s expiry; when unspecified it uses the application setting. An expired application token can be reissued while the global token remains valid and the user’s identity still meets policy. “One-hour Access session” therefore does not establish “Entra CA reevaluates every hour.” [10]
Entra sign-in frequency set to Every time also does not mean MFA on every HTTP request. It requires reauthentication when the session is evaluated, which depends on the application returning to Entra. Microsoft also documents a five-minute clock-skew tolerance. [11]
Scroll horizontally to view the complete diagram.
Read the diagram as text
In the ordinary Access flow, a valid global session can support application-token reissue. When client authentication is enabled, its session takes precedence. Entra Every time applies when the Entra session is evaluated.
When Authenticate with Cloudflare One Client is enabled, the client session takes precedence over application, policy and global durations. A valid client session can avoid an IdP prompt even after the global session expires. For administrative applications, inspect the actual browser and client paths that return the user to Entra. [10]
Session settings represent multiple clocks, including the origin application’s own cookie. Review existing sessions, token reissue after expiry, a new browser session and One Client authentication separately. A list of configured durations does not establish the effective behavior.
8. Measure continuous evaluation and revocation propagation
For self-hosted HTTP applications, supported non-identity conditions are evaluated with each new HTTP request. Request evaluation, posture-source refresh and connection termination are separate events. A new evaluation can consume an older posture result. Review source polling and result expiry, and do not extrapolate HTTP behavior into immediate termination of an open WebSocket or SSH connection. [7][9]
SCIM also does not mean automatic, instantaneous revocation. Access evaluates identity and groups from the IdP information used during authentication. Configured user deprovisioning and group-change reauthentication can revoke active sessions and force updated identity information to be read at the next authentication. Gateway consumes synchronized User Registry identity, so its behavior differs from Access. [6][12]
The Entra integration uses a separate enterprise application for SCIM. Align its assignments with the groups supplied through the authentication application. Nested-group provisioning has limitations; check direct membership and actual provisioning logs. [6]
| Change | Propagation to inspect | Evidence of success |
|---|---|---|
| Remove Entra group membership | Provisioning → session revocation → authentication → Access denial | Update logs and denial times for existing and new sessions |
| Disable a user | New IdP authentication blocked; residual Access sessions handled | Records from both systems; account disablement alone does not establish immediate revocation |
| Disconnect Gateway | Path changes → next protected request | Client state, Access result and request timestamps |
| Device becomes noncompliant | Intune update → Entra evaluation → effect on Access | Compliance-change, reevaluation and denial records |
| User already signed into SaaS | SaaS session management and revocation | SaaS-side denial or session-termination evidence |
For SaaS, Access can enforce policy at initial sign-on and when reissuing the SaaS session. Subsequent session management belongs to the SaaS application. The same policy name therefore has a different enforcement scope from self-hosted HTTP. [7]
Measure change, delivery, revocation and first denial instead of treating configured intervals as a measured SLO. Include missing SCIM updates, retries and long-lived connections. No propagation measurements are supplied with this article.
9. Preserve application authorization and origin protection
The application decides what an admitted principal can do. At the origin, validate the Access JWT signature, issuer, expected application audience and expiry, then map the verified principal to the application user. The presence of an identity header alone is not authentication. [13]
Restrict direct origin access using appropriate Tunnel and firewall arrangements. Review unprotected hostnames, management ports and alternate ingress paths. Having a Tunnel does not establish that every bypass is closed. Cryptographic JWT validation also does not retrieve current revocation state; preserve the Access enforcement path and deliberate application-session management.
The application must enforce tenant ownership, resource scope, role and operation. Include a negative case where a user with a valid Access JWT attempts to operate on another tenant’s resource.
10. Separate human, machine and emergency access
Human access uses Entra authentication and the required context. Machine access uses appropriate Service Auth, narrowly scoped service tokens or mTLS. Do not repurpose a human MFA session for automation. Service Auth has a different evaluation order from human Allow policies; adding it to the same application requires a separate review of reachability and business permissions. [7]
Excluding an emergency Entra account from CA does not automatically admit it through Cloudflare or grant an application role. If Cloudflare itself is unavailable, an Entra exception does not restore the network path either.
For critical infrastructure, consider an independent out-of-band console path. Record custody, authorized users, activation conditions, logging and time-limited recovery procedures. A permanent broad Bypass is not a substitute for a controlled emergency path. Verify that temporary exceptions are removed after recovery.
11. Follow the boundaries when investigating denial
Treating every “cannot log in” report as one kind of 403 makes investigation harder. Separate Entra authentication / CA denial, Access admission denial and origin domain-authorization denial.
1. Identify UTC time, principal, application and requested operation.
2. Did Entra authentication succeed? Which CA policies applied?
3. Was the required context enforced for this user and device?
4. Did Access admit the user? Inspect policy and posture results.
5. Did the request reach the origin with a valid Access JWT?
6. Did domain authorization permit this tenant/resource/action?
7. For stale access, inspect SCIM delivery and every session layer.
Inspect applied CA policies, authentication method, device and risk in Entra sign-in logs. In Cloudflare, inspect the application, policy, posture and available authentication / request records. At the origin, record verified principal, tenant, action and denial reason. Use UTC timestamps, user and application identifiers, and each system’s request or correlation IDs. Do not assume one ID automatically propagates through all products, and never log token bodies or secrets.
Scroll horizontally to view the complete diagram.
Read the diagram as text
Record identity change, SCIM delivery, Access revocation, reauthentication and denial. Check Gateway path changes and origin domain authorization separately. All measurements and acceptance exercises here remain unexecuted.
| Acceptance case | Expected result | Execution status |
|---|---|---|
| Group, context and Gateway all match | Application reachable; only authorized domain operations succeed | NOT_RUN |
| Noncompliant device or insufficient authentication strength | Enforced CA denies or requires stronger authentication | NOT_RUN |
| Context policy is report-only or does not target the user | Deployment review fails because the assurance contract is incomplete | NOT_RUN |
| Consumer WARP only or no Gateway | New protected HTTP requests to the admin application denied | NOT_RUN |
| Group removed while a session exists | Measure propagation and confirm denial within the agreed window | NOT_RUN |
| A permissive Allow or Bypass exists | Detect unexpected admission and correct the complete policy set | NOT_RUN |
| Forged JWT, wrong audience or direct origin request | Token validation or path enforcement denies the request | NOT_RUN |
| Cross-tenant operation or emergency access | Domain boundary holds; only authorized recovery actions are available | NOT_RUN |
Positive cases alone cannot establish the contract. Include changes with live sessions, failed integration delivery and origin bypass. Execute exercises separately with limited targets, stop conditions and recovery procedures.
12. Make responsibility explainable
Record the owner and change rationale for the Entra context contract, the resource and required assurance in the Cloudflare policy, and operational permissions in the application. Review not only which condition changed, but whose decision is refreshed, when that happens and when existing sessions observe it.
Overlapping MFA and device features do not require duplicating every condition. Cloudflare can request Entra’s assurance, add its own path conditions and leave business authorization to the application. That structure makes denial reasons and change impact traceable to a boundary.
Before writing the same condition twice, decide who evaluates it, which boundary consumes the result and when it is refreshed. That is the first design artifact this integration needs.
References
The provider example follows the published 5.23.0 schema. Examples and acceptance records are NOT_RUN; they do not establish adoption or validation in a customer environment.
- Microsoft Entra Conditional Access overview
- Authentication strengths
- Cloudflare: Entra Conditional Access integration
- Entra target resources and authentication context
- Entra report-only mode
- Cloudflare Entra integration, groups and SCIM
- Access policies, selectors and evaluation order
- Require Gateway
- Cloudflare Provider v5.23.0: Access policy · Application schema · Device posture rule schema
- Access session management
- Entra session lifetime and Every time
- Cloudflare SCIM policy behavior
- Validate Access JWTs