{"id":29436,"date":"2026-05-29T08:36:26","date_gmt":"2026-05-29T06:36:26","guid":{"rendered":"https:\/\/whiteduck.de\/flock-v0-5-500-enterprise-security-for-agentic-ai\/"},"modified":"2026-09-29T14:48:44","modified_gmt":"2026-09-29T12:48:44","slug":"flock-v0-5-500-enterprise-security-for-agentic-ai","status":"publish","type":"post","link":"https:\/\/whiteduck.de\/en\/flock-v0-5-500-enterprise-security-for-agentic-ai\/","title":{"rendered":"Flock v0.5.500: Enterprise Security for Agentic AI"},"content":{"rendered":"<p>AI agents are moving into production. And with that move comes a set of questions that no one asks during a prototype: How do we authenticate without hardcoding API keys? How do we prevent prompt injection from compromising agent behavior? How do we make security a first-class concern, not an afterthought?   <\/p>\n<p>Flock 0.5.500 answers all three. This release introduces two foundational security features that make it significantly easier to build and operate AI agents in enterprise environments: keyless authentication via Azure Entra ID and Managed Identity, and a pluggable guard framework to protect agents from malicious inputs. <\/p>\n<h2>Keyless Authentication with Azure Entra ID and Managed Identity<\/h2>\n<h3>The Problem with API Keys<\/h3>\n<p>Most LLM frameworks require an API key to communicate with Azure OpenAI. That key ends up in environment variables, CI\/CD pipelines, container specs, and developers\u2019 machines. It needs to be rotated, audited, and kept out of source control. In practice, that rarely happens.   <\/p>\n<p>In Azure-native workloads, there is a better way: <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/managed-identities-azure-resources\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">Managed Identity<\/a>. A workload running on Azure Container Apps, AKS, or Azure Functions can authenticate to Azure OpenAI directly, with no secrets involved. Azure handles the credential lifecycle. You handle the business logic.   <\/p>\n<p>Flock 0.5.500 makes this the default path for Azure deployments. Authentication works across Azure OpenAI and Azure AI Foundry. <\/p>\n<h3>How It Works<\/h3>\n<p>A new <code>lm_kwargs<\/code> field on <code>DSPyEngine<\/code> forwards arbitrary keyword arguments to the underlying <a href=\"https:\/\/docs.litellm.ai\/\" target=\"_blank\" rel=\"noreferrer noopener\">LiteLLM<\/a> constructor. This is a provider-agnostic mechanism: any LiteLLM parameter can be passed through. For Azure, a dedicated helper wraps    <a href=\"https:\/\/learn.microsoft.com\/en-us\/python\/api\/azure-identity\/azure.identity.defaultazurecredential\" target=\"_blank\" rel=\"noreferrer noopener\"><code>DefaultAzureCredential<\/code><\/a>  into a token provider callable that LiteLLM understands.<\/p>\n<p>The result is clean, keyless configuration:<\/p>\n<pre><code>from flock.engines import DSPyEngine\nfrom flock.engines.auth.azure import get_default_azure_token_provider\n\ntoken_provider = get_default_azure_token_provider()\n\nengine = DSPyEngine(lm_kwargs={\n    \"api_base\": \"https:\/\/<resource>.openai.azure.com\/\",\n    \"api_version\": \"2024-12-01-preview\",\n    \"azure_ad_token_provider\": token_provider,\n})<\/resource><\/code><\/pre>\n<p><code>DefaultAzureCredential<\/code>  resolves the correct credential automatically: Managed Identity when running on Azure, <code>az login<\/code> during local development. No code changes are required between environments. <\/p>\n<p>For workloads using a user-assigned Managed Identity, pass the client ID:<\/p>\n<pre><code>token_provider = get_default_azure_token_provider(\n    managed_identity_client_id=\"<client-id>\"\n)<\/client-id><\/code><\/pre>\n<p>The Azure AI Foundry Agents API requires a different token scope. That is covered as well: <\/p>\n<pre><code>from flock.engines.auth.azure import (\n    get_default_azure_token_provider,\n    AZURE_AI_FOUNDRY_SCOPE,\n)\n\ntoken_provider = get_default_azure_token_provider(scopes=AZURE_AI_FOUNDRY_SCOPE)<\/code><\/pre>\n<h3>Getting Started<\/h3>\n<p>Azure identity support ships as an optional dependency to keep the core package lean. It pulls in   <a href=\"https:\/\/pypi.org\/project\/azure-identity\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>azure-identity<\/code><\/a>, Microsoft\u2019s official Python credential library:<\/p>\n<pre><code>uv add \"flock[azure]\"<\/code><\/pre>\n<p>That\u2019s it. No secrets. No rotation. No exposure.   <\/p>\n<h2>GuardComponent: Pluggable Input and Output Protection<\/h2>\n<h3>The Prompt Injection Problem<\/h3>\n<p>Agentic systems are different from chatbots. They process external data (documents, web content, API responses, user inputs) and act on it. That external data is an attack surface. A malicious PDF can contain instructions that redirect agent behavior. A crafted user message can attempt to jailbreak the underlying model. <a href=\"https:\/\/owasp.org\/www-project-top-10-for-large-language-model-applications\/\" target=\"_blank\" rel=\"noreferrer noopener\">Prompt injection<\/a> consistently ranks as one of the top risks in production LLM applications.    <\/p>\n<p>Without explicit protection, there is no reliable way to detect these attacks before they influence what an agent does.<\/p>\n<p>Flock 0.5.500 introduces a guard framework that makes protection composable and configurable, rather than bolted on as an afterthought.<\/p>\n<h3>How It Works<\/h3>\n<p><code>GuardComponent<\/code>  is an abstract base class that integrates into Flock\u2019s existing agent lifecycle. Guards execute during <code>on_pre_evaluate<\/code> (before the model sees the input) and <code>on_post_evaluate<\/code> (after the model produces output). No new architectural patterns are needed: guards are simply components with a well-defined interface.  <\/p>\n<p>Each guard returns a <code>GuardVerdict<\/code> with four fields: <code>safe<\/code>, <code>reason<\/code>, <code>details<\/code>, and <code>provider<\/code>. This provides full auditability: every decision is traceable. <\/p>\n<p>Three actions can be configured per phase:<\/p>\n<ul>\n<li><code>block<\/code>: raises <code>GuardBlockedError<\/code> and halts execution<\/li>\n<li><code>warn<\/code>: logs the finding and continues<\/li>\n<li><code>annotate<\/code>: attaches the verdict to the agent\u2019s context<\/li>\n<\/ul>\n<p>Guards compose naturally. Assign priorities to control execution order. A block in any guard stops subsequent components and the engine run.  <\/p>\n<h3>Azure Prompt Shield: The First Built-in Guard<\/h3>\n<p>The first built-in implementation calls the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/ai-services\/content-safety\/concepts\/jailbreak-detection\" target=\"_blank\" rel=\"noreferrer noopener\">Azure AI Content Safety Prompt Shields<\/a> API. It detects two classes of attacks: direct jailbreak attempts in user prompts, and indirect prompt injection embedded in context documents. <\/p>\n<p>Both Managed Identity and API key authentication are supported. Document content is extracted automatically from Flock\u2019s artifact types, with configurable truncation for large documents. <\/p>\n<pre><code>from flock.components.agent.azure_prompt_shield import (\n    AzurePromptShieldGuard,\n    AzurePromptShieldConfig,\n)\nfrom flock.core import Agent\nfrom flock.engines import DSPyEngine\n\nagent = Agent(\n    name=\"support_agent\",\n    engine=DSPyEngine(model=\"azure\/gpt-4.1\"),\n    components=[\n        AzurePromptShieldGuard(\n            priority=-10,  # run before all other components\n            config=AzurePromptShieldConfig(\n                endpoint=\"https:\/\/<resource>.cognitiveservices.azure.com\",\n                on_input_flagged=\"block\",\n                scan_context_artifacts=True,  # scan documents passed as context\n            ),\n        ),\n    ],\n)<\/resource><\/code><\/pre>\n<p>Setting <code>priority=-10<\/code> ensures the guard runs before any other component. If the input is flagged, a <code>GuardBlockedError<\/code> is raised immediately, and the model never sees the malicious content. <\/p>\n<h3>Building Custom Guards<\/h3>\n<p>The framework is designed to be extended. Implement <code>scan_input<\/code> and optionally <code>scan_output<\/code>, and the base class handles the rest: lifecycle wiring, artifact extraction, verdict routing, and action dispatch. <\/p>\n<pre><code>from flock.components.agent.guard import GuardComponent, GuardVerdict\n\nclass MyCustomGuard(GuardComponent):\n    async def scan_input(self, text: str, documents: list[str]) -&gt; GuardVerdict:\n        flagged = await my_policy_check(text)\n        return GuardVerdict(\n            safe=not flagged,\n            reason=\"Custom policy violation\" if flagged else None,\n            provider=\"my-guard\",\n        )<\/code><\/pre>\n<p>Multiple guards with different backends can run on the same agent. Combine Azure Prompt Shield with a domain-specific policy check, for example. Priority ordering guarantees a deterministic execution sequence.  <\/p>\n<p>The <code>GuardComponent<\/code> interface is also a natural integration point for broader policy enforcement tooling. Microsoft\u2019s <a href=\"https:\/\/github.com\/microsoft\/agent-governance-toolkit\" target=\"_blank\" rel=\"noreferrer noopener\">Agent Governance Toolkit<\/a> covers policy enforcement, zero-trust identity, and audit logging across the full OWASP Agentic Top 10. A custom guard wrapping its <code>PolicyEvaluator<\/code> can bring those deterministic controls directly into the Flock agent lifecycle, putting content safety (Prompt Shield) and tool-call governance in the same execution pipeline with no changes to the agent itself. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>AI agents are moving into production. And with that move  [&#8230;]<\/p>\n","protected":false},"author":6,"featured_media":29345,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_tribe_events_control_status":"","_tribe_events_control_status_canceled_reason":"","_tribe_events_control_status_postponed_reason":"","_tribe_events_control_online":"","_tribe_events_control_online_url":"","footnotes":""},"categories":[598],"tags":[644,586,854,612,659,718,662],"class_list":["post-29436","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-2","tag-agentic-ai-2","tag-ai-2","tag-ai-3","tag-flock-2","tag-open-source-2","tag-security-2","tag-sovereignty-3"],"acf":[],"_links":{"self":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/29436","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/comments?post=29436"}],"version-history":[{"count":0,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/29436\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media\/29345"}],"wp:attachment":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media?parent=29436"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/categories?post=29436"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/tags?post=29436"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}