Blog Post

Apps on Azure Blog
13 MIN READ

Govern AI Agents on App Service with the Microsoft Agent Governance Toolkit

jordanselig's avatar
jordanselig
Icon for Microsoft rankMicrosoft
Apr 13, 2026

The Microsoft Agent Governance Toolkit brings runtime security to AI agents — policy enforcement, audit logging, and SRE practices in a single open-source package. In this final part of our series, we add governance to the travel planner in under 30 minutes and show why App Service's enterprise features make it the ideal host for governed agent workloads.

Part 3 of 3 — Multi-Agent AI on Azure App Service

In Blog 1, we built a multi-agent travel planner with Microsoft Agent Framework 1.0 on App Service. In Blog 2, we added observability with OpenTelemetry and the new Application Insights Agents view. Now in Part 3, we secure those agents for production with the Microsoft Agent Governance Toolkit.

This post assumes you've followed the guidance in Blog 1 to deploy the multi-agent travel planner to Azure App Service. If you haven't deployed the app yet, start there first.

The governance gap

Our travel planner works. It's observable. But here's the question I'm hearing from customers: "How do I make sure my agents don't do something they shouldn't?"

It's a fair question. Our six agents — Coordinator, Currency Converter, Weather Advisor, Local Knowledge, Itinerary Planner, and Budget Optimizer — can call external APIs, process user data, and make autonomous decisions. In a demo, that's impressive. In production, that's a risk surface.

Consider what can go wrong with ungoverned agents:

  • Unauthorized API calls — An agent calls an external API it was never intended to use, leaking data or incurring costs
  • Sensitive data exposure — An agent passes PII to a third-party service without consent controls
  • Runaway token spend — A recursive agent loop burns through your OpenAI budget in minutes
  • Tool misuse — A prompt injection tricks an agent into executing a tool it shouldn't
  • Cascading failures — One agent's error propagates through the entire multi-agent workflow

These aren't theoretical. In December 2025, OWASP published the Top 10 for Agentic Applications — the first formal taxonomy of risks specific to autonomous AI agents, including goal hijacking, tool misuse, identity abuse, memory poisoning, and rogue agents. Regulators are paying attention too: the EU AI Act's high-risk AI obligations take effect in August 2026, and the Colorado AI Act becomes enforceable in June 2026.

The bottom line: if you're running agents in production, you need governance. Not eventually — now.

What the Agent Governance Toolkit does

The Agent Governance Toolkit is an open-source project (MIT license) from Microsoft that brings runtime security governance to autonomous AI agents. It's the first toolkit to address all 10 OWASP agentic AI risks with deterministic, sub-millisecond policy enforcement.

The toolkit is organized into 7 packages:

PackageWhat it doesThink of it as...
Agent OSStateless policy engine, intercepts every action before execution (<0.1ms p99)The kernel for AI agents
Agent MeshCryptographic identity (DIDs), inter-agent trust protocol, dynamic trust scoringmTLS for agents
Agent RuntimeExecution rings (like CPU privilege levels), saga orchestration, kill switchProcess isolation for agents
Agent SRESLOs, error budgets, circuit breakers, chaos engineeringSRE practices for agents
Agent ComplianceAutomated governance verification, regulatory mapping (EU AI Act, HIPAA, SOC2)Compliance-as-code
Agent MarketplacePlugin lifecycle management, Ed25519 signing, supply-chain securityPackage manager security
Agent LightningRL training governance with policy-enforced runnersSafe training guardrails

The toolkit is available in Python, TypeScript, Rust, Go, and .NET. It's framework-agnostic — it works with MAF, LangChain, CrewAI, Google ADK, and more. For our ASP.NET Core travel planner, we'll use the .NET SDK via NuGet (Microsoft.AgentGovernance).

For this blog, we're focusing on three packages:

  • Agent OS — the policy engine that intercepts and evaluates every agent action
  • Agent Compliance — regulatory mapping and audit trail generation
  • Agent SRE — SLOs and circuit breakers for agent reliability

How easy it was to add governance

Here's the part that surprised me. I expected adding governance to a production agent system to be a multi-hour effort — new infrastructure, complex configuration, extensive refactoring. Instead, it took about 30 minutes.

Here's exactly what we changed:

Step 1: Add NuGet packages

Three packages added to TravelPlanner.Shared.csproj:

<itemgroup> <!-- Existing packages --> <packagereference include="Azure.Monitor.OpenTelemetry.AspNetCore" version="1.3.0"> <packagereference include="Microsoft.Agents.AI" version="1.0.0"> <!-- NEW: Agent Governance Toolkit (single package, all features included) --> <packagereference include="Microsoft.AgentGovernance" version="3.0.2"> </packagereference></packagereference></packagereference></itemgroup>

Step 2: Create the policy file

One new file: governance-policies.yaml in the project root. This is where all your governance rules live:

apiVersion: governance.toolkit/v1 name: travel-planner-governance description: Policy enforcement for the multi-agent travel planner on App Service scope: global defaultAction: deny rules: - name: allow-currency-conversion condition: "tool == 'ConvertCurrency'" action: allow priority: 10 description: Allow Currency Converter agent to call Frankfurter exchange rate API - name: allow-weather-forecast condition: "tool == 'GetWeatherForecast'" action: allow priority: 10 description: Allow Weather Advisor agent to call NWS forecast API - name: allow-weather-alerts condition: "tool == 'GetWeatherAlerts'" action: allow priority: 10 description: Allow Weather Advisor agent to check NWS weather alerts

Step 3: One line in BaseAgent.cs

This is the moment. Here's our BaseAgent.cs before:

Agent = new ChatClientAgent(
    chatClient, instructions: Instructions, 
    name: AgentName, description: Description)
    .AsBuilder()
    .UseOpenTelemetry(sourceName: AgentName)
    .Build();

And after:

var kernel = serviceProvider.GetService<GovernanceKernel>();
if (kernel is not null)
    builder.UseGovernance(kernel, AgentName);

Agent = builder.Build();

One line of intent, two lines of null-safety. The .UseGovernance(kernel, AgentName) call intercepts every tool/function invocation in the agent's pipeline, evaluating it against the loaded policies before execution. If the GovernanceKernel isn't registered (governance disabled), agents work exactly as before — no crash, no code change needed.

Here's the full updated constructor using IServiceProvider to optionally resolve governance:

using AgentGovernance;
using Microsoft.Extensions.DependencyInjection;

public abstract class BaseAgent : IAgent
{
    protected readonly ILogger Logger;
    protected readonly AgentOptions Options;
    protected readonly AIAgent Agent;

    // Constructor for simple agents without tools
    protected BaseAgent(
        ILogger logger,
        IOptions<AgentOptions> options,
        IChatClient chatClient,
        IServiceProvider serviceProvider)
    {
        Logger = logger;
        Options = options.Value;

        var builder = new ChatClientAgent(
            chatClient, instructions: Instructions,
            name: AgentName, description: Description)
            .AsBuilder()
            .UseOpenTelemetry(sourceName: AgentName);

        var kernel = serviceProvider.GetService<GovernanceKernel>();
        if (kernel is not null)
            builder.UseGovernance(kernel, AgentName);

        Agent = builder.Build();
    }

    // Constructor for agents with tools
    protected BaseAgent(
        ILogger logger,
        IOptions<AgentOptions> options,
        IChatClient chatClient,
        ChatOptions chatOptions,
        IServiceProvider serviceProvider)
    {
        Logger = logger;
        Options = options.Value;

        var builder = new ChatClientAgent(
            chatClient, instructions: Instructions,
            name: AgentName, description: Description,
            tools: chatOptions.Tools?.ToList())
            .AsBuilder()
            .UseOpenTelemetry(sourceName: AgentName);

        var kernel = serviceProvider.GetService<GovernanceKernel>();
        if (kernel is not null)
            builder.UseGovernance(kernel, AgentName);

        Agent = builder.Build();
    }
    
    // ... rest unchanged
}

Step 4: DI registrations in Program.cs

A few lines to wire up governance in the dependency injection container:

using AgentGovernance;

// ... existing builder setup ...

// Configure OpenTelemetry with Azure Monitor (existing — from Blog 2)
builder.Services.AddOpenTelemetry().UseAzureMonitor();

// NEW: Configure Agent Governance Toolkit
// Load policy from YAML, register as singleton. Agents resolve via IServiceProvider.
var policyPath = Path.Combine(builder.Environment.ContentRootPath, "governance-policies.yaml");
if (File.Exists(policyPath))
{
    try
    {
        var yaml = File.ReadAllText(policyPath);
        var kernel = new GovernanceKernel(new GovernanceOptions 
        { 
            EnableAudit = true, 
            EnableMetrics = true 
        });
        kernel.LoadPolicyFromYaml(yaml);
        builder.Services.AddSingleton(kernel);
        Console.WriteLine($"[Governance] Loaded policies from {policyPath}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"[Governance] Failed to load: {ex.Message}. Running without governance.");
    }
}

That's it. Your agents are now governed.

Let me repeat that because it's the core message of this blog: we added production governance to a six-agent system by adding one NuGet package, creating one YAML policy file, adding a few lines to our base agent class, and registering the governance kernel in DI. No new infrastructure. No complex rewiring. No multi-sprint project. If you followed Blog 1 and Blog 2, you can do this in 30 minutes.

Policy flexibility deep-dive

The YAML policy language is intentionally simple to start with, but it supports real complexity when you need it. Let's walk through what each policy in our file does.

API allowlists and blocklists

Our travel planner calls two external APIs: Frankfurter (currency exchange) and the National Weather Service. The defaultAction: deny combined with explicit allow rules ensures agents can only call these approved tools. If an agent attempts to call any other function — whether through a prompt injection or a bug — the call is blocked before it executes:

defaultAction: deny
rules:
  - name: allow-currency-conversion
    condition: "tool == 'ConvertCurrency'"
    action: allow
    priority: 10
  - name: allow-weather-forecast
    condition: "tool == 'GetWeatherForecast'"
    action: allow
    priority: 10

When a blocked call happens, you'll see output like this in your logs:

[Governance] Tool call 'DeleteDatabase' blocked for agent 'LocalKnowledgeAgent': 
  No matching rules; default action is deny.

Condition language

The condition field supports equality checks, pattern matching, and boolean logic. You can match on tool name, agent ID, or any key in the evaluation context:

# Match a specific tool
condition: "tool == 'ConvertCurrency'"

# Match multiple tools with OR
condition: "tool == 'GetWeatherForecast' or tool == 'GetWeatherAlerts'"

# Match by agent
condition: "agent == 'CurrencyConverterAgent' and tool == 'ConvertCurrency'"

Priority and conflict resolution

When multiple rules match, the toolkit evaluates by priority (higher number = higher priority). A deny rule at priority 100 will override an allow rule at priority 10. This lets you layer broad allows with specific denies:

rules:
  - name: allow-all-weather-tools
    condition: "tool == 'GetWeatherForecast' or tool == 'GetWeatherAlerts'"
    action: allow
    priority: 10
  - name: block-during-maintenance
    condition: "tool == 'GetWeatherForecast'"
    action: deny
    priority: 100
    description: Temporarily block NWS calls during API maintenance

Advanced: OPA Rego and Cedar

The YAML policy language handles most scenarios, but for teams with advanced needs, the toolkit also supports OPA Rego and Cedar policy languages. You can mix them — use YAML for simple rules and Rego for complex conditional logic:

# policies/advanced.rego — Example: time-based access control
package travel_planner.governance

default allow_tool_call = false

allow_tool_call {
    input.agent == "CurrencyConverterAgent"
    input.tool == "get_exchange_rate"
    time.weekday(time.now_ns()) != "Sunday"  # Markets closed
}

Start simple with YAML. Add complexity only when you need it.

Why App Service for governed agent workloads

You might be wondering: why does hosting platform matter for governance? It matters a lot. The governance toolkit handles the application-level policies, but a production agent system also needs platform-level security, networking, identity, and deployment controls. App Service gives you these out of the box.

Managed Identity

Governance policies enforce what agents can access. Managed Identity handles how they authenticate — without secrets to manage, rotate, or leak. Our travel planner already uses DefaultAzureCredential for Azure OpenAI, Cosmos DB, and Service Bus. Governance layers on top of this identity foundation.

VNet Integration + Private Endpoints

The governance toolkit enforces API allowlists at the application level. App Service's VNet integration and private endpoints enforce network boundaries at the infrastructure level. This is defense in depth: even if a governance policy is misconfigured, the network layer prevents unauthorized egress. Your agents can only reach the networks you've explicitly allowed.

Easy Auth

App Service's built-in authentication (Easy Auth) protects your agent APIs without custom code. Before a request even reaches your governance engine, App Service has already validated the caller's identity. No custom auth middleware. No JWT parsing. Just toggle it on.

Deployment Slots

This is underrated for governance. With deployment slots, you can test new governance policies in a staging slot before swapping to production. Deploy updated governance-policies.yaml to staging, run your test suite, verify the policies work as expected, and then swap. Zero-downtime policy updates with full rollback capability.

App Insights integration

Governance audit events flow into the same Application Insights instance we configured in Blog 2. This means your governance decisions appear alongside your OTel traces in the Agents view. One pane of glass for agent behavior and governance enforcement.

Always-on + WebJobs

Our travel planner uses WebJobs for long-running agent workflows. With App Service's Always-on feature, those workflows stay warm, and governance is continuous — no cold-start gaps where agents run unmonitored.

azd deployment

One command deploys the full governed stack — application code, governance policies, infrastructure, and monitoring:

azd up

App Service gives you the enterprise production features governance needs — identity, networking, observability, safe deployment — out of the box. The governance toolkit handles agent-level policy enforcement; App Service handles platform-level security. Together, they're a complete governed agent platform.

Governance audit events in App Insights

In Blog 2, we set up OpenTelemetry and the Application Insights Agents view to monitor agent behavior. With the governance toolkit, those same traces now include governance audit events — every policy decision is recorded as a span attribute on the agent's trace.

When you open a trace in the Agents view, you'll see governance events inline:

  • Policy: api-allowlist → ALLOWED — CurrencyConverterAgent called Frankfurter API, permitted
  • Policy: token-budget → ALLOWED — Request used 3,200 tokens, within per-request limit of 8,000
  • Policy: rate-limit → THROTTLED — WeatherAdvisorAgent exceeded 60 calls/min, request delayed

For deeper analysis, use KQL to query governance events directly. Here's a query that finds all policy violations in the last 24 hours:

// Find all governance policy violations in the last 24 hours
traces
| where timestamp > ago(24h)
| where customDimensions["governance.decision"] != "ALLOWED"
| extend 
    agentName = tostring(customDimensions["agent.name"]),
    policyName = tostring(customDimensions["governance.policy"]),
    decision = tostring(customDimensions["governance.decision"]),
    violationReason = tostring(customDimensions["governance.reason"]),
    targetUrl = tostring(customDimensions["tool.target_url"])
| project timestamp, agentName, policyName, decision, violationReason, targetUrl
| order by timestamp desc

And here's one for tracking token budget consumption across agents:

// Token budget consumption by agent over the last hour
customMetrics
| where timestamp > ago(1h)
| where name == "governance.tokens.consumed"
| extend agentName = tostring(customDimensions["agent.name"])
| summarize 
    totalTokens = sum(value),
    avgTokensPerRequest = avg(value),
    maxTokensPerRequest = max(value)
    by agentName, bin(timestamp, 5m)
| order by totalTokens desc

This is the power of integrating governance with your existing observability stack. You don't need a separate governance dashboard — everything lives in the same App Insights workspace you already know.

SRE for agents

The Agent SRE package brings Site Reliability Engineering practices to agent systems. This was the part that got me most excited, because it addresses a question I hear constantly: "How do I know my agents are actually reliable?"

Service Level Objectives (SLOs)

We defined SLOs in our policy file:

slos:
  - name: weather-agent-latency
    agent: "WeatherAdvisorAgent"
    metric: latency-p99
    target: 5000ms
    window: 5m

This says: "The Weather Advisor Agent must respond within 5 seconds at the 99th percentile, measured over a 5-minute rolling window." When the SLO is breached, the toolkit emits an alert event and can trigger automated responses.

Circuit breakers

Circuit breakers prevent cascading failures. If an agent fails 5 times in a row, the circuit opens, and subsequent requests get a fast failure response instead of waiting for another timeout:

circuit-breakers:
  - agent: "*"
    failure-threshold: 5
    recovery-timeout: 30s
    half-open-max-calls: 2

After 30 seconds, the circuit enters a half-open state, allowing 2 test calls through. If those succeed, the circuit closes and normal operation resumes. If they fail, the circuit opens again. This pattern is battle-tested in microservices — now it protects your agents too.

Error budgets

Error budgets tie SLOs to business decisions. If your Coordinator Agent's success rate target is 99.5% over a 15-minute window, that means you have an error budget of 0.5%. When the budget is consumed, the toolkit can automatically reduce agent autonomy — for example, requiring human approval for high-risk actions until the error budget recovers.

SRE practices turn agent reliability from a hope into a measurable, enforceable contract.

Architecture

Here's how everything fits together after adding governance:


┌─────────────────────────────────────────────────────────────────┐
│                     Azure App Service                           │
│  ┌──────────────┐    ┌─────────────────────────────────────┐    │
│  │   Frontend   │───▶│           ASP.NET Core API          │    │
│  │   (Static)   │    │                                     │    │
│  └──────────────┘    │  ┌─────────────────────────────┐    │    │
│                      │  │     Coordinator Agent       │    │    │
│                      │  │  ┌───────┐  ┌────────────┐  │    │    │
│                      │  │  │ OTel  │─▶│ Governance │  │    │    │
│                      │  │  └───────┘  │   Engine   │  │    │    │
│                      │  │             │ ┌────────┐ │  │    │    │
│                      │  │             │ │Policies│ │  │    │    │
│                      │  │             │ └────────┘ │  │    │    │
│                      │  │             └─────┬──────┘  │    │    │
│                      │  └───────────────────┼─────────┘    │    │
│                      │  ┌───────────────────┼──────────┐   │    │
│                      │  │  Specialist Agents │         │   │    │
│                      │  │  (Currency, Weather, etc.)   │   │    │
│                      │  │  Each with OTel + Governance │   │    │
│                      │  └───────────────────┼──────────┘   │    │
│                      └──────────────────────┼──────────────┘    │
│                                             │                   │
│  ┌────────────┐  ┌───────────┐  ┌───────────┼─────────┐         │
│  │  Managed   │  │   VNet    │  │ App Insights        │         │
│  │  Identity  │  │Integration│  │ (Traces +           │         │
│  │ (no keys)  │  │(network   │  │  Governance Audit)  │         │
│  │            │  │ boundary) │  │                     │         │
│  └────────────┘  └───────────┘  └─────────────────────┘         │
└──────────────────────────────┬──────────────────────────────────┘
                               │ Only allowed APIs
                               ▼
                    ┌──────────────────────┐
                    │   External APIs      │
                    │  ✅ Frankfurter API  │
                    │  ✅ NWS Weather API  │
                    │  ❌ Everything else  │
                    └──────────────────────┘

The key insight: governance is a transparent layer in the agent pipeline. It sits between the agent's decision and the action's execution. The agent code doesn't know or care about governance — it just builds the agent with .UseGovernance() and the policy engine handles the rest.

Bring it to your own agents

We've shown governance with Microsoft Agent Framework on .NET, but the toolkit is framework-agnostic. Here's how to add it to other popular frameworks:

LangChain (Python)

from agent_governance import PolicyEngine, GovernanceCallbackHandler

policy_engine = PolicyEngine.from_yaml("governance-policies.yaml")

# Add governance as a LangChain callback handler
agent = create_react_agent(
    llm=llm,
    tools=tools,
    callbacks=[GovernanceCallbackHandler(policy_engine)]
)

CrewAI (Python)

from agent_governance import PolicyEngine
from agent_governance.integrations.crewai import GovernanceTaskDecorator

policy_engine = PolicyEngine.from_yaml("governance-policies.yaml")

# Add governance as a CrewAI task decorator
@GovernanceTaskDecorator(policy_engine)
def research_task(agent, context):
    return agent.execute(context)

Google ADK (Python)

from agent_governance import PolicyEngine
from agent_governance.integrations.google_adk import GovernancePlugin

policy_engine = PolicyEngine.from_yaml("governance-policies.yaml")

# Add governance as a Google ADK plugin
agent = Agent(
    model="gemini-2.0-flash",
    tools=[...],
    plugins=[GovernancePlugin(policy_engine)]
)

TypeScript / Node.js

import { PolicyEngine } from '@microsoft/agentmesh-sdk';

const policyEngine = PolicyEngine.fromYaml('governance-policies.yaml');

// Use as middleware in your agent pipeline
agent.use(policyEngine.middleware());

Every integration hooks into the framework's native extension points — callbacks, decorators, plugins, middleware — so adding governance doesn't require rewriting your agent code. Install the package, point it at your policy file, and you're governed.

What's next

This wraps up our three-part series on building production-ready multi-agent AI applications on Azure App Service:

  1. Blog 1: Build — Deploy a multi-agent travel planner with Microsoft Agent Framework 1.0
  2. Blog 2: Monitor — Add observability with OpenTelemetry and the Application Insights Agents view
  3. Blog 3: Govern — Secure agents for production with the Agent Governance Toolkit (you are here)

The progression is intentional: first make it work, then make it visible, then make it safe. And the consistent theme across all three parts is that App Service makes each step easier — managed hosting for Blog 1, integrated monitoring for Blog 2, and platform-level security features for Blog 3.

Next steps for your agents

  • Explore the Agent Governance Toolkit — star the repo, browse the 20 tutorials, try the demo
  • Customize policies for your compliance needs — start with our YAML template and adapt it to your domain. Healthcare teams: enable HIPAA mappings. Finance teams: add SOC2 controls.
  • Explore Agent Mesh for multi-agent trust — if you have agents communicating across services or trust boundaries, Agent Mesh's cryptographic identity and trust scoring add another layer of defense
  • Deploy the sample — clone our travel planner repo, run azd up, and see governed agents in action

AI agents are becoming autonomous decision-makers in high-stakes domains. The question isn't whether we need governance — it's whether we build it proactively, before incidents force our hand. With the Agent Governance Toolkit and Azure App Service, you can add production governance to your agents today. In about 30 minutes.

Published Apr 13, 2026
Version 1.0
No CommentsBe the first to comment