top of page

Part 2 of 3: Your Pro-Code Agent Has an Identity Too. Here Is How Conditional Access Governs It

  • Writer: Derek Morgan
    Derek Morgan
  • 2 days ago
  • 7 min read

The CA Drift Sentinel's job is to read the tenant's Conditional Access policies, diff them against a published baseline, and report drift. In this PoC, Conditional Access blocked it.


The block appeared in 2 places: the agent sign-in log and the Container Apps console log, joined by a correlation ID. The Sentinel had its own Entra agent identity. The policy evaluated that identity, found the condition unmet, and denied the token. The control the agent was built to audit treated it as a principal to govern.


Flowchart of Azure Container Apps job and Conditional Access: allowed path or blocked at token issuance, with blue boxes and arrows.
"Diagram illustrating the Azure Container Apps job workflow, showcasing the integration with Conditional Access policies and the decision process for allowing or blocking token issuance based on agent identity and risk assessment."

Part 1 of this series covered 2 Copilot Studio agents, each with its own Entra agent identity and Agent 365 registry entry, governed through the same Entra admin center and Microsoft 365 admin center the IAM team already operates. Part 2 takes the same model to a custom-built, headless agent and adds live enforcement.


The agents touching a tenant's security posture are increasingly custom code running on a schedule. The identity plane has to hold there too.


The CA Drift Sentinel

The Sentinel is a headless, scheduled agent with no signed-in user. It runs as an Azure Container Apps job, calls Microsoft Graph to read Conditional Access policies, diffs them against a committed baseline, and emits a drift report for writeback to the designated SharePoint site. No human in the loop. No browser session to interrupt.


Azure portal Containers page for ca-drift-sentinel shows sidecar and sentinel job containers highlighted in red with an arrow.
Displayed is a configuration screen for a container app job named "ca-drift-sentinel," highlighting two job containers: "sidecar" and "sentinel." Each container shows its CPU core allocation, memory usage, and associated image source.

The Sentinel runs under app-only access. In a standard client-credentials flow, the blueprint principal authenticates and the token subject is the blueprint, not the agent. Conditional Access policies targeting agent identities evaluate the token subject; if the subject is the blueprint, the agent identity is not in scope.


The Entra Auth SDK sidecar resolves this. It runs as a second container alongside the agent, handles the 2-leg token exchange with Entra, and makes the agent identity the token subject in the issued access token. That is what puts the Sentinel in scope for CA policies targeting agent identities.


Secrets never enter the agent code. The sidecar manages the certificate and token lifecycle on the agent's behalf.


Practitioner callout: build order matters! You can hand-assemble an Entra agent identity: create the blueprint, register the identity, assign permissions, wire a federated credential. That agent will authenticate and obey Conditional Access. It won't appear in the Agent 365 registry. Agent 365 expects its own tooling to own blueprint creation. The Agent 365 CLI stamps platform metadata that a hand-built blueprint doesn't carry. In our build, that included the managerApplications linkage the registry keys on. Without it, the registry has no record of the agent. We built the Sentinel Entra-first. The cost was a rebuild through the Agent 365 CLI to get registry visibility. The clean pattern: scaffold with the Agent 365 CLI first, then layer code, permissions, and Conditional Access on top.

Two enforcement signals, proven live

The same identity primitive and CA surface from Part 1 hold for a pro-code agent. The enforcement plane does not change when the build path does.


These agent identity and Conditional Access for agents capabilities are in public preview as of June 2026; verify them in your own tenant before relying on them.


The Sentinel's governance in this PoC used 2 distinct policy shapes. Both are documented enforcement patterns for autonomous agents. Both were proven on the running agent by forcing the condition and capturing the block.


CA-COV012: Allow only approved agent identities

CA-COV012 targets agent identities by a custom security attribute. The attribute set is AgentIdAttributes; the attribute is AgentIdApprovedForUse, a single-valued string with an approved value of yes. Agents without the approved value are blocked at token issuance via a Block grant.


This is an attribute-driven scoping pattern: the policy identifies which agent identities may request tokens for governed resources. Any identity without the approved tag is denied. The practical advantage is scale: adding a new agent to the approved set is an attribute assignment, not a policy edit. The policy stays stable as the agent count grows.


Microsoft Entra conditional access policy editor with Edit filter open, showing AgentIdApprovedForUse equals yes highlighted in red.
Conditional Access Policy Configuration: The image displays the setup of a Conditional Access policy labeled "CA-COV012-Agents-AllowOnlyApprovedAgents," which includes a configured custom security attribute filter. The policy is set to "Report-only," ensuring only approved agents gain access to the specified resources.

To prove the block, we removed the approved attribute from the Sentinel's agent identity and ran the job. The Container Apps log showed a failed Graph call. The service principal sign-in log showed the denial reason. The same correlation ID appeared in both.


CA-COV011: Block agent identities with Medium or High risk

ID Protection for Agents assigns a risk level to an agent identity based on detections, including admin-confirmed compromise. CA-COV011 keys on that risk level.


Risk is a dynamic condition: the same agent identity can clear every token acquisition today and be flagged tomorrow after an anomalous event. CA-COV011 blocks the agent on the first token acquisition after the risk level crosses the threshold. No manual intervention required.


To prove the block, we used the confirm-compromise action on the Sentinel in the Risky Agents report. Confirm-compromise sets the agent's risk to High and creates a risk detection event. On the next token acquisition, CA-COV011 evaluated the signal, found High, and blocked the request.


Azure portal Conditional Access policy editor with Agent risk panel open; High and Medium selected, Low unchecked, Block access shown.
Configuring conditional access policy to block medium and high-risk agents using agent risk levels in a cloud security management interface.

The proof

With the approved attribute present and no active risk, the Sentinel runs clean: it acquires its token, reads the policies, and produces the drift report. The two blocks here are the deny side of the same identity evaluation.


Both blocks appear in the service principal sign-in logs. The Agent type field reads Agent Identity; the Agent subject type field reads Not Agentic. The Container Apps console log shows the same run as a failed Graph call. One correlation ID ties the two records together.


  1. Blocked due to missing custom security attribute:

Azure Logs query results showing a highlighted ERROR: BLOCKED BY CONDITIONAL ACCESS, token acquisition denied in sentinel logs.
Log data analysis in Azure Monitor displays an error related to conditional access blocking token acquisition, with a specific error code (AADSTS53003) and correlation ID for troubleshooting.
Azure sign-in logs details pane with highlighted Correlation ID and failure reason: access blocked by Conditional Access policies.
Sign-in attempt failed due to Conditional Access policy restrictions. Access was blocked, preventing token issuance, as detailed in the sign-in logs for CA Drift Sentinel Identity.
Azure sign-in logs page showing Activity Details: Sign-ins with Conditional access tab; policy CA-COV012 blocked, result Failure.
Conditional Access sign-in logs reveal a failure in user authentication due to a blocking policy called "CA-COV012-Agents-AllowOnlyApprovedAgents", which resulted in an unsuccessful login attempt.

  1. Blocked due to "agent compromise" and at High risk:

    Azure Logs query results with a red callout highlighting a sentinel ERROR: blocked by conditional access, token acquisition denied.
    Log details from the Azure Resource Manager display an error in the Sentinel container, indicating "BLOCKED BY CONDITIONAL ACCESS" due to token acquisition being denied, with error code AADSTS53003 and a specific correlation ID.
    Azure sign-in logs showing Activity Details: Sign-ins, with Correlation ID highlighted and failure blocked by Conditional Access.
    The image displays a sign-in activity log from the CA Drift Sentinel Identity management interface. It highlights a failed sign-in attempt on June 17, 2026, due to a conditional access policy blocking token issuance. The error code is 53003, and the failure reason is prominently noted.
    Azure sign-in logs with Activity Details pane on Conditional Access tab, highlighting blocked policy CA-COV011 and failure.
    Sign-in attempt failed due to a conditional access policy block in CA Drift Sentinel Identity, highlighting potential security measures in place.

Conditional Access blocked the agent built to audit Conditional Access. The block is documented, attributed to the agent identity, and traceable end to end.


Why this matters

A pro-code agent with Graph read access to a tenant's security configuration is a reconnaissance asset if compromised. It can read CA policies, inspect named locations, enumerate enforcement targets, and map the policy posture before any analyst notices.


Risk-based CA changes the response timeline. ID Protection flags the agent at detection. CA-COV011 acts on that flag at the next token acquisition. No analyst opens a ticket or initiates a block. The enforcement follows the signal.


The gap, without either policy, is detection without enforcement. ID Protection can surface a risky agent in the Risky Agents report. Without a CA policy consuming that signal, the agent continues to acquire tokens until someone manually disables it. In a tenant with a growing agent count, that manual step is the one that gets deferred.


How to build and prove it

7 steps, ordered. Engineers can act. Executives can audit.


Step 1. Scaffold the blueprint with the Agent 365 CLI first. The CLI stamps the platform metadata the Agent 365 registry requires (in our tenant, the managerApplications linkage); going Entra-first forces a rebuild to get registry visibility. See the build-order callout above.


Step 2. Layer your code, add the Auth SDK sidecar as a second container, and confirm the sub claim in the issued token matches the agent identity's object ID, not the blueprint principal's.


Step 3. Confirm the agent appears in the Agent 365 registry (Microsoft 365 admin center, Agents, All Agents, Registry) with the Entra Agent ID GUID and platform of origin populated.


Step 4. Create an AgentIdAttributes attribute set with an AgentIdApprovedForUse attribute (String, single-valued) and assign the approved value yes to the Sentinel's agent identity.


Step 5. Author CA-COV012 targeting agent identities by the AgentIdApprovedForUse attribute, Block grant, in Report-only mode first.


Step 6. Enable ID Protection for Agents and author CA-COV011 with the agent risk condition set to High, grant to Block.


Step 7. Prove both blocks. Remove the approved attribute to trip CA-COV012. Use confirm-compromise in the Risky Agents report to trip CA-COV011. Capture the Container Apps log and service principal sign-in log for each block. Join them on the correlation ID.


Validation checklist

  • Blueprint scaffolded via Agent 365 CLI; agent visible in the registry

  • Token sub claim = agent identity object ID (not the blueprint principal's)

  • Agent 365 registry entry: Entra Agent ID GUID and platform of origin populated

  • CA-COV012 in enforcement mode; approved AgentIdApprovedForUse attribute (value yes) assigned to the Sentinel

  • CA-COV011 in enforcement mode; ID Protection for Agents active

  • Both blocks documented: service principal sign-in log and Container Apps log joined by correlation ID


Pattern guidance: Start with defensive-only, read-only Graph scope. The SharePoint write-back path is a separate investigation and is not covered here.


Where this leaves you

The identity plane holds from low-code to pro-code. The same Conditional Access policies that govern a Copilot Studio agent govern an Azure Container Apps job built from scratch. The same Agent 365 registry holds both.


Build order is the one lesson worth taking into the next build: scaffold through the Agent 365 CLI, then add code and policies. Going Entra-first costs a rebuild to get registry visibility.


For most tenants, the live question is whether the custom automation already running has its own agent identity and a CA policy that can block it on risk. Custom automation without governed identity sits outside the enforcement plane. The tooling to bring it in is the same tooling from Part 1.


Part 3 closes the series. Identity and Conditional Access decide whether an agent gets a token. They say nothing about the data it reads once it has one, or the signal you get when an agent identity is the thing under attack. That is where Purview and Defender come in: Purview for the sensitivity and movement of the data an agent touches, Defender for detection and response when an agent is compromised. Same two agents, low-code and pro-code; one more plane of control.

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page