{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.13.0"
    },
    "blog_metadata": {
      "topic": "How Azure Landing Zones Are Evolving for Agentic Workloads",
      "slug": "how-azure-landing-zones-are-evolving-for-agentic-workloads",
      "generated_by": "LinkedIn Post Generator + Azure OpenAI",
      "generated_at": "2026-06-29T15:58:48.320Z"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# How Azure Landing Zones Are Evolving for Agentic Workloads\n",
        "\n",
        "Agentic workloads do not behave like traditional applications. They choose tools, retrieve context, trigger workflows, and act across systems, which means Azure landing zones must evolve from deployment scaffolding into a control plane for runtime autonomy.\n",
        "\n",
        "This notebook turns the blog post into hands-on validation exercises using Python simulations. You will explore policy-aware tool invocation, audit evidence generation, tool registry design, and simple readiness scoring aligned to identity delegation, tool access, data boundaries, and egress control."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "%pip install pandas matplotlib networkx"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from urllib.parse import urlparse\n",
        "from dataclasses import dataclass, asdict\n",
        "from datetime import datetime\n",
        "import pandas as pd\n",
        "import matplotlib.pyplot as plt\n",
        "import networkx as nx\n",
        "import json\n",
        "from typing import Dict, List"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Core idea: the landing zone becomes an active control plane\n",
        "\n",
        "The blog argues that classic landing zones assume static identities, predictable traffic, known dependencies, bounded data paths, and compliance focused on deployed resources. Agentic systems violate those assumptions.\n",
        "\n",
        "This first exercise models the architecture as a graph so you can visualize how networking, governance, runtime, data, and observability all become first-class platform concerns."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "components = {\n",
        "    \"App Team\": {\"type\": \"person\"},\n",
        "    \"Platform/Security Team\": {\"type\": \"person\"},\n",
        "    \"Hub-Spoke Network\": {\"type\": \"platform\"},\n",
        "    \"Governance Plane\": {\"type\": \"platform\"},\n",
        "    \"Agent Runtime\": {\"type\": \"runtime\"},\n",
        "    \"Enterprise Data\": {\"type\": \"data\"},\n",
        "    \"Observability\": {\"type\": \"ops\"},\n",
        "}\n",
        "\n",
        "relationships = [\n",
        "    (\"App Team\", \"Agent Runtime\", \"Deploys agent apps\"),\n",
        "    (\"Platform/Security Team\", \"Governance Plane\", \"Publishes controls\"),\n",
        "    (\"Agent Runtime\", \"Governance Plane\", \"Requests policy decisions\"),\n",
        "    (\"Agent Runtime\", \"Enterprise Data\", \"Reads/writes via private endpoints\"),\n",
        "    (\"Agent Runtime\", \"Observability\", \"Emits logs and traces\"),\n",
        "    (\"Hub-Spoke Network\", \"Agent Runtime\", \"Provides controlled connectivity\"),\n",
        "]\n",
        "\n",
        "G = nx.DiGraph()\n",
        "for node, attrs in components.items():\n",
        "    G.add_node(node, **attrs)\n",
        "for src, dst, label in relationships:\n",
        "    G.add_edge(src, dst, label=label)\n",
        "\n",
        "color_map = {\n",
        "    \"person\": \"#d9eaf7\",\n",
        "    \"platform\": \"#cfe8cf\",\n",
        "    \"runtime\": \"#f9d5a7\",\n",
        "    \"data\": \"#e6d5f7\",\n",
        "    \"ops\": \"#f7c6c7\",\n",
        "}\n",
        "node_colors = [color_map[G.nodes[n][\"type\"]] for n in G.nodes]\n",
        "\n",
        "plt.figure(figsize=(12, 7))\n",
        "pos = nx.spring_layout(G, seed=42)\n",
        "nx.draw(G, pos, with_labels=True, node_color=node_colors, node_size=2800, font_size=9, arrows=True)\n",
        "edge_labels = {(u, v): d[\"label\"] for u, v, d in G.edges(data=True)}\n",
        "nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=8)\n",
        "plt.title(\"Azure Landing Zone Evolution for Agentic Workloads\")\n",
        "plt.axis(\"off\")\n",
        "plt.show()\n",
        "\n",
        "pd.DataFrame(relationships, columns=[\"Source\", \"Target\", \"Relationship\"])"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Policy-aware tool invocation\n",
        "\n",
        "A central theme in the post is that the important question is no longer just whether an app can run, but whether a specific action can happen under policy. This example checks three things at runtime: approved tool, allowed data sensitivity, and approved outbound destination."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from urllib.parse import urlparse\n",
        "\n",
        "POLICY = {\n",
        "    \"allowed_tools\": {\"search_docs\", \"create_ticket\"},\n",
        "    \"max_sensitivity\": \"internal\",\n",
        "    \"approved_hosts\": {\"api.contoso.internal\", \"tickets.contoso.internal\"},\n",
        "}\n",
        "RANK = {\"public\": 0, \"internal\": 1, \"confidential\": 2}\n",
        "\n",
        "def invoke_tool(tool: str, data_sensitivity: str, destination: str) -> str:\n",
        "    host = urlparse(destination).hostname or \"\"\n",
        "    if tool not in POLICY[\"allowed_tools\"]:\n",
        "        return f\"DENY: tool '{tool}' is not approved\"\n",
        "    if RANK[data_sensitivity] > RANK[POLICY[\"max_sensitivity\"]]:\n",
        "        return f\"DENY: sensitivity '{data_sensitivity}' exceeds policy\"\n",
        "    if host not in POLICY[\"approved_hosts\"]:\n",
        "        return f\"DENY: outbound host '{host}' is not approved\"\n",
        "    return f\"ALLOW: executing {tool} against {host}\"\n",
        "\n",
        "print(invoke_tool(\"search_docs\", \"internal\", \"https://api.contoso.internal/query\"))\n",
        "print(invoke_tool(\"send_email\", \"internal\", \"https://api.contoso.internal/query\"))\n",
        "print(invoke_tool(\"create_ticket\", \"confidential\", \"https://tickets.contoso.internal/update\"))\n",
        "print(invoke_tool(\"create_ticket\", \"internal\", \"https://unapproved.example.com/update\"))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Minimal policy decision point with audit evidence\n",
        "\n",
        "The blog emphasizes evidence: who asked, what was attempted, whether it was allowed, and why. This example returns a structured decision record that could be sent to observability systems for review and incident response."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from datetime import datetime\n",
        "\n",
        "\n",
        "def evaluate_request(tool: str, sensitivity: str, host: str) -> dict:\n",
        "    allowed_tools = {\"search_docs\", \"create_ticket\"}\n",
        "    approved_hosts = {\"api.contoso.internal\", \"tickets.contoso.internal\"}\n",
        "    decision = tool in allowed_tools and host in approved_hosts and sensitivity != \"confidential\"\n",
        "    return {\n",
        "        \"timestamp\": datetime.utcnow().isoformat() + \"Z\",\n",
        "        \"tool\": tool,\n",
        "        \"sensitivity\": sensitivity,\n",
        "        \"host\": host,\n",
        "        \"decision\": \"allow\" if decision else \"deny\",\n",
        "        \"reason\": \"policy_passed\" if decision else \"guardrail_violation\",\n",
        "    }\n",
        "\n",
        "result = evaluate_request(\"create_ticket\", \"internal\", \"tickets.contoso.internal\")\n",
        "print(result)\n",
        "\n",
        "scenarios = [\n",
        "    (\"search_docs\", \"public\", \"api.contoso.internal\"),\n",
        "    (\"create_ticket\", \"internal\", \"tickets.contoso.internal\"),\n",
        "    (\"send_email\", \"internal\", \"api.contoso.internal\"),\n",
        "    (\"create_ticket\", \"confidential\", \"tickets.contoso.internal\"),\n",
        "    (\"search_docs\", \"internal\", \"external.example.com\"),\n",
        "]\n",
        "\n",
        "audit_df = pd.DataFrame([evaluate_request(*s) for s in scenarios])\n",
        "audit_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Tool registry pattern for approved implementations\n",
        "\n",
        "The post recommends a tool registry so that approved tools resolve to managed, private-first implementations with known authentication expectations. This reduces the risk of arbitrary endpoints being wired into prompts or orchestration logic."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "from dataclasses import dataclass\n",
        "\n",
        "@dataclass\n",
        "class Tool:\n",
        "    name: str\n",
        "    requires_private_network: bool\n",
        "    auth_mode: str\n",
        "\n",
        "TOOLS = {\n",
        "    \"search_docs\": Tool(\"search_docs\", True, \"managed_identity\"),\n",
        "    \"create_ticket\": Tool(\"create_ticket\", True, \"managed_identity\"),\n",
        "}\n",
        "\n",
        "def resolve_tool(name: str) -> Tool:\n",
        "    tool = TOOLS.get(name)\n",
        "    if not tool:\n",
        "        raise ValueError(f\"Unknown tool: {name}\")\n",
        "    return tool\n",
        "\n",
        "tool = resolve_tool(\"search_docs\")\n",
        "print(tool)\n",
        "\n",
        "registry_df = pd.DataFrame([\n",
        "    {\"tool\": t.name, \"requires_private_network\": t.requires_private_network, \"auth_mode\": t.auth_mode}\n",
        "    for t in TOOLS.values()\n",
        "])\n",
        "registry_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Simulating the runtime decision flow\n",
        "\n",
        "The structured examples also included a flow where a user prompt reaches the agent runtime, then a policy decision point checks tool, sensitivity, and destination before execution. The code below simulates that sequence and records telemetry-style evidence."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "def simulate_agent_request(user_prompt: str, tool: str, sensitivity: str, destination: str) -> dict:\n",
        "    host = urlparse(destination).hostname or \"\"\n",
        "    decision = evaluate_request(tool, sensitivity, host)\n",
        "    outcome = {\n",
        "        \"user_prompt\": user_prompt,\n",
        "        \"tool\": tool,\n",
        "        \"destination\": destination,\n",
        "        \"policy_decision\": decision[\"decision\"],\n",
        "        \"policy_reason\": decision[\"reason\"],\n",
        "        \"executed\": decision[\"decision\"] == \"allow\",\n",
        "        \"telemetry_recorded\": True,\n",
        "    }\n",
        "    if outcome[\"executed\"]:\n",
        "        outcome[\"result\"] = f\"Executed {tool} via managed identity against {host}\"\n",
        "    else:\n",
        "        outcome[\"result\"] = f\"Blocked {tool}; evidence logged\"\n",
        "    return outcome\n",
        "\n",
        "requests = [\n",
        "    (\"Find support article\", \"search_docs\", \"public\", \"https://api.contoso.internal/query\"),\n",
        "    (\"Open a support ticket\", \"create_ticket\", \"internal\", \"https://tickets.contoso.internal/update\"),\n",
        "    (\"Email customer directly\", \"send_email\", \"internal\", \"https://api.contoso.internal/query\"),\n",
        "    (\"Export confidential records\", \"search_docs\", \"confidential\", \"https://api.contoso.internal/query\"),\n",
        "]\n",
        "\n",
        "runtime_df = pd.DataFrame([simulate_agent_request(*r) for r in requests])\n",
        "runtime_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Inventorying likely agent hosts and identity posture\n",
        "\n",
        "The original post included PowerShell to audit managed identities on App Service, Container Apps, AKS, and VM scale sets. In this notebook, we simulate that inventory in Python so you can validate the anti-pattern the author warns about: identities enabled on runtime hosts without clear separation between orchestration rights and tool-execution rights."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "resources = [\n",
        "    {\"Name\": \"agent-web-01\", \"Type\": \"Microsoft.Web/sites\", \"ResourceGroup\": \"rg-agents\", \"IdentityEnabled\": True, \"IdentityType\": \"SystemAssigned\", \"RoleSeparationClear\": False},\n",
        "    {\"Name\": \"agent-ca-01\", \"Type\": \"Microsoft.App/containerApps\", \"ResourceGroup\": \"rg-agents\", \"IdentityEnabled\": True, \"IdentityType\": \"UserAssigned\", \"RoleSeparationClear\": True},\n",
        "    {\"Name\": \"agent-aks-01\", \"Type\": \"Microsoft.ContainerService/managedClusters\", \"ResourceGroup\": \"rg-platform\", \"IdentityEnabled\": True, \"IdentityType\": \"SystemAssigned\", \"RoleSeparationClear\": False},\n",
        "    {\"Name\": \"batch-vmss-01\", \"Type\": \"Microsoft.Compute/virtualMachineScaleSets\", \"ResourceGroup\": \"rg-batch\", \"IdentityEnabled\": False, \"IdentityType\": \"None\", \"RoleSeparationClear\": False},\n",
        "]\n",
        "\n",
        "identity_df = pd.DataFrame(resources)\n",
        "identity_df[\"PotentialAntiPattern\"] = identity_df[\"IdentityEnabled\"] & (~identity_df[\"RoleSeparationClear\"])\n",
        "identity_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Checking private connectivity posture for AI-related services\n",
        "\n",
        "The blog also recommends validating private connectivity instead of assuming it exists. This Python version simulates an inventory for AI-related services and highlights which resources do or do not have private endpoint coverage."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "ai_services = [\n",
        "    {\"Name\": \"aoai-prod\", \"Type\": \"Microsoft.CognitiveServices/accounts\", \"ResourceGroup\": \"rg-ai\", \"PrivateEndpointCount\": 1},\n",
        "    {\"Name\": \"mlw-prod\", \"Type\": \"Microsoft.MachineLearningServices/workspaces\", \"ResourceGroup\": \"rg-ml\", \"PrivateEndpointCount\": 2},\n",
        "    {\"Name\": \"search-prod\", \"Type\": \"Microsoft.Search/searchServices\", \"ResourceGroup\": \"rg-search\", \"PrivateEndpointCount\": 0},\n",
        "]\n",
        "\n",
        "pe_df = pd.DataFrame(ai_services)\n",
        "pe_df[\"HasPrivateConnectivity\"] = pe_df[\"PrivateEndpointCount\"] > 0\n",
        "pe_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Listing policy assignments relevant to agentic guardrails\n",
        "\n",
        "Another structured example focused on policy assignments for private endpoints, managed identity, public network access, and diagnostics. Here we simulate a policy inventory and filter for assignments that matter most to agentic workloads."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "policy_assignments = [\n",
        "    {\"Name\": \"deny-public-network\", \"Scope\": \"/providers/Microsoft.Management/managementGroups/platform\", \"DisplayName\": \"Deny public network access\", \"Description\": \"Blocks public network access on supported services\", \"Enforcement\": \"Default\"},\n",
        "    {\"Name\": \"require-diagnostics\", \"Scope\": \"/providers/Microsoft.Management/managementGroups/platform\", \"DisplayName\": \"Require diagnostic settings\", \"Description\": \"Ensures logs are sent to central workspace\", \"Enforcement\": \"Default\"},\n",
        "    {\"Name\": \"managed-identity-required\", \"Scope\": \"/providers/Microsoft.Management/managementGroups/apps\", \"DisplayName\": \"Managed identity required for app hosts\", \"Description\": \"Requires managed identity on supported compute\", \"Enforcement\": \"Default\"},\n",
        "    {\"Name\": \"allowed-locations\", \"Scope\": \"/providers/Microsoft.Management/managementGroups/root\", \"DisplayName\": \"Allowed locations\", \"Description\": \"Restricts deployment regions\", \"Enforcement\": \"Default\"},\n",
        "    {\"Name\": \"private-endpoint-preferred\", \"Scope\": \"/providers/Microsoft.Management/managementGroups/ai\", \"DisplayName\": \"Private endpoint required for AI services\", \"Description\": \"Requires private endpoint connectivity for AI-related services\", \"Enforcement\": \"DoNotEnforce\"},\n",
        "]\n",
        "\n",
        "keywords = [\"private endpoint\", \"managed identity\", \"allowed locations\", \"public network access\", \"diagnostic\"]\n",
        "filtered = []\n",
        "for p in policy_assignments:\n",
        "    text = (p[\"DisplayName\"] + \" \" + p[\"Description\"]).lower()\n",
        "    if any(k in text for k in keywords):\n",
        "        filtered.append(p)\n",
        "\n",
        "policy_df = pd.DataFrame(filtered)\n",
        "policy_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Data boundaries and evidence trails\n",
        "\n",
        "The post makes a strong claim: in enterprise AI, the biggest risk is often not the model endpoint but retrieval, grounding, memory, logs, and output handling. This exercise creates a simple inventory of AI data domains so you can reason about segmentation by sensitivity and ownership."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "data_domains = [\n",
        "    {\"Domain\": \"vector_store\", \"Sensitivity\": \"internal\", \"Owner\": \"Search Team\", \"Subscription\": \"sub-ai-data\", \"PrivateAccess\": True},\n",
        "    {\"Domain\": \"conversation_state\", \"Sensitivity\": \"confidential\", \"Owner\": \"App Team\", \"Subscription\": \"sub-agent-runtime\", \"PrivateAccess\": True},\n",
        "    {\"Domain\": \"logs_and_traces\", \"Sensitivity\": \"internal\", \"Owner\": \"Platform Ops\", \"Subscription\": \"sub-observability\", \"PrivateAccess\": True},\n",
        "    {\"Domain\": \"business_system_data\", \"Sensitivity\": \"confidential\", \"Owner\": \"ERP Team\", \"Subscription\": \"sub-business-data\", \"PrivateAccess\": True},\n",
        "    {\"Domain\": \"evaluation_datasets\", \"Sensitivity\": \"internal\", \"Owner\": \"AI Engineering\", \"Subscription\": \"sub-ai-experiments\", \"PrivateAccess\": False},\n",
        "]\n",
        "\n",
        "data_df = pd.DataFrame(data_domains)\n",
        "data_df[\"SegmentationRisk\"] = (~data_df[\"PrivateAccess\"]) | (data_df[\"Sensitivity\"] == \"confidential\")\n",
        "data_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Readiness scoring across the four weakest-control categories\n",
        "\n",
        "The article ends with a practical challenge: rate readiness from 1 to 5 and name the weakest control among identity delegation, tool access, data boundaries, or egress. The code below provides a simple scoring model you can adjust for your environment."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "readiness = {\n",
        "    \"identity_delegation\": 2,\n",
        "    \"tool_access\": 3,\n",
        "    \"data_boundaries\": 4,\n",
        "    \"egress_control\": 2,\n",
        "}\n",
        "\n",
        "readiness_df = pd.DataFrame(\n",
        "    [{\"control\": k, \"score\": v} for k, v in readiness.items()]\n",
        ").sort_values(\"score\")\n",
        "\n",
        "weakest = readiness_df.iloc[0][\"control\"]\n",
        "overall = readiness_df[\"score\"].mean()\n",
        "\n",
        "print(f\"Overall readiness score: {overall:.2f} / 5\")\n",
        "print(f\"Weakest control: {weakest}\")\n",
        "readiness_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "plt.figure(figsize=(8, 4))\n",
        "plt.bar(readiness_df[\"control\"], readiness_df[\"score\"], color=[\"#d9534f\", \"#f0ad4e\", \"#5bc0de\", \"#5cb85c\"])\n",
        "plt.ylim(0, 5)\n",
        "plt.ylabel(\"Score\")\n",
        "plt.title(\"Agentic Landing Zone Readiness\")\n",
        "plt.xticks(rotation=20)\n",
        "plt.show()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Summary\n",
        "\n",
        "Azure landing zones for agentic workloads must govern runtime action, not just deployment posture. The practical control surface is identity delegation, tool access, data boundaries, egress control, and evidence-rich policy enforcement.\n",
        "\n",
        "## Next Steps\n",
        "\n",
        "1. Inventory likely agent runtimes and verify identity separation between orchestration and tool execution.\n",
        "2. Build or refine a central tool registry with private-first implementations and explicit auth modes.\n",
        "3. Validate private connectivity for AI services, data stores, and tool endpoints.\n",
        "4. Review policy assignments for public network access, diagnostics, managed identity, and private endpoints.\n",
        "5. Score your environment from 1 to 5 and prioritize the weakest control domain for remediation."
      ]
    }
  ]
}