Semantic Kernel runtime authorization
Wrap Microsoft Semantic Kernel plugins and kernel functions with Veto. Each governed function invocation is evaluated before dispatch: allow, review, or deny, with an exportable decision record per governed decision.
Why Semantic Kernel needs guardrails
Microsoft Semantic Kernel exposes plugin functions to a model. When the kernel is configured with FunctionChoiceBehavior.Auto, the model autonomously selects functions and supplies arguments. The kernel executes them. The function attribute, parameter types, and description do not encode enforcement policy: they only describe shape.
Enterprise Semantic Kernel deployments often expose operations-grade plugins: kubectl, internal incident management, database admin. The kernel's automatic function-calling loop can compose a destructive sequence if a prompt injection steers it. Enforcement at the kernel function boundary is the reliable way to stop the side effect deterministically.
The kernel's auto behavior invokes plugin functions without a guardrail step. The model decides; the kernel runs.
Common Semantic Kernel plugins wrap kubectl, Azure CLI, and internal admin APIs. One destructive call costs uptime.
Application Insights captures telemetry. Veto adds the decision record enterprises need for SOC 2.
Before and after Veto
The left tab shows a standard Semantic Kernel plugin with three kernel functions. The right tab adds Veto inside each function. Same kernel, same plugin, each governed call evaluated against policy first.
import os
from semantic_kernel import Kernel
from semantic_kernel.functions import kernel_function
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
class IncidentPlugin:
@kernel_function(description="Page the on-call engineer")
def page_oncall(self, severity: str, message: str) -> str:
return pagerduty.create_incident(severity=severity, summary=message)
@kernel_function(description="Restart a production service")
def restart_service(self, service_name: str, region: str) -> str:
return k8s.rollout_restart(service_name, region)
@kernel_function(description="Run a kubectl command")
def kubectl(self, command: str) -> str:
return shell.run(f"kubectl {command}")
kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(ai_model_id=os.environ["OPENAI_MODEL"]))
kernel.add_plugin(IncidentPlugin(), plugin_name="incidents")
settings = kernel.get_prompt_execution_settings_from_service_id("default")
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
# The model picks kubectl with command="delete deployment payments".
# Semantic Kernel calls the function. The deployment is gone.
result = await kernel.invoke_prompt(prompt=user_request, settings=settings)Kernel-wide filters
Semantic Kernel exposes a filter API that wraps every function invocation. Register one Veto filter and every plugin in the kernel is guarded: no per-function edits required.
import os
from semantic_kernel.filters import FunctionInvocationContext, FilterTypes
from semantic_kernel import Kernel
from veto_sdk import Veto
veto = Veto(api_key=os.environ["VETO_API_KEY"])
kernel = Kernel()
@kernel.filter(FilterTypes.FUNCTION_INVOCATION)
async def veto_filter(context: FunctionInvocationContext, next):
arguments = {k: v for k, v in context.arguments.items()}
decision = veto.guard(
tool=context.function.fully_qualified_name,
arguments=arguments,
context={"plugin": context.function.plugin_name},
)
if decision.decision == "deny":
context.result = f"Blocked by policy: {decision.reason}"
return
if decision.decision == "require_approval":
context.result = f"Awaiting approval (ID: {decision.approval_id})"
return
await next(context)
# Filters can wrap kernel function calls before dispatch.
# Plugins do not need per-function Veto code when using a filter.Policy configuration
Author policies in declarative YAML. Match on the fully qualified function name (plugin.function) when using a kernel-wide filter, or on the unqualified function name when guarding inside the function body.
rules:
- name: protect_production_restarts
description: Production restarts need an SRE approval
tool: restart_service
when: context.environment == "production"
action: require_approval
approvers: [sre-oncall]
timeout: 15m
- name: block_destructive_kubectl
description: Forbid delete and exec commands
tool: kubectl
when: "args.command.match(/^(delete|exec|patch|edit)\\b/)"
action: deny
message: "Destructive kubectl verbs require a human operator"
- name: rate_limit_oncall_pages
description: At most 5 on-call pages per hour
tool: page_oncall
when: context.hourly_pages >= 5
action: deny
message: "Page rate limit reached for this hour"
- name: severity_allowlist
description: Severity must be sev1-sev4
tool: page_oncall
when: "!['sev1', 'sev2', 'sev3', 'sev4'].includes(args.severity)"
action: deny
message: "Invalid severity: must be sev1, sev2, sev3, or sev4"How Veto fits
Install the SDK
pip install veto-sdk semantic-kernelDefine policies
Create veto/policies.yaml. Match on the kernel function name. Set actions per plugin or per environment.
Guard with a filter or per-function
Register a kernel filter for blanket coverage, or call veto.guard() inside individual kernel functions for fine-grained control.
Use cases
SRE incident assistant
Kernel plugin that pages on-call and triggers runbooks. Rate-limit pages per hour, block destructive kubectl verbs, require approval before any production rollout-restart.
Microsoft 365 copilot extensions
Custom plugins that read mail and create Teams channels. Restrict recipient domains, block channels with external members, log each governed action with the user's identity.
Azure resource management
Plugins that wrap Azure CLI. Restrict to specific subscriptions, block resource deletion, require change approval for scaling decisions in prod.
Enterprise decision record
Veto emits a decision record for each governed kernel function call. Exportable to your SIEM. Pairs with Microsoft Purview for compliance evidence.
Frequently asked questions
Does Veto work with Semantic Kernel filters?
Does this work with the .NET and Java versions of Semantic Kernel?
Does Veto interact with Semantic Kernel's planner?
Can I share policies between Semantic Kernel and other frameworks?
Related integrations
Wrap one Semantic Kernel plugin path and inspect the decision record.