Practical engineering guidance
Securing enterprise AI agents: a hands-on Microsoft implementation guide
A practical guide to governing AI agents with Entra Agent ID, Conditional Access, Defender and Purview, including PowerShell, Graph requests and validation.
What this guide builds
AI agents can read data, call tools and take actions at machine speed. A production design needs an accountable identity, narrowly scoped access, a controlled execution path, data protection, runtime monitoring and a tested way to stop the agent.
This worked example creates an autonomous reporting agent that reads approved data and produces a report. It does not receive permission to modify users, applications or directory roles. You will build:
- an inventory and approval record;
- a Microsoft Entra agent identity blueprint with an owner and sponsor;
- a dedicated child agent identity;
- credentialless authentication from an Azure managed identity;
- a Conditional Access boundary deployed first in report-only mode;
- Microsoft Defender discovery and monitoring; and
- validation, containment and recovery procedures.
Microsoft Entra Agent ID, Conditional Access for agents and some Defender for Agent 365 features may be preview or licence-dependent. Test in a non-production tenant and verify availability before production use.
Architecture and trust boundaries
Use a separate identity for each deployed agent instance. The identity blueprint defines common configuration; each agent identity becomes the auditable principal requesting access.
The request path should be:
- The workload authenticates from an approved Azure environment.
- Microsoft Entra issues a token for the agent identity.
- Conditional Access evaluates the agent, target resource and risk.
- The target API enforces its own permissions.
- Defender and resource audit logs record the action.
- High-impact tools require approval outside the model response.
Keep read, propose and execute as separate capabilities. A reporting agent can read and propose. A separate workflow should execute privileged changes after approval.
Prerequisites
Prepare a test tenant and confirm:
- PowerShell 7 and Microsoft Graph PowerShell;
- Agent ID Administrator or Agent ID Developer for blueprint work;
- Conditional Access Administrator for access policies;
- Security Administrator for Defender configuration;
- an Azure workload with a managed identity; and
- the licences required for the features you will test.
Install the Graph modules:
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.Applications -Scope CurrentUser
Install-Module Microsoft.Graph.Users -Scope CurrentUser
Get-InstalledModule Microsoft.Graph* |
Select-Object Name, Version |
Sort-Object Name
Do not paste production secrets into a console transcript, repository or AI prompt. The production path below uses managed identity federation.
Step 1: create the governance record
Create the record before the identity. A repository-backed YAML file makes ownership reviewable:
agentId: finance-reporting-agent-prod
purpose: Read approved finance data and prepare a daily summary
businessOwner: finance-operations
technicalOwner: cloud-platform
sponsor: named-user-or-supported-group
environment: production
dataClassification: confidential
allowedDataSources:
- approved-reporting-api
allowedActions: [read, summarise]
blockedActions: [update-records, send-external-email, change-permissions]
humanApprovalRequired: [publish-report]
reviewFrequencyDays: 90
expiryDate: 2027-09-19
The owner maintains the service. The sponsor remains accountable for its business purpose. Reject identities with no sponsor, no expiry or an undefined data boundary.
Step 2: connect to Microsoft Graph
Replace the example values before running any command:
$TenantId = "00000000-0000-0000-0000-000000000000"
$BlueprintName = "Finance Reporting Agent Blueprint"
$AgentName = "Finance Reporting Agent - Production"
Connect-MgGraph -TenantId $TenantId -Scopes @(
"AgentIdentityBlueprint.Create"
"AgentIdentityBlueprint.AddRemoveCreds.All"
"AgentIdentityBlueprint.UpdateAuthProperties.All"
"AgentIdentityBlueprintPrincipal.Create"
"AgentIdentity.Create.All"
"User.Read"
)
Get-MgContext | Select-Object TenantId, Account, Scopes
Review the consent screen. In production, split creation, credential management and approval between operators rather than granting one administrator every scope permanently.
Step 3: create the agent identity blueprint
The sponsor is mandatory. This lab uses the signed-in administrator as initial owner and sponsor; assign the accountable production sponsor afterward.
$Context = Get-MgContext
$CurrentUser = Get-MgUser -UserId $Context.Account
$BlueprintBody = @{
"@odata.type" = "Microsoft.Graph.AgentIdentityBlueprint"
displayName = $BlueprintName
"sponsors@odata.bind" = @(
"https://graph.microsoft.com/v1.0/users/$($CurrentUser.Id)"
)
"owners@odata.bind" = @(
"https://graph.microsoft.com/v1.0/users/$($CurrentUser.Id)"
)
} | ConvertTo-Json -Depth 5
$Blueprint = Invoke-MgGraphRequest `
-Method POST `
-Uri "https://graph.microsoft.com/v1.0/applications/microsoft.graph.agentIdentityBlueprint" `
-Headers @{ "OData-Version" = "4.0" } `
-Body $BlueprintBody `
-ContentType "application/json"
$Blueprint | Select-Object id, appId, displayName
$BlueprintObjectId = $Blueprint.id
$BlueprintAppId = $Blueprint.appId
Do not use New-MgApplication, New-AzADApplication or az ad app create. They create a standard application, not an Agent ID object with agent sponsorship, lifecycle and audit behaviour.
Create the blueprint principal:
$PrincipalBody = @{ appId = $BlueprintAppId } | ConvertTo-Json
$BlueprintPrincipal = Invoke-MgGraphRequest `
-Method POST `
-Uri "https://graph.microsoft.com/v1.0/servicePrincipals/microsoft.graph.agentIdentityBlueprintPrincipal" `
-Headers @{ "OData-Version" = "4.0" } `
-Body $PrincipalBody `
-ContentType "application/json"
$BlueprintPrincipal | Select-Object id, appId, displayName, accountEnabled
The application object ID, application/client ID and principal object ID are different. Label each one in the deployment record.
Step 4: configure managed identity federation
For an agent on Azure App Service, Functions, Container Apps or a VM, prefer managed identity over a secret. Obtain the managed identity’s principal object ID:
$ManagedIdentityPrincipalId = "11111111-1111-1111-1111-111111111111"
$FederatedCredential = @{
Name = "finance-reporting-agent-azure-mi"
Issuer = "https://login.microsoftonline.com/$TenantId/v2.0"
Subject = $ManagedIdentityPrincipalId
Audiences = @("api://AzureADTokenExchange")
}
New-MgApplicationFederatedIdentityCredential `
-ApplicationId $BlueprintObjectId `
-BodyParameter $FederatedCredential
Get-MgApplicationFederatedIdentityCredential `
-ApplicationId $BlueprintObjectId |
Select-Object Id, Name, Issuer, Subject, Audiences
Use a certificate where managed identity is unavailable. Use a client secret only for short-lived development, keep its lifetime short and store it in a managed vault.
Step 5: create the child agent identity
The child is the runtime principal. The agentIdentityBlueprintId value is the blueprint app ID.
$AgentBody = @{
displayName = $AgentName
agentIdentityBlueprintId = $BlueprintAppId
"sponsors@odata.bind" = @(
"https://graph.microsoft.com/v1.0/users/$($CurrentUser.Id)"
)
} | ConvertTo-Json -Depth 5
$AgentIdentity = Invoke-MgGraphRequest `
-Method POST `
-Uri "https://graph.microsoft.com/v1.0/servicePrincipals/microsoft.graph.agentIdentity" `
-Headers @{ "OData-Version" = "4.0" } `
-Body $AgentBody `
-ContentType "application/json"
$AgentIdentity | Select-Object id, displayName, servicePrincipalType, agentIdentityBlueprintId
$AgentObjectId = $AgentIdentity.id
Validate the object:
$AgentCheck = Invoke-MgGraphRequest `
-Method GET `
-Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$AgentObjectId"
$AgentCheck | Select-Object id, displayName, servicePrincipalType, accountEnabled
Also verify it in Microsoft Entra admin center > Entra ID > Agents > Agent identities.
Step 6: grant the minimum permission
Start with no resource permission. Map every required API operation to the narrowest delegated scope, application role or resource-specific role. Microsoft blocks several high-risk permissions for agent identities, but that boundary does not replace your least-privilege review.
A blueprint can define which resource apps have inheritable permissions. This defines what can be inherited; administrators must still grant and consent to the underlying permissions.
$GraphResourceAppId = "00000003-0000-0000-c000-000000000000"
$InheritanceBody = @{
resourceAppId = $GraphResourceAppId
inheritableScopes = @{
"@odata.type" = "#microsoft.graph.allAllowedScopes"
kind = "allAllowed"
}
inheritableRoles = @{
"@odata.type" = "#microsoft.graph.allAllowedRoles"
kind = "allAllowed"
}
} | ConvertTo-Json -Depth 5
Invoke-MgGraphRequest `
-Method POST `
-Uri "https://graph.microsoft.com/v1.0/applications/microsoft.graph.agentIdentityBlueprint/$BlueprintObjectId/inheritablePermissions" `
-Headers @{ "OData-Version" = "4.0" } `
-Body $InheritanceBody `
-ContentType "application/json"
This shows the administration mechanism, not a recommendation to grant every Graph permission. allAllowed lets eligible permissions granted for that resource be inherited. For sensitive agents, prefer explicit grants, review inherited baselines and separate read-only and action-taking agents into different blueprints.
Test a permitted read and a prohibited write. Least-privilege validation is incomplete until the prohibited operation fails.
Step 7: create the Conditional Access boundary
Use the Entra admin center so the agent-specific picker and risk controls are easy to verify:
- Go to Entra ID > Conditional Access > Policies > New policy.
- Name it
CA-AI-Agents-Block-Unapproved. - Under Users, agents or workload identities, select Agents.
- Include All agent identities.
- Exclude only reviewed and approved blueprints or identities.
- Under Target resources, include All resources.
- Under Grant, select Block access.
- Set it to Report-only and create it.
Create a second policy for agent risk: include all agent identities and resources, select Conditions > Agent risk > High, choose Block access, and start in Report-only.
Run representative workflows and review Conditional Access insights and sign-in logs. Move a policy to On only after proving that approved agents work and unapproved or risky agents are denied.
Step 8: enable Microsoft Defender protection
After onboarding to Microsoft Agent 365:
- Open the Microsoft Defender portal.
- Go to Settings > Security for AI > Get started.
- Confirm security for AI agents is enabled.
- Connect Microsoft 365 and include Microsoft Entra ID management events and Microsoft 365 activities.
- For Copilot Studio agents, enable real-time protection with the Power Platform administrator.
- Confirm the connector status is Connected.
Without the Microsoft 365 connector, supported runtime blocking can continue, but related alerts and incidents might not appear in Defender. Monitor connector health. Under Assets > AI assets, confirm the agent appears, has an owner and has no unresolved excessive-permission findings.
Step 9: validate and hunt
Defender hunting schema can vary by rollout. In Advanced Hunting > Schema, search for tables containing AI, Agent or CloudApp, and prefer Microsoft-provided queries rather than guessing table names.
Use Graph to validate the deployed identities:
Invoke-MgGraphRequest -Method GET -Uri `
"https://graph.microsoft.com/v1.0/applications/microsoft.graph.agentIdentityBlueprint/$BlueprintObjectId"
Invoke-MgGraphRequest -Method GET -Uri `
"https://graph.microsoft.com/v1.0/servicePrincipals/$AgentObjectId"
$FilterName = [uri]::EscapeDataString("displayName eq '$AgentName'")
Invoke-MgGraphRequest -Method GET -Uri `
"https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=$FilterName&`$select=id,displayName,accountEnabled,servicePrincipalType"
Complete these tests:
| Test | Expected result |
|---|---|
| Approved agent performs allowed read | Token and API request succeed |
| Agent attempts prohibited write | Target API returns access denied |
| Unapproved agent targets protected resource | Report-only event first; blocked after enforcement |
| Prompt requests a credential | Agent refuses; no secret in output or logs |
| Prompt requests an unapproved tool | Tool gateway denies invocation |
| Defender connector is interrupted | Operational monitoring alerts |
| Agent identity is disabled | New token acquisition fails |
Use test identities and synthetic data. Do not run destructive simulations in production.
Step 10: enforce every tool call in code
Identity controls decide who may request access. Application code must still authorise each tool invocation:
if tool not in approved_tools:
deny("Tool is not approved")
if requested_resource not in approved_resources:
deny("Resource is outside the approved boundary")
if action in [delete, publish, send_external, change_permission]:
require_human_approval()
execute_with_agent_identity()
write_immutable_audit_event()
Never use the system prompt as the only authorisation control. Log agent object ID, blueprint, calling user when applicable, tool, target, approval reference, result and correlation ID. Avoid full prompts or outputs when they contain sensitive data.
Step 11: protect the data
Apply Microsoft Purview sensitivity labels and data-loss-prevention policies where the platform and data path support them. For each source, document:
- which classifications the agent may read;
- whether output inherits source classification;
- allowed destinations and external-sharing restrictions;
- retention and deletion requirements; and
- whether prompts and responses are collected for monitoring.
Test with synthetic labelled documents. Confirm the agent cannot move protected content to an unapproved destination and that blocked attempts produce investigation evidence.
Step 12: containment and recovery
For a single affected agent, disable the child service principal:
Update-MgServicePrincipal `
-ServicePrincipalId $AgentObjectId `
-AccountEnabled:$false
Get-MgServicePrincipal -ServicePrincipalId $AgentObjectId |
Select-Object Id, DisplayName, AccountEnabled
Re-enable only after investigation and approval:
Update-MgServicePrincipal `
-ServicePrincipalId $AgentObjectId `
-AccountEnabled:$true
Disabling the blueprint principal provides a broader kill switch for its child identities. Your incident runbook should also stop the deployment and tool gateway, remove affected permissions, preserve logs, identify actions, rotate downstream credentials, correct the weakness and require owner approval before recovery.
Already-issued tokens can remain valid until expiry or resource-side revocation takes effect. A tool-gateway kill switch adds immediate application-level containment.
Production checklist
- Named business owner, technical owner and sponsor
- Purpose, environment, expiry and review date recorded
- Dedicated identity created from an Agent ID blueprint
- Managed identity federation or certificate authentication
- Effective permissions documented and tested
- Prohibited write test fails
- Conditional Access evaluated in report-only mode
- High-risk agent policy tested
- Agent visible in Defender inventory
- Connector health monitored
- Tool calls enforced outside the model
- Human approval for consequential actions
- Purview/DLP tested with synthetic data
- Single-agent and blueprint containment tested
Common mistakes
Creating a normal app registration and calling it an agent. Use a blueprint and agent identity so sponsorship, lifecycle and audit semantics are available.
Giving the agent a shared administrator account. Use a dedicated non-human identity and the minimum resource access.
Treating inherited permissions as harmless. A broad blueprint baseline affects current and future child identities.
Enabling blocking immediately. Use report-only mode, review impact, test approved and denied paths, then enforce.
Logging every prompt without a data review. Observability can contain confidential input and output. Agree collection, access, retention and regional requirements.
Using the prompt as an access-control list. Enforce tools and resources in code and at the target API.
Tested scope and limitations
These commands follow Microsoft Graph v1.0 Agent ID endpoints and Microsoft documentation available on 19 September 2026. They use placeholders and were syntax-reviewed but were not executed against the reader’s tenant. Roles, licences, preview availability, Defender schema and portal labels can differ.
Test in a non-production tenant. Microsoft recommends the Microsoft 365 Agents SDK for new projects because it handles identity creation and Agent 365 registration. If provisioning directly through Graph, also register the agent in the Agent 365 registry so administrators can discover and govern it.
References
- Create an agent identity blueprint
- Create an agent identity with Microsoft Graph
- Plan an agent identity architecture
- Authorization in Microsoft Entra Agent ID
- Configure inheritable permissions
- Conditional Access policies for autonomous agents
- Enable security for AI agents using Microsoft Defender
- Discover AI agents and assess security posture
- Data handling and privacy in Defender for Agent 365
Reader feedback
Was this article useful?
No ratings yet. Be the first to rate this article.
