<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>Azure Infrastructure Blog articles</title>
    <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/bg-p/AzureInfrastructureBlog</link>
    <description>Azure Infrastructure Blog articles</description>
    <pubDate>Mon, 01 Jun 2026 10:52:14 GMT</pubDate>
    <dc:creator>AzureInfrastructureBlog</dc:creator>
    <dc:date>2026-06-01T10:52:14Z</dc:date>
    <item>
      <title>Golden Image Refresh for Virtual Machines and VM Scale Sets: Driving Consistency at Scale</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/golden-image-refresh-for-virtual-machines-and-vm-scale-sets/ba-p/4521376</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Overview:&lt;BR /&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A&amp;nbsp;&lt;STRONG&gt;golden image&lt;/STRONG&gt; is a prebuilt, approved system template that represents the ideal baseline for deployment. It includes:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Hardened operating system configuration (e.g., RHEL)&lt;/LI&gt;
&lt;LI&gt;Preinstalled software and dependencies&lt;/LI&gt;
&lt;LI&gt;Security patches and updates&lt;/LI&gt;
&lt;LI&gt;Organizational compliance standards&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Architecture:&lt;/STRONG&gt;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&lt;SPAN data-teams="true"&gt;&lt;STRONG&gt;Golden Image Refresh for VM Scale Sets (VMSS):&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;Instead of updating instances individually:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A &lt;STRONG&gt;new image version is published&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;The VMSS is updated to reference the new image&lt;/LI&gt;
&lt;LI&gt;Instances are gradually replaced through a controlled rollout&lt;/LI&gt;
&lt;LI&gt;New instances (based on updated image) are introduced&lt;/LI&gt;
&lt;LI&gt;Traffic is gradually shifted to these new instances&lt;/LI&gt;
&lt;LI&gt;Old instances are decommissioned in phases&lt;/LI&gt;
&lt;LI&gt;Minimizes service disruption&lt;/LI&gt;
&lt;LI&gt;Enables safe rollout of updated environments&lt;/LI&gt;
&lt;LI&gt;Allows real-time validation of new image versions&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Virtual Machine Scale Set (VMSS) deployments use a&amp;nbsp;&lt;STRONG&gt;custom image&lt;/STRONG&gt; that is baked on top of a &lt;STRONG&gt;Golden Image&lt;/STRONG&gt;.&lt;BR /&gt;The Golden Image version is pinned in the environment-specific &lt;STRONG&gt;Packer variables (&lt;/STRONG&gt;&lt;STRONG&gt;pkrvariables&lt;/STRONG&gt;&lt;STRONG&gt;) files&lt;/STRONG&gt;.&lt;BR /&gt;Refreshing a VMSS Golden Image involves baking a new custom image using an updated Golden Image version and deploying it via the VMSS pipelines.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Image Dependency Flow&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Golden Image&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;Published and versioned by the Golden Image Team.&lt;/LI&gt;
&lt;LI&gt;Source OS image, pinned in pkrvariables per environment.&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Custom Image&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;Created by the &lt;STRONG&gt;custom image pipeline&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Built on top of the pinned Golden Image.&lt;/LI&gt;
&lt;LI&gt;Used by VMSS deployments.&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;VMSS Deployment&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;Deploys or updates scale sets using the selected custom image version.&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;STRONG&gt;Golden Image Version Management (VMSS)&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Each environment pins the Golden Image version in its respective pkrvariables file.&lt;/LI&gt;
&lt;LI&gt;Golden Image versions are selected from the same Golden Image Galleries:
&lt;UL&gt;
&lt;LI&gt;Dev&lt;/LI&gt;
&lt;LI&gt;PPR&lt;/LI&gt;
&lt;LI&gt;Prod&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;No automatic upgrades occur; changes are explicit and controlled via Git.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;VMSS Golden Image Refresh Procedure&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1.Select Golden Image Version&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Navigate to the appropriate &lt;STRONG&gt;Golden Image Gallery&lt;/STRONG&gt; for the target environment.&lt;/LI&gt;
&lt;LI&gt;Identify the Golden Image version to be used for the refresh.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;2. Update Packer Variables&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Create a &lt;STRONG&gt;feature branch&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;Update the pinned Golden Image version in the environment-specific pkrvariables file.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;3.Merge Changes&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Raise a &lt;STRONG&gt;Merge Request (MR)&lt;/STRONG&gt; for the updated version.&lt;/LI&gt;
&lt;LI&gt;After approval, merge the MR into the target branch.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Custom Image Creation&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Trigger the &lt;STRONG&gt;custom image pipeline&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;LI&gt;This pipeline:
&lt;UL&gt;
&lt;LI&gt;Uses the updated Golden Image version&lt;/LI&gt;
&lt;LI&gt;Bakes a &lt;STRONG&gt;new custom image&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Publishes a new custom image version for VMSS consumption&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;VMSS Deployment&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Once the custom image is successfully created, deploy it using one of the following approaches:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Option 1: Operational Pipeline&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Use the&amp;nbsp;&lt;STRONG&gt;operational pipeline&lt;/STRONG&gt; to deploy the newly created custom image to the VMSS. Operational Pipeline is separate pipeline which will refresh the image.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;option 2: Infrastructure Pipeline Update&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Update the infrastructure (Terraform) pipeline code with the new custom image version.&lt;/LI&gt;
&lt;LI&gt;Run:
&lt;UL&gt;
&lt;LI&gt;terraform plan to review VMSS updates&lt;/LI&gt;
&lt;LI&gt;terraform apply to roll out the new image&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Terraform Behavior&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;VMSS instances are updated to use the newly created custom image.&lt;/LI&gt;
&lt;LI&gt;The same remote Terraform backend is used to preserve state consistency.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Validation and Verification&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After deployment:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Validate VMSS instance health&lt;/LI&gt;
&lt;LI&gt;Confirm successful instance provisioning&lt;/LI&gt;
&lt;LI&gt;Verify application and service functionality&lt;/LI&gt;
&lt;LI&gt;Monitor scale set upgrade status and error metrics&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Image Team will provide the golden image and then we need to create custom image.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After retrieval of Custom image used in Infra code.&lt;/P&gt;
&lt;P&gt;The Golden image refresh in infra code, requires a activity which is called upgrade and there are 2 kinds of upgrade in VMSS :&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Automatic upgrade -&amp;nbsp;&lt;/STRONG&gt;VMSS instances will upgrade automatically, and this requires downtime.&lt;/P&gt;
&lt;P&gt;All VMSS instances will start upgrading simultaneously and application will be down till VMSS instances is up and running.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Manual upgrade -&amp;nbsp;&lt;/STRONG&gt;VMSS instances need to be manually upgraded, and this requires 10 - 15 minutes of degradation.&lt;/P&gt;
&lt;P&gt;As part of this Upgrade - we need to manually upgrade VMSS instance one by one and so other instances will be up. There will be no downtime for the application.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bydefault VMSS will consider automatic upgrade which requires downtime. If we do not require Automatic upgrade then we need to change the setting in provider like below.&lt;/P&gt;
&lt;P&gt;provider "azurerm" {&lt;BR /&gt;&amp;nbsp; features {&lt;BR /&gt;&lt;STRONG&gt;virtual_machine_scale_set {&lt;/STRONG&gt;&lt;BR /&gt;&lt;STRONG&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; reimage_on_manual_upgrade &amp;nbsp; &amp;nbsp;= false&lt;/STRONG&gt;&lt;BR /&gt;&lt;STRONG&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; roll_instances_when_required = false&lt;/STRONG&gt;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; }&lt;BR /&gt;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;After updating above code in provider.tf as part of manual upgrade then update the terraform code for new golden image.&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Create a New Image: Start by creating a new golden image with the latest updates and configurations using YAML pipeline.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;Update Terraform Configuration: Modify your Terraform configuration to reference the new image. This involves updating the source_image_id or image_reference in your azurerm_virtual_machine_scale_set resource to point to the new image version.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Example:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;source_image_id = "/subscriptions/subscriptionid/resourceGroups/rgname/providers/Microsoft.Compute/images/confluence-prd-v-24052450"&lt;/STRONG&gt;&lt;BR /&gt;&lt;BR /&gt;data_disks = [&lt;BR /&gt;&amp;nbsp; &amp;nbsp; {&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; storage_account_type &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = "Premium_LRS"&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; caching &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= "ReadWrite"&lt;BR /&gt;&lt;STRONG&gt; create_option &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= "FromImage"&lt;/STRONG&gt;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; lun &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= 0&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; disk_size_gb &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = "500"&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; disk_encryption_set_id &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = null&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ultra_ssd_disk_iops_read_write = null&lt;BR /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ultra_ssd_disk_mbps_read_write = null&lt;BR /&gt;&amp;nbsp; &amp;nbsp; }&lt;BR /&gt;&amp;nbsp; ]&lt;BR /&gt;instances = 3&amp;nbsp;&lt;BR /&gt;automatic_instance_repair = [{&lt;BR /&gt;&amp;nbsp; &amp;nbsp; enabled &amp;nbsp; &amp;nbsp; &amp;nbsp;= false&lt;BR /&gt;&amp;nbsp; &amp;nbsp; grace_period = "PT30M"&lt;BR /&gt;&amp;nbsp; }]&lt;BR /&gt;computer_name_prefix &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = "Appname-prd"&lt;BR /&gt;overprovision &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= false&lt;BR /&gt;edge_zone &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= null&lt;BR /&gt;health_probe_id &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= null&lt;BR /&gt;&lt;STRONG&gt;upgrade_mode &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = "Manual"&lt;/STRONG&gt;&lt;BR /&gt;single_placement_group &amp;nbsp; &amp;nbsp; &amp;nbsp; = true&lt;BR /&gt;secure_boot_enabled &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= false&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;Apply Terraform Configuration: Run terraform apply to apply the updated configuration. This will update the scale set to use the new image.&lt;/P&gt;
&lt;P&gt;After the Apply - Upgrade type is Manual then upgrade the VMSS instances one by one to make the service up and running.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-teams="true"&gt;Golden Image Refresh for VM Scale Sets (VM)&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-teams="true"&gt;Scope&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Linux VMs:
&lt;UL&gt;
&lt;LI&gt;VMs use&amp;nbsp;&lt;STRONG&gt;RHEL 7.9&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;VMs use&amp;nbsp;&lt;STRONG&gt;RHEL 8.10&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;For RHEL 7.9 , there is no golden image hence needs to create custom image. To refresh the image, change the image from (example from 1.0 to 1.1)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Resource Changes (VMTRF):&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;VM: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt; (source_image_id changed)&lt;/LI&gt;
&lt;LI&gt;OS disk: azapi_update_resource.disk ⇒ &lt;STRONG&gt;replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Data disk attachments: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Network interface: &lt;STRONG&gt;updated in-place&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Disk encryption set: &lt;STRONG&gt;updated in-place&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Role assignments: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;VM extension (Custom Script Extension): &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;RHEL 8.10&lt;/P&gt;
&lt;P&gt;To refresh the image, change the image from (example from 1.0 to 1.1)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Resource Changes (VM STD):&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;VM: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt; (source_image_id changed)&lt;/LI&gt;
&lt;LI&gt;OS disk: azapi_update_resource.disk ⇒ &lt;STRONG&gt;replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Data disk attachments: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Network interface: &lt;STRONG&gt;updated in-place&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Disk encryption set: &lt;STRONG&gt;updated in-place&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Role assignments: &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;VM extension (Custom Script): &lt;STRONG&gt;will be replaced&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;</description>
      <pubDate>Wed, 20 May 2026 02:56:39 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/golden-image-refresh-for-virtual-machines-and-vm-scale-sets/ba-p/4521376</guid>
      <dc:creator>ranjsharma</dc:creator>
      <dc:date>2026-05-20T02:56:39Z</dc:date>
    </item>
    <item>
      <title>Building AI Guardian Extension: AI Detection and Enterprise AI Security</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-ai-guardian-extension-ai-detection-and-enterprise-ai/ba-p/4521125</link>
      <description>&lt;H2&gt;&lt;STRONG&gt;Introduction&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Generative AI tools such as &lt;STRONG&gt;ChatGPT, GitHub Copilot, and Google Gemini&lt;/STRONG&gt; are rapidly becoming part of everyday enterprise workflows. Teams use them for code generation, documentation, analysis, support automation, and productivity enhancement.&lt;/P&gt;
&lt;P&gt;However, this accelerated adoption has also created a significant governance and security challenge: &lt;STRONG&gt;Shadow AI&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;Shadow AI refers to the &lt;STRONG&gt;unauthorized, unmanaged, or unmonitored use of AI tools inside an organization&lt;/STRONG&gt;. Employees may unknowingly paste sensitive enterprise information into external AI platforms, exposing:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;API keys&lt;/LI&gt;
&lt;LI&gt;Source code&lt;/LI&gt;
&lt;LI&gt;Customer data&lt;/LI&gt;
&lt;LI&gt;Credentials&lt;/LI&gt;
&lt;LI&gt;Internal business documents&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;At the same time, enterprise AI usage is increasingly exposed to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Prompt injection attacks&lt;/LI&gt;
&lt;LI&gt;Malicious API manipulation&lt;/LI&gt;
&lt;LI&gt;Unsafe model outputs&lt;/LI&gt;
&lt;LI&gt;Compliance violations&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Security and compliance teams currently lack centralized visibility and governance over enterprise AI usage.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Existing tools are fragmented and do not provide unified protection across the complete AI attack surface including Data, Prompt/API, and Model layers.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Organizations require an intelligent, autonomous platform capable of&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;detecting Shadow AI usage,&lt;BR /&gt;preventing sensitive data leakage,&lt;BR /&gt;securing AI interactions,&lt;BR /&gt;enforcing governance policies,&lt;BR /&gt;and maintaining compliance in real time.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Proposed Solution:&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;AI Guardian is an intelligent security and governance platform designed to secure enterprise AI adoption and mitigate Shadow AI risks.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;1) The platform continuously monitors AI interactions across enterprise environments and provides autonomous protection across multiple AI attack surfaces.&lt;/STRONG&gt;&lt;BR /&gt;&lt;BR /&gt;Core Capabilities&lt;BR /&gt;Shadow AI Detection&lt;BR /&gt;Detects unauthorized AI tool usage&lt;BR /&gt;Monitors risky AI interactions&lt;BR /&gt;Identifies sensitive data exposure&lt;BR /&gt;Multi-Layer AI Security&lt;BR /&gt;Data Layer Protection&lt;BR /&gt;PII detection&lt;BR /&gt;API key and credential scanning&lt;BR /&gt;Confidential data leakage prevention&lt;BR /&gt;Prompt/API Layer Protection&lt;BR /&gt;Prompt injection detection&lt;BR /&gt;Malicious prompt analysis&lt;BR /&gt;API abuse detection&lt;BR /&gt;Model Layer Protection&lt;BR /&gt;Unsafe response monitoring&lt;BR /&gt;AI Compliance Copilot&lt;BR /&gt;Generates governance reports&lt;BR /&gt;Recommends remediation actions&lt;BR /&gt;&lt;BR /&gt;&lt;STRONG&gt;2.AI Guardian Extension Automatically performs:&lt;/STRONG&gt;&lt;BR /&gt;prompt blocking,&lt;BR /&gt;redaction,&lt;BR /&gt;SOC alerting,&lt;BR /&gt;incident creation,&lt;BR /&gt;and compliance logging.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;3.AI Guardian Extension Business Value:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This AI Guardian delivers measurable business value by enabling secure and governed enterprise AI adoption.&lt;BR /&gt;&lt;STRONG&gt;4.Key Business Benefits&lt;/STRONG&gt;&lt;BR /&gt;1. Prevents Sensitive Data Leakage&lt;BR /&gt;2. Enables Safe Enterprise AI Adoption&lt;BR /&gt;3. Reduces Compliance Risks and helps align enterprise AI usage with:&lt;BR /&gt;SOC2&lt;BR /&gt;ISO27001&lt;BR /&gt;GDPR&lt;BR /&gt;Internal security policies&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;&lt;STRONG&gt;5. Improves Security Visibility and provides centralized visibility into:&lt;/STRONG&gt;&lt;BR /&gt;&lt;BR /&gt;AI usage patterns&lt;BR /&gt;risky prompts&lt;BR /&gt;Shadow AI activity&lt;BR /&gt;policy violations&lt;BR /&gt;&lt;BR /&gt;&lt;STRONG&gt;6. Strengthens Enterprise AI Security Posture and protects multiple AI attack surfaces including:&lt;/STRONG&gt;&lt;BR /&gt;&lt;BR /&gt;Data Layer&lt;BR /&gt;Prompt/API Layer&lt;BR /&gt;Model Layer&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Customer Involvement&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-teams="true"&gt;No Customer Involvement added.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Scenario: Employee pastes confidential code into ChatGPT&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;User opens ChatGPT in the browser&lt;/LI&gt;
&lt;LI&gt;AI Guardian Extension detects site access&lt;/LI&gt;
&lt;LI&gt;User pastes source code containing an API key&lt;/LI&gt;
&lt;LI&gt;Content script captures prompt text&lt;/LI&gt;
&lt;LI&gt;Sensitive data detector finds the API key&lt;/LI&gt;
&lt;LI&gt;Policy engine classifies the action as high risk&lt;/LI&gt;
&lt;LI&gt;Extension redacts the key and blocks original submission&lt;/LI&gt;
&lt;LI&gt;User sees a notification explaining the action&lt;/LI&gt;
&lt;LI&gt;Event is logged to AI Guardian backend&lt;/LI&gt;
&lt;LI&gt;SOC alert and compliance log are generated if required&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The rise of Shadow AI means enterprises can no longer rely solely on backend monitoring or post-event analysis. Security controls must move closer to the &lt;STRONG&gt;user interaction point&lt;/STRONG&gt;, where prompts are created and data is shared.&lt;/P&gt;
&lt;P&gt;Building an &lt;STRONG&gt;AI Guardian Browser Extension&lt;/STRONG&gt; provides that control plane.&lt;/P&gt;
&lt;P&gt;It enables organizations to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;detect unauthorized AI usage&lt;/LI&gt;
&lt;LI&gt;inspect prompts in real time&lt;/LI&gt;
&lt;LI&gt;prevent sensitive data leakage&lt;/LI&gt;
&lt;LI&gt;block malicious interactions&lt;/LI&gt;
&lt;LI&gt;enforce governance policies&lt;/LI&gt;
&lt;LI&gt;generate audit-ready logs&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;In a world where AI adoption is accelerating faster than governance, the AI Guardian Extension becomes a practical and scalable way to make enterprise AI usage &lt;STRONG&gt;secure, visible, and compliant&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 19 May 2026 11:41:31 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-ai-guardian-extension-ai-detection-and-enterprise-ai/ba-p/4521125</guid>
      <dc:creator>ranjsharma</dc:creator>
      <dc:date>2026-05-19T11:41:31Z</dc:date>
    </item>
    <item>
      <title>Rundeck – AWS Enterprise Rundeck Integration with Azure Runner</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/rundeck-aws-enterprise-rundeck-integration-with-azure-runner/ba-p/4521080</link>
      <description>&lt;H2&gt;Architecture Overview&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Rundeck Server (AWS)&lt;/STRONG&gt; → https://dev.rundeck.xyz.com&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Rundeck Runner (Azure Linux VM)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Secure Communication&lt;/STRONG&gt; over HTTPS (Port 4432)&lt;/LI&gt;
&lt;LI&gt;Optional Proxy for enterprise networks&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;1.Ensure that network connectivity is established between the Rundeck endpoint (dev.rundeck.xyz.com) and the Azure subnet over port 443.&lt;/P&gt;
&lt;P&gt;2.Request the customer to create a Runner within a new or existing project in the Rundeck portal by providing a suitable name and tags and&amp;nbsp;then proceed to download the corresponding Runner JAR file.&lt;/P&gt;
&lt;P&gt;3.Provision an Azure Linux Virtual Machine and deploy the downloaded Runner JAR using a VM extension or through a CI/CD pipeline integrated with BAMS/Artifactory. Below all prerequisite steps are mentioned which needs to be run on Azure VM to ensure Rundeck runner is ready.&lt;/P&gt;
&lt;P&gt;4.Additionally, make sure all required prerequisites are installed on the Azure Linux VM that will host the Rundeck Runner.&lt;/P&gt;
&lt;P&gt;5.After installation it will establish the connectivity between azure Rundeck runner and Aws Enterprise Rundeck.&lt;/P&gt;
&lt;P&gt;6.We can trigger any Rundeck jobs on Azure virtual machines.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;By deploying the Rundeck Runner on Azure, enterprises can seamlessly bridge AWS-hosted orchestration with Azure-based execution environments. This setup enables robust, scalable, and secure automation across hybrid cloud ecosystems.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;All prerequiste needs to be run on the Azure vm.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 1: Network Connectivity Prerequisites:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Ensure proper network connectivity between Rundeck and Azure:&lt;/P&gt;
&lt;P&gt;Allow outbound/inbound access: Source: Azure Subnet Destination: dev.rundeck.xyz.com Port: 443 Protocol: HTTP&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 2: Create Rundeck Runner&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Login to Rundeck Portal&lt;/P&gt;
&lt;P&gt;Navigate to a project → Runner Management&lt;/P&gt;
&lt;P&gt;Create a new runner:&lt;/P&gt;
&lt;P&gt;Provide Name&lt;/P&gt;
&lt;P&gt;Add Tags&lt;/P&gt;
&lt;P&gt;Download the Runner JAR file&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 3: Azure VM setup&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Create a Linux VM (RHEL/CentOS) in Azure.&lt;/P&gt;
&lt;P&gt;Deploy the runner jar via:&lt;/P&gt;
&lt;P&gt;CI/CD pipeline (BAMS/Artifactory)&lt;/P&gt;
&lt;P&gt;VM Extension for automation&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 4: Install Prerequisites on Azure VM&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Install Java 11&lt;/P&gt;
&lt;P&gt;sudo bash&lt;/P&gt;
&lt;P&gt;yum install java-11-openjdk.x86_64&lt;/P&gt;
&lt;P&gt;rpm -qa | grep java-11&lt;/P&gt;
&lt;P&gt;java --version&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 5: Start the Runner -&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;useradd rundeck&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 6: Create Rundeck User-&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;mkdir /opt/rundeck/&lt;/P&gt;
&lt;P&gt;chown -R rundeck:rundeck /opt/rundeck/&lt;/P&gt;
&lt;P&gt;cp runner-*.jar /opt/rundeck/&lt;/P&gt;
&lt;P&gt;ll /opt/rundeck/&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 7: Start the Runner -&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;without proxy&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;/bin/java -jar /opt/rundeck/runner-&amp;lt;id&amp;gt;.jar&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;With proxy:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;/bin/java \&lt;/P&gt;
&lt;P&gt;-Dmicronaut.http.client.proxy-type=http \&lt;/P&gt;
&lt;P&gt;-Dmicronaut.http.client.proxy-address=webproxy.lo5.mgmt.services:80 \&lt;/P&gt;
&lt;P&gt;-jar /opt/rundeck/runner-&amp;lt;id&amp;gt;.jar&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 8: Configure Runner as a Service&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;vi /etc/systemd/system/runner.service&lt;/P&gt;
&lt;P&gt;Add Configuration&lt;/P&gt;
&lt;P&gt;[Unit]&lt;/P&gt;
&lt;P&gt;Description=Process Automation Runner&lt;/P&gt;
&lt;P&gt;[Service]&lt;/P&gt;
&lt;P&gt;WorkingDirectory=/opt/rundeck/&lt;/P&gt;
&lt;P&gt;Type=simple&lt;/P&gt;
&lt;P&gt;User=rundeck&lt;/P&gt;
&lt;P&gt;Group=rundeck&lt;/P&gt;
&lt;P&gt;ExecStart=/bin/java -jar /opt/rundeck/runner-&amp;lt;id&amp;gt;.jar&lt;/P&gt;
&lt;P&gt;Restart=on-failure&lt;/P&gt;
&lt;P&gt;[Install]&lt;/P&gt;
&lt;P&gt;WantedBy=multi-user.target&lt;/P&gt;
&lt;P&gt;Enable and start service:&lt;/P&gt;
&lt;P&gt;chmod 0640 /etc/systemd/system/runner.service&lt;/P&gt;
&lt;P&gt;systemctl daemon-reload&lt;/P&gt;
&lt;P&gt;systemctl enable runner.service&lt;/P&gt;
&lt;P&gt;systemctl start runner.service&lt;/P&gt;
&lt;P&gt;systemctl status runner.service&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 9: Verify Runner Process&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;ps aux | grep rundeck&lt;/P&gt;
&lt;P&gt;systemctl status runner.service&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 10: Configure Log Rotation&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;create configuration:&lt;/P&gt;
&lt;P&gt;vi /etc/logrotate.d/rundeck_runnerd&lt;/P&gt;
&lt;P&gt;/opt/rundeck/runner/logs/operations.log&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp;daily&lt;/P&gt;
&lt;P&gt;&amp;nbsp;missingok&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rotate 8&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; compress&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; copytruncate&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; maxsize 150M&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; create 644 root root&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 11: Runner Upgrade Process&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Regenerate credentials:&lt;/P&gt;
&lt;P&gt;curl -k -X POST https://dev.rundeck.xyz.com/api/42/runnerManagement/runner/&amp;lt;runner-id&amp;gt;/regenerateCreds \&lt;/P&gt;
&lt;P&gt;--header "Content-Type: application/json" \&lt;/P&gt;
&lt;P&gt;--header "X-Rundeck-Auth-Token: &amp;lt;token&amp;gt;"&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Step 12: Download Updated runner&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;curl -k -X GET https://dev.rundeck.xyz.com/api/41/runnerManagement/download/&amp;lt;downloadTk&amp;gt; \&lt;/P&gt;
&lt;P&gt;--header "X-Rundeck-Auth-Token: &amp;lt;token&amp;gt;" \&lt;/P&gt;
&lt;P&gt;--output runner-${runner_id}.jar&lt;/P&gt;</description>
      <pubDate>Tue, 19 May 2026 10:08:59 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/rundeck-aws-enterprise-rundeck-integration-with-azure-runner/ba-p/4521080</guid>
      <dc:creator>ranjsharma</dc:creator>
      <dc:date>2026-05-19T10:08:59Z</dc:date>
    </item>
    <item>
      <title>Building a Terraform Drift Validator for Azure with Live Portal Verification</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-a-terraform-drift-validator-for-azure-with-live-portal/ba-p/4520952</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Architecture:&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;This blog describes how to build a practical &lt;STRONG&gt;Terraform Drift Validator for Azure&lt;/STRONG&gt; that compares &lt;STRONG&gt;three sources of truth&lt;/STRONG&gt;:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Excel sheet or design document&lt;/STRONG&gt; containing expected Azure configuration&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform state file&lt;/STRONG&gt; representing IaC-managed deployed intent&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Live Azure configuration&lt;/STRONG&gt;, verified both programmatically and through &lt;STRONG&gt;Azure Portal step-by-step checks&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The solution can be exposed as a lightweight validation application. Below is the link of agent created for drift validator for infra.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;A class="lia-external-url" href="https://ca-aiv-agent.livelyhill-f6d3be20.eastus.azurecontainerapps.io/" target="_blank" rel="noopener"&gt;https://ca-aiv-agent.livelyhill-f6d3be20.eastus.azurecontainerapps.io/&lt;/A&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;H2&gt;Key Takeaways&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;Terraform drift detection is valuable but &lt;STRONG&gt;Terraform alone is not enough&lt;/STRONG&gt; when enterprises also rely on design documents, migration inventories, and operational portal validations.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;Azure attributes such as &lt;STRONG&gt;SKU, tags, accelerated networking, managed disk type, and zone placement&lt;/STRONG&gt; can all be validated using a mix of Terraform state parsing, Azure APIs/Resource Graph, and portal verification.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure Resource Graph&lt;/STRONG&gt; is especially useful for fast, large-scale live validation because it can query resource properties across subscriptions without calling every resource provider one by one.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Managed Identity&lt;/STRONG&gt; is the preferred enterprise authentication model for a read-only validator because it removes credential handling and supports token-based access to downstream Azure services.&lt;/LI&gt;
&lt;LI&gt;Manual &lt;STRONG&gt;Azure Portal verification with documented steps and screenshot placeholders&lt;/STRONG&gt; makes the solution feel audit-ready, migration-ready, and operationally trustworthy.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;1. Introduction&lt;/H2&gt;
&lt;P&gt;Terraform drift in Azure happens when what is actually deployed no longer matches what Terraform thinks exists or what the original design intended. In practice, drift appears after portal edits, partial manual changes, external scripts, policy remediation, or emergency operational actions that never get folded back into code. HashiCorp recommends automated drift detection because unmanaged divergence can create operational inconsistency, security exposure, and compliance risk.&lt;/P&gt;
&lt;P&gt;Azure environments make this especially important because infrastructure is often governed by multiple teams: architects define the target design, DevOps teams deploy through Terraform, and operations teams may validate or troubleshoot through Azure Portal. Azure Resource Graph itself exists to support large-scale governance and current-state visibility across subscriptions, which makes it a strong foundation for live verification.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;That is why an enterprise-grade drift validator should not compare only &lt;STRONG&gt;Terraform vs Azure&lt;/STRONG&gt;. It should compare:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Design intent&lt;/STRONG&gt; from Excel or architecture documentation&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform state&lt;/STRONG&gt; as the IaC-managed representation&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure live configuration&lt;/STRONG&gt; as the real runtime state&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;2. Problem Statement&lt;/H2&gt;
&lt;P&gt;Many organizations still maintain infrastructure specifications in Excel, migration trackers, or design documents. Those documents often contain the details that matter most to governance and operations: VM sizes, storage SKUs, disk performance expectations, tags, zones, and network settings. Terraform state, on the other hand, reflects what Terraform knows about deployed resources. Azure live state reflects what is actually running.&lt;/P&gt;
&lt;P&gt;These three sources diverge for common reasons:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A VM was resized manually in Azure Portal&lt;/LI&gt;
&lt;LI&gt;Accelerated networking was expected in design, defined in Terraform, but the actual NIC does not reflect it&lt;/LI&gt;
&lt;LI&gt;Tags were defined in a workbook but never applied consistently&lt;/LI&gt;
&lt;LI&gt;Storage or disk settings changed during production troubleshooting&lt;/LI&gt;
&lt;LI&gt;Zone placement differs from the architecture baseline&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;3. Solution Overview&lt;/H2&gt;
&lt;P&gt;The proposed solution is a &lt;STRONG&gt;Terraform Drift Validator for Azure with Live Portal Verification&lt;/STRONG&gt;. At a high level, it works like this:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The user uploads an &lt;STRONG&gt;Excel sheet&lt;/STRONG&gt; or &lt;STRONG&gt;design document&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;The solution extracts expected resource configuration&lt;/LI&gt;
&lt;LI&gt;It ingests the &lt;STRONG&gt;Terraform state file&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;It queries &lt;STRONG&gt;Azure live resources&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;It normalizes values across all three sources&lt;/LI&gt;
&lt;LI&gt;It compares attributes and generates a structured drift report&lt;/LI&gt;
&lt;LI&gt;It optionally presents portal validation steps for manual verification&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;This can run as a &lt;STRONG&gt;web application, API service, or agent-based validator&lt;/STRONG&gt;, exposed through:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;https://ca-aiv-agent.livelyhill-f6d3be20.eastus.azurecontainerapps.io/&lt;/STRONG&gt;&lt;/P&gt;
&lt;H2&gt;4. Supported Validation Parameters&lt;/H2&gt;
&lt;P&gt;A useful validator should support the following checks:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;SKU&lt;/STRONG&gt;&lt;BR /&gt;Validate expected SKU from design against Terraform and live Azure. This is critical for cost and performance.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;IOPS&lt;/STRONG&gt;&lt;BR /&gt;Validate disk performance expectations. Azure documents that some disk types—particularly Ultra Disk and Premium SSD v2—allow direct performance tuning, making IOPS a meaningful validation parameter. &lt;A href="https://learn.microsoft.com/en-us/azure/virtual-machines/disks-performance-options" target="_blank" rel="noopener"&gt;[&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Accelerated Networking&lt;/STRONG&gt;&lt;BR /&gt;Azure states that accelerated networking improves VM network performance by reducing latency and CPU utilization via SR-IOV on supported VM sizes. This is exactly the kind of feature that is frequently missed or changed during deployments.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Tags&lt;/STRONG&gt;&lt;BR /&gt;Azure tags are key-value metadata used for governance, organization, and cost management. Azure also warns that tags are stored as plain text and should not contain sensitive data.&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Availability Zones&lt;/STRONG&gt;&lt;BR /&gt;Validate whether resources are placed in the expected zone(s) or zone-resilient configuration.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Region&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;VM Size&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Disk Type&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Resource Group&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;NIC and network configuration&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Optional controls&lt;/STRONG&gt; such as NSG expectations, public/private exposure, backup status, or monitoring configuration&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;a { text-decoration: none; color: #464feb; } tr th, tr td { border: 1px solid #e6e6e6; } tr th { background-color: #f5f5f5; }&lt;/P&gt;
&lt;H2&gt;7. Workflow&lt;/H2&gt;
&lt;OL&gt;
&lt;LI&gt;User uploads an Excel sheet or design document&lt;/LI&gt;
&lt;LI&gt;System extracts expected fields such as resource type, name, SKU, IOPS, tags, zones, region, VM size, and network settings&lt;/LI&gt;
&lt;LI&gt;Terraform state file is parsed into resource objects&lt;/LI&gt;
&lt;LI&gt;Azure live resources are queried using Resource Graph and targeted API calls&lt;/LI&gt;
&lt;LI&gt;Attribute names and values are normalized&lt;/LI&gt;
&lt;LI&gt;Comparison engine calculates:
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Match&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Design vs Terraform drift&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform vs Azure drift&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Design vs Azure drift&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;Final report is generated with severity and remediation recommendations&lt;/LI&gt;
&lt;/OL&gt;
&lt;H2&gt;8. Drift Report Output&lt;/H2&gt;
&lt;P&gt;A report should look like this:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Resource&lt;/th&gt;&lt;th&gt;Attribute&lt;/th&gt;&lt;th&gt;Expected&lt;/th&gt;&lt;th&gt;Terraform&lt;/th&gt;&lt;th&gt;Azure Live&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Severity&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;vm-prod-01&lt;/td&gt;&lt;td&gt;VM Size&lt;/td&gt;&lt;td&gt;Standard_D8s_v5&lt;/td&gt;&lt;td&gt;Standard_D8s_v5&lt;/td&gt;&lt;td&gt;Standard_D4s_v5&lt;/td&gt;&lt;td&gt;Drift&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nic-prod-01&lt;/td&gt;&lt;td&gt;Accelerated Networking&lt;/td&gt;&lt;td&gt;Enabled&lt;/td&gt;&lt;td&gt;Enabled&lt;/td&gt;&lt;td&gt;Disabled&lt;/td&gt;&lt;td&gt;Drift&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;disk-prod-01&lt;/td&gt;&lt;td&gt;Disk SKU&lt;/td&gt;&lt;td&gt;Premium SSD&lt;/td&gt;&lt;td&gt;Premium_LRS&lt;/td&gt;&lt;td&gt;StandardSSD_LRS&lt;/td&gt;&lt;td&gt;Drift&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;vm-prod-01&lt;/td&gt;&lt;td&gt;Tags.Environment&lt;/td&gt;&lt;td&gt;Production&lt;/td&gt;&lt;td&gt;Production&lt;/td&gt;&lt;td&gt;Prod&lt;/td&gt;&lt;td&gt;Drift&lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;vm-prod-01&lt;/td&gt;&lt;td&gt;Zone&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;col style="width: 14.29%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;9. Creating agents for same and uploading entire python code on the chrysalis&lt;/H2&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;10. Future Enhancements&lt;/H2&gt;
&lt;P&gt;Next-step enhancements could include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Scheduled drift monitoring&lt;/LI&gt;
&lt;LI&gt;CI/CD integration after deployment&lt;/LI&gt;
&lt;LI&gt;ServiceNow or Teams notifications&lt;/LI&gt;
&lt;LI&gt;AI-generated remediation summaries&lt;/LI&gt;
&lt;LI&gt;Policy-aware scoring&lt;/LI&gt;
&lt;LI&gt;Compliance dashboards&lt;/LI&gt;
&lt;LI&gt;FinOps insights tied to SKU variance&lt;/LI&gt;
&lt;LI&gt;Historical trend tracking of drift across subscriptions&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Tue, 19 May 2026 06:18:13 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-a-terraform-drift-validator-for-azure-with-live-portal/ba-p/4520952</guid>
      <dc:creator>ranjsharma</dc:creator>
      <dc:date>2026-05-19T06:18:13Z</dc:date>
    </item>
    <item>
      <title>Modernizing TCP Applications with Azure Application Gateway Layer 4 TCP/TLS Proxy</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/modernizing-tcp-applications-with-azure-application-gateway/ba-p/4519840</link>
      <description>&lt;H1 data-section-id="133azgn" data-start="1212" data-end="1239"&gt;Why TCP/TLS Proxy Matters&lt;/H1&gt;
&lt;P data-start="1241" data-end="1359"&gt;Modern cloud architectures commonly focus on HTTP/HTTPS traffic management, but many enterprise systems still rely on:&lt;/P&gt;
&lt;UL data-start="1360" data-end="1511"&gt;
&lt;LI data-section-id="lqalmf" data-start="1360" data-end="1387"&gt;Proprietary TCP protocols&lt;/LI&gt;
&lt;LI data-section-id="kw8ng3" data-start="1388" data-end="1419"&gt;Financial transaction systems&lt;/LI&gt;
&lt;LI data-section-id="149c7m2" data-start="1420" data-end="1441"&gt;Messaging platforms&lt;/LI&gt;
&lt;LI data-section-id="1d2gpeg" data-start="1442" data-end="1474"&gt;Legacy middleware applications&lt;/LI&gt;
&lt;LI data-section-id="1y88zqm" data-start="1475" data-end="1511"&gt;Secure client-server communication&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1513" data-end="1559"&gt;Traditionally, these workloads often required:&lt;/P&gt;
&lt;UL data-start="1560" data-end="1693"&gt;
&lt;LI data-section-id="832oea" data-start="1560" data-end="1595"&gt;Network Virtual Appliances (NVAs)&lt;/LI&gt;
&lt;LI data-section-id="2rmb87" data-start="1596" data-end="1621"&gt;Hardware load balancers&lt;/LI&gt;
&lt;LI data-section-id="17r2cfx" data-start="1622" data-end="1654"&gt;Custom reverse proxy solutions&lt;/LI&gt;
&lt;LI data-section-id="e6od9g" data-start="1655" data-end="1693"&gt;Dedicated TCP ingress infrastructure&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1695" data-end="1823"&gt;Managing these components across large environments can increase operational complexity and infrastructure maintenance overhead.&lt;/P&gt;
&lt;P data-start="1825" data-end="1999"&gt;The Layer 4 proxy capability in Azure Application Gateway helps organizations standardize ingress management for both HTTP and non-HTTP workloads using Azure-native services.&lt;/P&gt;
&lt;P data-start="1825" data-end="1999"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1 data-section-id="xnn57e" data-start="2006" data-end="2043"&gt;Understanding Layer 4 TCP/TLS Proxy&lt;/H1&gt;
&lt;H2 data-section-id="hf7hzx" data-start="2045" data-end="2085"&gt;Layer 7 vs Layer 4 Traffic Management&lt;/H2&gt;
&lt;H3 data-section-id="l48jsf" data-start="2087" data-end="2111"&gt;Layer 7 (HTTP/HTTPS)&lt;/H3&gt;
&lt;P data-start="2113" data-end="2183"&gt;Layer 7 routing focuses on application-aware traffic handling such as:&lt;/P&gt;
&lt;UL data-start="2184" data-end="2277"&gt;
&lt;LI data-section-id="1qtxb7" data-start="2184" data-end="2203"&gt;URL-based routing&lt;/LI&gt;
&lt;LI data-section-id="wp28qx" data-start="2204" data-end="2223"&gt;Header inspection&lt;/LI&gt;
&lt;LI data-section-id="1bl2sj2" data-start="2224" data-end="2241"&gt;Cookie affinity&lt;/LI&gt;
&lt;LI data-section-id="hld52i" data-start="2242" data-end="2277"&gt;Web Application Firewall policies&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="1s39voz" data-start="2279" data-end="2300"&gt;Layer 4 (TCP/TLS)&lt;/H3&gt;
&lt;P data-start="2302" data-end="2371"&gt;Layer 4 proxy focuses on connection-level traffic handling including:&lt;/P&gt;
&lt;UL data-start="2372" data-end="2472"&gt;
&lt;LI data-section-id="1wzd7zt" data-start="2372" data-end="2396"&gt;TCP traffic forwarding&lt;/LI&gt;
&lt;LI data-section-id="149w76x" data-start="2397" data-end="2423"&gt;TLS traffic pass-through&lt;/LI&gt;
&lt;LI data-section-id="1jf2ogh" data-start="2424" data-end="2444"&gt;Port-based routing&lt;/LI&gt;
&lt;LI data-section-id="n3893k" data-start="2445" data-end="2472"&gt;Backend load distribution&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="2474" data-end="2597"&gt;This approach is useful for applications that do not use HTTP protocols but still require centralized ingress architecture.&lt;/P&gt;
&lt;P data-start="2474" data-end="2597"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1 data-section-id="iu56ur" data-start="2604" data-end="2630"&gt;Key Feature Capabilities&lt;/H1&gt;
&lt;H2 data-section-id="ug22m8" data-start="2632" data-end="2662"&gt;TCP and TLS Traffic Support&lt;/H2&gt;
&lt;P data-start="2664" data-end="2702"&gt;The Layer 4 proxy capability supports:&lt;/P&gt;
&lt;UL data-start="2703" data-end="2794"&gt;
&lt;LI data-section-id="15nuh0i" data-start="2703" data-end="2718"&gt;TCP listeners&lt;/LI&gt;
&lt;LI data-section-id="q56hce" data-start="2719" data-end="2734"&gt;TLS listeners&lt;/LI&gt;
&lt;LI data-section-id="lje7s9" data-start="2735" data-end="2762"&gt;Secure traffic forwarding&lt;/LI&gt;
&lt;LI data-section-id="12my7u1" data-start="2763" data-end="2794"&gt;Backend connection management&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="2796" data-end="2888"&gt;This enables organizations to expose non-HTTP workloads through a centralized ingress layer.&lt;/P&gt;
&lt;H2 data-section-id="11y619i" data-start="2895" data-end="2922"&gt;TLS Pass-Through Support&lt;/H2&gt;
&lt;P data-start="2924" data-end="3034"&gt;In TLS pass-through scenarios, encrypted traffic remains encrypted between the client and backend application.&lt;/P&gt;
&lt;P data-start="3036" data-end="3065"&gt;Potential advantages include:&lt;/P&gt;
&lt;UL data-start="3066" data-end="3187"&gt;
&lt;LI data-section-id="1r6b8xf" data-start="3066" data-end="3097"&gt;End-to-end encryption support&lt;/LI&gt;
&lt;LI data-section-id="gh5n1u" data-start="3098" data-end="3137"&gt;Backend-managed certificate ownership&lt;/LI&gt;
&lt;LI data-section-id="wrs1m9" data-start="3138" data-end="3187"&gt;Reduced application-layer processing at ingress&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="3189" data-end="3281"&gt;This model can be useful for applications with strict encryption or compliance requirements.&lt;/P&gt;
&lt;H2 data-section-id="v2gw2f" data-start="3288" data-end="3316"&gt;Proxy Protocol v1 Support&lt;/H2&gt;
&lt;P data-start="3318" data-end="3418"&gt;One important capability available in TCP/TLS backend settings is support for &lt;STRONG data-start="3396" data-end="3417"&gt;Proxy Protocol v1&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P data-start="3420" data-end="3523"&gt;Proxy Protocol v1 helps pass original client connection information to backend applications, including:&lt;/P&gt;
&lt;UL data-start="3524" data-end="3601"&gt;
&lt;LI data-section-id="oi6kfu" data-start="3524" data-end="3543"&gt;Source IP address&lt;/LI&gt;
&lt;LI data-section-id="k0ecwr" data-start="3544" data-end="3568"&gt;Destination IP address&lt;/LI&gt;
&lt;LI data-section-id="iyiqcs" data-start="3569" data-end="3582"&gt;Source port&lt;/LI&gt;
&lt;LI data-section-id="1pc8dfx" data-start="3583" data-end="3601"&gt;Destination port&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="3603" data-end="3639"&gt;This capability can be valuable for:&lt;/P&gt;
&lt;UL data-start="3640" data-end="3757"&gt;
&lt;LI data-section-id="4nmdm1" data-start="3640" data-end="3670"&gt;Backend logging and auditing&lt;/LI&gt;
&lt;LI data-section-id="1w3hg6k" data-start="3671" data-end="3690"&gt;Security analysis&lt;/LI&gt;
&lt;LI data-section-id="vv7hsq" data-start="3691" data-end="3711"&gt;Connection tracing&lt;/LI&gt;
&lt;LI data-section-id="hotpyn" data-start="3712" data-end="3757"&gt;Applications requiring client IP visibility&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="3759" data-end="3900"&gt;Without Proxy Protocol support, backend applications may only see the Application Gateway frontend IP rather than the original client source.&lt;/P&gt;
&lt;P data-start="3902" data-end="4121"&gt;When enabling Proxy Protocol v1, backend applications must also support parsing the Proxy Protocol header. Organizations should validate application compatibility before enabling this setting in production environments.&lt;/P&gt;
&lt;H2 data-section-id="1aj6vc3" data-start="4128" data-end="4155"&gt;Backend Pool Integration&lt;/H2&gt;
&lt;P data-start="4157" data-end="4210"&gt;Layer 4 proxy supports backend pool integration with:&lt;/P&gt;
&lt;UL data-start="4211" data-end="4336"&gt;
&lt;LI data-section-id="olznun" data-start="4211" data-end="4229"&gt;Virtual machines&lt;/LI&gt;
&lt;LI data-section-id="1yj71np" data-start="4230" data-end="4258"&gt;Virtual machine scale sets&lt;/LI&gt;
&lt;LI data-section-id="qz11mi" data-start="4259" data-end="4278"&gt;IP-based backends&lt;/LI&gt;
&lt;LI data-section-id="lsm4d4" data-start="4279" data-end="4336"&gt;Kubernetes workloads hosted on Azure Kubernetes Service&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4338" data-end="4444"&gt;This flexibility allows organizations to standardize ingress architecture across different workload types.&lt;/P&gt;
&lt;P data-start="4338" data-end="4444"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1 data-section-id="16jv0hm" data-start="4451" data-end="4480"&gt;Common Enterprise Use Cases&lt;/H1&gt;
&lt;H2 data-section-id="z0yi2j" data-start="4482" data-end="4517"&gt;Legacy Application Modernization&lt;/H2&gt;
&lt;P data-start="4519" data-end="4654"&gt;Organizations migrating traditional applications to Azure may need TCP ingress without redesigning application communication protocols.&lt;/P&gt;
&lt;H2 data-section-id="1hrem5w" data-start="4656" data-end="4683"&gt;Kubernetes TCP Workloads&lt;/H2&gt;
&lt;P data-start="4685" data-end="4773"&gt;Applications running on Azure Kubernetes Service frequently expose TCP services such as:&lt;/P&gt;
&lt;UL data-start="4774" data-end="4871"&gt;
&lt;LI data-section-id="13cqjzq" data-start="4774" data-end="4793"&gt;Messaging brokers&lt;/LI&gt;
&lt;LI data-section-id="1o956xp" data-start="4794" data-end="4814"&gt;Database endpoints&lt;/LI&gt;
&lt;LI data-section-id="cyi6wq" data-start="4815" data-end="4835"&gt;Streaming services&lt;/LI&gt;
&lt;LI data-section-id="13fupbe" data-start="4836" data-end="4871"&gt;Proprietary application protocols&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4873" data-end="4946"&gt;Layer 4 proxy can help centralize ingress management for these workloads.&lt;/P&gt;
&lt;H2 data-section-id="wvk8ce" data-start="4948" data-end="4974"&gt;Secure TLS Pass-Through&lt;/H2&gt;
&lt;P data-start="4976" data-end="5115"&gt;Some enterprise applications require end-to-end encryption where TLS termination remains on backend services rather than the ingress layer.&lt;/P&gt;
&lt;H2 data-section-id="19l81tj" data-start="5117" data-end="5148"&gt;Hybrid Connectivity Patterns&lt;/H2&gt;
&lt;P data-start="5150" data-end="5277"&gt;Enterprises integrating on-premises applications with Azure workloads may also benefit from centralized TCP traffic management.&lt;/P&gt;
&lt;P data-start="5150" data-end="5277"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1 data-section-id="h3bfrs" data-start="5284" data-end="5308"&gt;Architecture Pattern&lt;/H1&gt;
&lt;P data-start="5352" data-end="5392"&gt;A typical architecture pattern includes:&lt;/P&gt;
&lt;OL data-start="5394" data-end="5655"&gt;
&lt;LI data-section-id="vihet8" data-start="5394" data-end="5444"&gt;Client application initiates TCP/TLS connection&lt;/LI&gt;
&lt;LI data-section-id="6so9fm" data-start="5445" data-end="5498"&gt;Azure Application Gateway receives inbound traffic&lt;/LI&gt;
&lt;LI data-section-id="1bev247" data-start="5499" data-end="5551"&gt;Layer 4 listener forwards traffic to backend pool&lt;/LI&gt;
&lt;LI data-section-id="16yz9cj" data-start="5552" data-end="5595"&gt;Backend applications process TCP traffic&lt;/LI&gt;
&lt;LI data-section-id="1p5ximt" data-start="5596" data-end="5655"&gt;Traffic routing is managed based on backend availability&lt;/LI&gt;
&lt;/OL&gt;
&lt;P data-start="5657" data-end="5695"&gt;Core Azure services commonly involved:&lt;/P&gt;
&lt;UL data-start="5696" data-end="5774"&gt;
&lt;LI data-section-id="144zwnn" data-start="5696" data-end="5723"&gt;Azure Application Gateway&lt;/LI&gt;
&lt;LI data-section-id="139c5xq" data-start="5724" data-end="5750"&gt;Azure Kubernetes Service&lt;/LI&gt;
&lt;LI data-section-id="1lt2pm6" data-start="5751" data-end="5774"&gt;Azure Virtual Network&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1 data-section-id="lvctv2" data-start="6471" data-end="6509"&gt;Benefits of Azure-Native TCP Ingress&lt;/H1&gt;
&lt;P data-start="6511" data-end="6578"&gt;Potential advantages of using Azure-native Layer 4 ingress include:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Area&lt;/th&gt;&lt;th&gt;Potential Benefit&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Operations&lt;/td&gt;&lt;td&gt;Reduced infrastructure management overhead&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Scalability&lt;/td&gt;&lt;td&gt;Managed platform scaling capabilities&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Architecture&lt;/td&gt;&lt;td&gt;Centralized ingress management&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Integration&lt;/td&gt;&lt;td&gt;Native Azure networking compatibility&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Availability&lt;/td&gt;&lt;td&gt;Support for resilient deployment patterns&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1 data-section-id="12hrzbf" data-start="7007" data-end="7028"&gt;Key Recommendations&lt;/H1&gt;
&lt;P data-start="7030" data-end="7070"&gt;When implementing Layer 4 TCP/TLS proxy:&lt;/P&gt;
&lt;UL data-start="7071" data-end="7346"&gt;
&lt;LI data-section-id="vjrs23" data-start="7071" data-end="7149"&gt;Validate backend application compatibility with Proxy Protocol v1 if enabled&lt;/LI&gt;
&lt;LI data-section-id="loen5f" data-start="7150" data-end="7186"&gt;Monitor long-lived TCP connections&lt;/LI&gt;
&lt;LI data-section-id="1wcwst6" data-start="7187" data-end="7219"&gt;Test backend scaling scenarios&lt;/LI&gt;
&lt;LI data-section-id="dwjdie" data-start="7220" data-end="7274"&gt;Validate TLS handling requirements before deployment&lt;/LI&gt;
&lt;LI data-section-id="uzt5na" data-start="7275" data-end="7346"&gt;Align ingress architecture with application connectivity requirements&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="7348" data-end="7411"&gt;For enterprise deployments, organizations should also evaluate:&lt;/P&gt;
&lt;UL data-start="7412" data-end="7493"&gt;
&lt;LI data-section-id="1vuz5rc" data-start="7412" data-end="7444"&gt;Disaster recovery requirements&lt;/LI&gt;
&lt;LI data-section-id="q43szl" data-start="7445" data-end="7464"&gt;Capacity planning&lt;/LI&gt;
&lt;LI data-section-id="mwy9gj" data-start="7465" data-end="7493"&gt;Operational support models&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Thu, 14 May 2026 18:51:33 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/modernizing-tcp-applications-with-azure-application-gateway/ba-p/4519840</guid>
      <dc:creator>rbhatia</dc:creator>
      <dc:date>2026-05-14T18:51:33Z</dc:date>
    </item>
    <item>
      <title>From Pipelines to Agents: Self-Healing CI/CD Workflow</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/from-pipelines-to-agents-self-healing-ci-cd-workflow/ba-p/4519494</link>
      <description>&lt;H3 data-path-to-node="4"&gt;&amp;nbsp;&lt;/H3&gt;
&lt;H3 data-path-to-node="4"&gt;&amp;nbsp;&lt;/H3&gt;
&lt;H3 data-path-to-node="4"&gt;&lt;STRONG data-path-to-node="4" data-index-in-node="0"&gt;The Brain of the Operation: Azure OpenAI.&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P data-path-to-node="5"&gt;When building a DevOps agent, following are the points which can be considered to select Azure OpenAI as the ideal choice for logical engine:&lt;/P&gt;
&lt;OL data-path-to-node="6"&gt;
&lt;LI&gt;&lt;STRONG data-path-to-node="6,0,0" data-index-in-node="0"&gt;Native Tool Use:&lt;/STRONG&gt; It is specifically optimized for function calling, allowing the agent to interact with Azure DevOps APIs and Github seamlessly.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG data-path-to-node="6,1,0" data-index-in-node="0"&gt;Cost Efficiency:&lt;/STRONG&gt; As a first-party service, Azure OpenAI is the most cost-effective way to run production-grade agents.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG data-path-to-node="6,2,0" data-index-in-node="0"&gt;Speed and Context:&lt;/STRONG&gt; GPT-4o processes complex logs in seconds, identifying the error much faster.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-path-to-node="8"&gt;&lt;STRONG data-path-to-node="8" data-index-in-node="0"&gt;The Architecture: A Self-Healing Loop&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P data-path-to-node="9"&gt;A self-healing workflow is an agentic loop consisting of three phases: &lt;STRONG data-path-to-node="9" data-index-in-node="71"&gt;Observe, Analyze, and Act.&lt;/STRONG&gt;&lt;/P&gt;
&lt;H4 data-path-to-node="10"&gt;&lt;STRONG data-path-to-node="10" data-index-in-node="0"&gt;1. Observe (The Trigger)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P data-path-to-node="11"&gt;The process begins with an event-driven trigger. When an Azure DevOps pipeline fails, a webhook sends the telemetry and build logs to an Azure Function.&lt;/P&gt;
&lt;H4 data-path-to-node="12"&gt;&lt;STRONG data-path-to-node="12" data-index-in-node="0"&gt;2. Analyze (The Reasoning)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P data-path-to-node="13"&gt;The logs are passed to GPT-4o via the Microsoft AI Foundry endpoint. The model doesn't just look for error codes; it understands the infrastructure context.&lt;/P&gt;
&lt;P data-path-to-node="14"&gt;&lt;STRONG data-path-to-node="14" data-index-in-node="0"&gt;The Prompt:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-path-to-node="15,0"&gt;&lt;EM data-path-to-node="15,0" data-index-in-node="0"&gt;"You are a DevOps Engineer. Analyze this build log from our Azure Internal Load Balancer deployment. Determine if the failure is a logic error in Terraform or a connectivity issue in the VNET. Suggest the exact code fix in JSON format."&lt;/EM&gt;&lt;/P&gt;
&lt;H4 data-path-to-node="16"&gt;&lt;STRONG data-path-to-node="16" data-index-in-node="0"&gt;3. Act (The Execution)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P data-path-to-node="17"&gt;This is where the agent becomes "autonomous." Using function calling, the agent can take the following action as an example:&lt;/P&gt;
&lt;UL data-path-to-node="18"&gt;
&lt;LI&gt;&lt;STRONG data-path-to-node="18,0,0" data-index-in-node="0"&gt;The Action:&lt;/STRONG&gt; If GPT-4o identifies a missing Health Probe in your ILB config, it invokes a tool to checkout the code branch, apply the fix, and open a Pull Request (PR) for your approval.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-path-to-node="20"&gt;&lt;STRONG data-path-to-node="20" data-index-in-node="0"&gt;Technical Implementation: Unified Inference&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P data-path-to-node="21"&gt;Microsoft AI Foundry provides a standardized way to call Azure OpenAI. This makes the agent code clean and portable:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="python"&gt;from azure.ai.inference import ChatCompletionsClient
from azure.core.credentials import AzureKeyCredential

# Initialize the Foundry Client for GPT-4o
client = ChatCompletionsClient(
    endpoint="https://your-gpt4o-deployment.eastus2.models.ai.azure.com",
    credential=AzureKeyCredential("YOUR_FOUNDRY_API_KEY")
)

def self_heal_pipeline(error_logs):
    response = client.complete(
        messages=[
            {"role": "system", "content": "You are an autonomous DevOps assistant."},
            {"role": "user", "content": f"Analyze and propose a fix for this log: {error_logs}"}
        ],
        model="gpt-4o"
    )
    
    # Logic to trigger a GitHub PR or an Azure DevOps Update
    return response.choices[0].message.content&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-path-to-node="23"&gt;&lt;STRONG data-path-to-node="23" data-index-in-node="0"&gt;Practical Example: The Migration Headache&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P data-path-to-node="24"&gt;In our example we had a task of mapping legacy load balancer settings (like &lt;EM data-path-to-node="24" data-index-in-node="139"&gt;fastest-app-response&lt;/EM&gt; or &lt;EM data-path-to-node="24" data-index-in-node="163"&gt;source-address persistence&lt;/EM&gt;) to Azure ILB rules.&lt;/P&gt;
&lt;P data-path-to-node="25"&gt;One small typo in a backend pool member IPs can tank a deployment. We have tested our agent to now scan these configs, flags mismatches, and suggests the correct Azure-native equivalent before the pipeline even runs. It’s saved us days of "trial and error" debugging.&lt;/P&gt;
&lt;P data-path-to-node="25"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P data-path-to-node="25"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-path-to-node="28"&gt;&lt;STRONG data-path-to-node="28" data-index-in-node="0"&gt;Final Thoughts: Stability on Autopilot&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P data-path-to-node="29"&gt;We’ve spent years trying to build the "perfect" pipeline, but the reality is that infrastructure is messy and code is human. By shifting the burden of initial troubleshooting to automated agents, we aren't just saving time; we’re increasing the reliability of our entire stack. Microsoft AI Foundry provides the secure sandbox we need to let these agents work safely.&lt;/P&gt;</description>
      <pubDate>Wed, 13 May 2026 20:21:28 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/from-pipelines-to-agents-self-healing-ci-cd-workflow/ba-p/4519494</guid>
      <dc:creator>RavinderGupta</dc:creator>
      <dc:date>2026-05-13T20:21:28Z</dc:date>
    </item>
    <item>
      <title>Azure Arc AKS Explained: Run Kubernetes Beyond Azure Cloud</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/azure-arc-aks-explained-run-kubernetes-beyond-azure-cloud/ba-p/4518443</link>
      <description>&lt;P data-start="62" data-end="192"&gt;Modern enterprises are no longer running workloads only inside a centralized cloud environment. Applications today operate across:&lt;/P&gt;
&lt;UL data-start="194" data-end="335"&gt;
&lt;LI data-section-id="1qarze" data-start="194" data-end="221"&gt;On-premises datacenters&lt;/LI&gt;
&lt;LI data-section-id="1xa8d57" data-start="222" data-end="247"&gt;Remote branch offices&lt;/LI&gt;
&lt;LI data-section-id="u3fi1o" data-start="248" data-end="272"&gt;Manufacturing plants&lt;/LI&gt;
&lt;LI data-section-id="3n6ibn" data-start="273" data-end="290"&gt;Retail stores&lt;/LI&gt;
&lt;LI data-section-id="1k15smd" data-start="291" data-end="309"&gt;Edge locations&lt;/LI&gt;
&lt;LI data-section-id="m3w92b" data-start="310" data-end="335"&gt;Hybrid infrastructure&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="337" data-end="506"&gt;While Kubernetes has become the standard for container orchestration, managing Kubernetes consistently across distributed environments introduces operational complexity.&lt;/P&gt;
&lt;P data-start="508" data-end="675"&gt;This is where Azure Arc and Azure Kubernetes Service extend the Azure control plane beyond traditional Azure cloud boundaries.&lt;/P&gt;
&lt;P data-start="677" data-end="776"&gt;Azure Arc enables organizations to deploy, govern, monitor, and manage Kubernetes clusters running:&lt;/P&gt;
&lt;UL data-start="777" data-end="892"&gt;
&lt;LI data-section-id="kh4cjm" data-start="777" data-end="790"&gt;On-premises&lt;/LI&gt;
&lt;LI data-section-id="10py7rb" data-start="791" data-end="804"&gt;At the edge&lt;/LI&gt;
&lt;LI data-section-id="131svgx" data-start="805" data-end="833"&gt;In multicloud environments&lt;/LI&gt;
&lt;LI data-section-id="xxmf6y" data-start="834" data-end="863"&gt;On virtualization platforms&lt;/LI&gt;
&lt;LI data-section-id="og2vx7" data-start="864" data-end="892"&gt;On physical infrastructure&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="894" data-end="925"&gt;In this guide, we will explore:&lt;/P&gt;
&lt;UL data-start="926" data-end="1144"&gt;
&lt;LI data-section-id="11dzh54" data-start="926" data-end="949"&gt;What Azure Arc AKS is&lt;/LI&gt;
&lt;LI data-section-id="1omdu9y" data-start="950" data-end="978"&gt;How the architecture works&lt;/LI&gt;
&lt;LI data-section-id="ee8krs" data-start="979" data-end="1011"&gt;Core infrastructure components&lt;/LI&gt;
&lt;LI data-section-id="1siqtlk" data-start="1012" data-end="1042"&gt;Step-by-step deployment flow&lt;/LI&gt;
&lt;LI data-section-id="rif47n" data-start="1043" data-end="1070"&gt;Networking considerations&lt;/LI&gt;
&lt;LI data-section-id="f99et" data-start="1071" data-end="1093"&gt;Operational insights&lt;/LI&gt;
&lt;LI data-section-id="ige9s6" data-start="1094" data-end="1144"&gt;Common challenges and troubleshooting approaches&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="fjleg9" data-start="1151" data-end="1195"&gt;Understanding the Problem Azure Arc Solves&lt;/H2&gt;
&lt;P data-start="1197" data-end="1314"&gt;Traditionally, Kubernetes management becomes fragmented when infrastructure exists outside public cloud environments.&lt;/P&gt;
&lt;P data-start="1316" data-end="1341"&gt;Organizations often face:&lt;/P&gt;
&lt;UL data-start="1342" data-end="1569"&gt;
&lt;LI data-section-id="gvekr" data-start="1342" data-end="1391"&gt;Separate tooling for on-prem and cloud clusters&lt;/LI&gt;
&lt;LI data-section-id="1hh25z5" data-start="1392" data-end="1417"&gt;Inconsistent governance&lt;/LI&gt;
&lt;LI data-section-id="1sd3pfd" data-start="1418" data-end="1449"&gt;Manual onboarding of clusters&lt;/LI&gt;
&lt;LI data-section-id="1e51i8d" data-start="1450" data-end="1479"&gt;Complex identity management&lt;/LI&gt;
&lt;LI data-section-id="1al36kq" data-start="1480" data-end="1528"&gt;Disconnected monitoring and policy enforcement&lt;/LI&gt;
&lt;LI data-section-id="1wm2du6" data-start="1529" data-end="1569"&gt;Operational overhead at edge locations&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1571" data-end="1674"&gt;Azure Arc addresses this by extending Azure management capabilities to infrastructure running anywhere.&lt;/P&gt;
&lt;P data-start="1676" data-end="1800"&gt;Instead of moving all infrastructure into Azure, Azure Arc brings Azure’s operational model to your existing infrastructure.&lt;/P&gt;
&lt;H2 data-section-id="dp1dvd" data-start="1807" data-end="1831"&gt;What is Azure Arc AKS?&lt;/H2&gt;
&lt;P data-start="1833" data-end="1955"&gt;Azure Arc-enabled Kubernetes allows Kubernetes clusters running outside Azure to become manageable resources inside Azure.&lt;/P&gt;
&lt;P data-start="1957" data-end="1968"&gt;This means:&lt;/P&gt;
&lt;UL data-start="1969" data-end="2172"&gt;
&lt;LI data-section-id="1jq6us7" data-start="1969" data-end="2006"&gt;Clusters appear inside Azure Portal&lt;/LI&gt;
&lt;LI data-section-id="1o2q47h" data-start="2007" data-end="2034"&gt;Azure RBAC can be applied&lt;/LI&gt;
&lt;LI data-section-id="t7g6bl" data-start="2035" data-end="2071"&gt;Policies can be enforced centrally&lt;/LI&gt;
&lt;LI data-section-id="1mri60b" data-start="2072" data-end="2119"&gt;Monitoring and governance become standardized&lt;/LI&gt;
&lt;LI data-section-id="1ok3m97" data-start="2120" data-end="2172"&gt;GitOps and extensions can be deployed consistently&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="2174" data-end="2317"&gt;AKS Arc extends this further by enabling an AKS-like Kubernetes deployment and lifecycle management experience on local or edge infrastructure.&lt;/P&gt;
&lt;H2 data-section-id="1lwh98m" data-start="2324" data-end="2349"&gt;High-Level Architecture&lt;/H2&gt;
&lt;P data-start="2351" data-end="2407"&gt;The deployment architecture typically follows this flow:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P data-start="2643" data-end="2659"&gt;At a high level:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th class="lia-align-center"&gt;Layer&lt;/th&gt;&lt;th class="lia-align-center"&gt;Purpose&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="lia-align-center"&gt;Infrastructure Layer&lt;/td&gt;&lt;td class="lia-align-center"&gt;Physical server or virtual machine&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="lia-align-center"&gt;Connectivity Layer&lt;/td&gt;&lt;td class="lia-align-center"&gt;Azure Arc agents and registration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="lia-align-center"&gt;Kubernetes Layer&lt;/td&gt;&lt;td class="lia-align-center"&gt;Kubernetes runtime and orchestration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="lia-align-center"&gt;Azure Integration Layer&lt;/td&gt;&lt;td class="lia-align-center"&gt;Governance, monitoring, policies&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="lia-align-center"&gt;Operations Layer&lt;/td&gt;&lt;td class="lia-align-center"&gt;Cluster lifecycle and workload management&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3 data-section-id="aetk3l" data-start="3006" data-end="3034"&gt;Core Components of AKS Arc&lt;/H3&gt;
&lt;P data-start="3036" data-end="3115"&gt;Before deployment, it is important to understand the major components involved.&lt;/P&gt;
&lt;H5 data-section-id="qi94wj" data-start="3122" data-end="3137"&gt;1. Azure Arc&lt;/H5&gt;
&lt;P data-start="3139" data-end="3238"&gt;Azure Arc acts as the bridge between Azure and external infrastructure.&lt;/P&gt;
&lt;P data-start="3240" data-end="3251"&gt;It enables:&lt;/P&gt;
&lt;UL data-start="3252" data-end="3375"&gt;
&lt;LI data-section-id="f9l62b" data-start="3252" data-end="3275"&gt;Resource registration&lt;/LI&gt;
&lt;LI data-section-id="1clmywa" data-start="3276" data-end="3295"&gt;Hybrid governance&lt;/LI&gt;
&lt;LI data-section-id="edeocs" data-start="3296" data-end="3316"&gt;Policy enforcement&lt;/LI&gt;
&lt;LI data-section-id="jqae90" data-start="3317" data-end="3329"&gt;Monitoring&lt;/LI&gt;
&lt;LI data-section-id="1up2gso" data-start="3330" data-end="3352"&gt;Extension deployment&lt;/LI&gt;
&lt;LI data-section-id="bstjrl" data-start="3353" data-end="3375"&gt;Inventory management&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5 data-section-id="1jdsms7" data-start="3382" data-end="3408"&gt;2. Arc-Enabled Machines&lt;/H5&gt;
&lt;P data-start="3410" data-end="3420"&gt;These are:&lt;/P&gt;
&lt;UL data-start="3421" data-end="3473"&gt;
&lt;LI data-section-id="nqwudn" data-start="3421" data-end="3439"&gt;Physical servers&lt;/LI&gt;
&lt;LI data-section-id="olznun" data-start="3440" data-end="3458"&gt;Virtual machines&lt;/LI&gt;
&lt;LI data-section-id="3gobq8" data-start="3459" data-end="3473"&gt;Edge devices&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="3475" data-end="3543"&gt;Once connected to Azure Arc, they become manageable Azure resources.&lt;/P&gt;
&lt;H5 data-section-id="lzl3f4" data-start="3550" data-end="3574"&gt;3. Kubernetes Cluster&lt;/H5&gt;
&lt;P data-start="3576" data-end="3606"&gt;The Kubernetes layer provides:&lt;/P&gt;
&lt;UL data-start="3607" data-end="3700"&gt;
&lt;LI data-section-id="krguxg" data-start="3607" data-end="3632"&gt;Container orchestration&lt;/LI&gt;
&lt;LI data-section-id="12s2yqw" data-start="3633" data-end="3645"&gt;Scheduling&lt;/LI&gt;
&lt;LI data-section-id="fhbifq" data-start="3646" data-end="3658"&gt;Networking&lt;/LI&gt;
&lt;LI data-section-id="1tzulud" data-start="3659" data-end="3668"&gt;Scaling&lt;/LI&gt;
&lt;LI data-section-id="1vd8rwq" data-start="3669" data-end="3700"&gt;Workload lifecycle management&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5 data-section-id="rfskz5" data-start="3707" data-end="3728"&gt;4. Custom Location&lt;/H5&gt;
&lt;P data-start="3730" data-end="3820"&gt;Custom Locations create a logical mapping between Azure resources and edge infrastructure.&lt;/P&gt;
&lt;P data-start="3822" data-end="3909"&gt;They allow Azure services to target workloads to specific on-prem or edge environments.&lt;/P&gt;
&lt;H5 data-section-id="1seohwa" data-start="3916" data-end="3933"&gt;5. Device Pool&lt;/H5&gt;
&lt;P data-start="3935" data-end="4003"&gt;A device pool groups machines participating in a cluster deployment.&lt;/P&gt;
&lt;P data-start="4005" data-end="4066"&gt;This becomes especially important in multi-node environments.&lt;/P&gt;
&lt;H5 data-section-id="dvk4xe" data-start="4073" data-end="4101"&gt;6. Logical Network (LNET)&lt;/H5&gt;
&lt;P data-start="4103" data-end="4131"&gt;The Logical Network defines:&lt;/P&gt;
&lt;UL data-start="4132" data-end="4207"&gt;
&lt;LI data-section-id="1wszun0" data-start="4132" data-end="4152"&gt;Cluster networking&lt;/LI&gt;
&lt;LI data-section-id="1ltd9ep" data-start="4153" data-end="4168"&gt;IP allocation&lt;/LI&gt;
&lt;LI data-section-id="1cjy0ww" data-start="4169" data-end="4192"&gt;Gateway configuration&lt;/LI&gt;
&lt;LI data-section-id="t45k4d" data-start="4193" data-end="4207"&gt;DNS behavior&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4209" data-end="4280"&gt;Networking is one of the most critical parts of any AKS Arc deployment.&lt;/P&gt;
&lt;H3 data-section-id="cjbzdo" data-start="4287" data-end="4330"&gt;Infrastructure Planning Before Deployment&lt;/H3&gt;
&lt;P data-start="4332" data-end="4398"&gt;Before starting deployment, infrastructure readiness is essential.&lt;/P&gt;
&lt;H4 data-section-id="b266xu" data-start="4405" data-end="4431"&gt;Hardware Recommendations&lt;/H4&gt;
&lt;P data-start="4433" data-end="4474"&gt;For a lab or proof-of-concept deployment:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;Recommended&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU&lt;/td&gt;&lt;td&gt;4+ vCPUs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RAM&lt;/td&gt;&lt;td&gt;16 GB minimum&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Disk&lt;/td&gt;&lt;td&gt;256 GB SSD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Network&lt;/td&gt;&lt;td&gt;Stable internet connectivity&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-start="4623" data-end="4650"&gt;For production deployments:&lt;/P&gt;
&lt;UL data-start="4651" data-end="4801"&gt;
&lt;LI data-section-id="1m7csgx" data-start="4651" data-end="4673"&gt;Redundant networking&lt;/LI&gt;
&lt;LI data-section-id="gs08sq" data-start="4674" data-end="4700"&gt;High-performance storage&lt;/LI&gt;
&lt;LI data-section-id="183resm" data-start="4701" data-end="4724"&gt;Multi-node clustering&lt;/LI&gt;
&lt;LI data-section-id="1d010z2" data-start="4725" data-end="4743"&gt;Power redundancy&lt;/LI&gt;
&lt;LI data-section-id="19zc7z3" data-start="4744" data-end="4773"&gt;Secure network segmentation&lt;/LI&gt;
&lt;LI data-section-id="vrrp5v" data-start="4774" data-end="4801"&gt;Monitoring infrastructure&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4803" data-end="4828"&gt;should all be considered.&lt;/P&gt;
&lt;H4 data-section-id="10dr634" data-start="4835" data-end="4871"&gt;Physical vs Virtual Infrastructure&lt;/H4&gt;
&lt;P data-start="4873" data-end="4895"&gt;AKS Arc supports both:&lt;/P&gt;
&lt;UL data-start="4896" data-end="4942"&gt;
&lt;LI data-section-id="1ujho1v" data-start="4896" data-end="4915"&gt;Physical hardware&lt;/LI&gt;
&lt;LI data-section-id="1l84vgd" data-start="4916" data-end="4942"&gt;Virtualized environments&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4944" data-end="4971"&gt;Many engineers begin using:&lt;/P&gt;
&lt;UL data-start="4972" data-end="5053"&gt;
&lt;LI data-section-id="1etlrsl" data-start="4972" data-end="5011"&gt;Hyper-V&lt;/LI&gt;
&lt;LI data-section-id="9xdms2" data-start="5012" data-end="5020"&gt;VMware&lt;/LI&gt;
&lt;LI data-section-id="e2aq7j" data-start="5021" data-end="5053"&gt;Other virtualization platforms&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="5055" data-end="5086"&gt;for lab simulation and testing.&lt;/P&gt;
&lt;H4 data-section-id="1d7cdzt" data-start="5093" data-end="5122"&gt;Virtual Machine Advantages&lt;/H4&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Benefit&lt;/th&gt;&lt;th&gt;Explanation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Faster setup&lt;/td&gt;&lt;td&gt;Easier experimentation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Lower cost&lt;/td&gt;&lt;td&gt;No dedicated hardware needed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flexible snapshots&lt;/td&gt;&lt;td&gt;Quick rollback capability&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Easier automation&lt;/td&gt;&lt;td&gt;Infrastructure reproducibility&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H4 data-section-id="1hq3w1i" data-start="5360" data-end="5391"&gt;Physical Hardware Advantages&lt;/H4&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Benefit&lt;/th&gt;&lt;th&gt;Explanation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Realistic edge testing&lt;/td&gt;&lt;td&gt;Accurate network behavior&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hardware validation&lt;/td&gt;&lt;td&gt;BIOS, TPM, drivers&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Production readiness&lt;/td&gt;&lt;td&gt;Real deployment conditions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-section-id="1rbfmqn" data-start="5589" data-end="5627"&gt;Step-by-Step AKS Arc Deployment Flow&lt;/H2&gt;
&lt;P data-start="5629" data-end="5678"&gt;Now let us walk through the deployment lifecycle.&lt;/P&gt;
&lt;H4 data-section-id="4usi1c" data-start="5685" data-end="5718"&gt;Step 1 – Prepare Infrastructure&lt;/H4&gt;
&lt;P data-start="5720" data-end="5739"&gt;Create or identify:&lt;/P&gt;
&lt;UL data-start="5740" data-end="5792"&gt;
&lt;LI data-section-id="nqwudn" data-start="5740" data-end="5758"&gt;Physical servers&lt;/LI&gt;
&lt;LI data-section-id="3gobq8" data-start="5759" data-end="5773"&gt;Edge devices&lt;/LI&gt;
&lt;LI data-section-id="olznun" data-start="5774" data-end="5792"&gt;Virtual machines&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="5794" data-end="5801"&gt;Ensure:&lt;/P&gt;
&lt;UL data-start="5802" data-end="5942"&gt;
&lt;LI data-section-id="1g56do6" data-start="5802" data-end="5832"&gt;Internet connectivity exists&lt;/LI&gt;
&lt;LI data-section-id="1banxur" data-start="5833" data-end="5866"&gt;Static IP planning is completed&lt;/LI&gt;
&lt;LI data-section-id="1qqr2w6" data-start="5867" data-end="5899"&gt;DNS resolution works correctly&lt;/LI&gt;
&lt;LI data-section-id="uiiqm3" data-start="5900" data-end="5942"&gt;Firewall rules allow Azure communication&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="1wn9cyw" data-start="5949" data-end="6007"&gt;Step 2 – Configure Virtualization Environment (Optional)&lt;/H3&gt;
&lt;P data-start="6009" data-end="6033"&gt;If using virtualization:&lt;/P&gt;
&lt;P data-start="6035" data-end="6042"&gt;Enable:&lt;/P&gt;
&lt;UL data-start="6043" data-end="6113"&gt;
&lt;LI data-section-id="tfyj74" data-start="6043" data-end="6064"&gt;Hypervisor platform&lt;/LI&gt;
&lt;LI data-section-id="113fwmv" data-start="6065" data-end="6085"&gt;Virtual networking&lt;/LI&gt;
&lt;LI data-section-id="zlhmvf" data-start="6086" data-end="6113"&gt;NAT or bridged networking&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="6115" data-end="6122"&gt;Create:&lt;/P&gt;
&lt;UL data-start="6123" data-end="6190"&gt;
&lt;LI data-section-id="1uh4yqk" data-start="6123" data-end="6148"&gt;Internal virtual switch&lt;/LI&gt;
&lt;LI data-section-id="c6syv5" data-start="6149" data-end="6171"&gt;DHCP-enabled network&lt;/LI&gt;
&lt;LI data-section-id="1hi5khb" data-start="6172" data-end="6190"&gt;Internet routing&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="6192" data-end="6281"&gt;A stable network configuration is critical because cluster deployment depends heavily on:&lt;/P&gt;
&lt;UL data-start="6282" data-end="6376"&gt;
&lt;LI data-section-id="p0lnow" data-start="6282" data-end="6301"&gt;API communication&lt;/LI&gt;
&lt;LI data-section-id="mx6uqo" data-start="6302" data-end="6322"&gt;Agent registration&lt;/LI&gt;
&lt;LI data-section-id="hn1mdy" data-start="6323" data-end="6344"&gt;Extension downloads&lt;/LI&gt;
&lt;LI data-section-id="1z9mh6" data-start="6345" data-end="6376"&gt;Kubernetes node communication&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="11m4wal" data-start="6383" data-end="6423"&gt;Step 3 – Install Operating Environment&lt;/H3&gt;
&lt;P data-start="6425" data-end="6482"&gt;Install the operating system image on the target machine.&lt;/P&gt;
&lt;P data-start="6484" data-end="6513"&gt;Typical requirements include:&lt;/P&gt;
&lt;UL data-start="6514" data-end="6650"&gt;
&lt;LI data-section-id="1nuy7hl" data-start="6514" data-end="6549"&gt;Linux-based edge operating system&lt;/LI&gt;
&lt;LI data-section-id="bf5br0" data-start="6550" data-end="6577"&gt;Container runtime support&lt;/LI&gt;
&lt;LI data-section-id="wdzqjz" data-start="6578" data-end="6604"&gt;Kubernetes prerequisites&lt;/LI&gt;
&lt;LI data-section-id="11r4mvg" data-start="6605" data-end="6633"&gt;Secure boot considerations&lt;/LI&gt;
&lt;LI data-section-id="5bu1e" data-start="6634" data-end="6650"&gt;TPM enablement&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="6652" data-end="6674"&gt;Recommended VM sizing:&lt;/P&gt;
&lt;UL data-start="6675" data-end="6726"&gt;
&lt;LI data-section-id="17dzm5w" data-start="6675" data-end="6686"&gt;16 GB RAM&lt;/LI&gt;
&lt;LI data-section-id="1xdchgv" data-start="6687" data-end="6709"&gt;4 processors minimum&lt;/LI&gt;
&lt;LI data-section-id="ujlntx" data-start="6710" data-end="6726"&gt;256 GB storage&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Get Image Reference to know where to Download Azure Local OS (ROE) and Azure Local Configurator App -&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="ssr3ug" data-start="6733" data-end="6779"&gt;Step 4 – Connect Infrastructure to Azure Arc&lt;/H3&gt;
&lt;P data-start="6781" data-end="6813"&gt;Once the machine is operational:&lt;/P&gt;
&lt;UL data-start="6814" data-end="6916"&gt;
&lt;LI data-section-id="94219c" data-start="6814" data-end="6851"&gt;Install Arc connectivity components&lt;/LI&gt;
&lt;LI data-section-id="1j7qzie" data-start="6852" data-end="6885"&gt;Register the machine with Azure&lt;/LI&gt;
&lt;LI data-section-id="bg5cfs" data-start="6886" data-end="6916"&gt;Verify successful onboarding&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="6918" data-end="6948"&gt;After successful registration:&lt;/P&gt;
&lt;UL data-start="6949" data-end="7047"&gt;
&lt;LI data-section-id="vh0vej" data-start="6949" data-end="6998"&gt;The machine becomes visible inside Azure Portal&lt;/LI&gt;
&lt;LI data-section-id="1m9ho5v" data-start="6999" data-end="7047"&gt;Azure governance capabilities become available&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="7049" data-end="7093"&gt;At this stage, the machine transitions from:&lt;/P&gt;
&lt;P data-start="7096" data-end="7123"&gt;“Standalone infrastructure”&lt;/P&gt;
&lt;P data-start="7125" data-end="7128"&gt;to:&lt;/P&gt;
&lt;P data-start="7132" data-end="7163"&gt;“Azure-managed hybrid resource”&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;
&lt;LI-CODE lang=""&gt;Login to Azure and Set Subscription

az login
az account set \
  --subscription "&amp;lt;subscription-id&amp;gt;"

Install Connected Machine Agent

#Install Azure Arc agent on Linux machine.
wget https://aka.ms/azcmagent -O ~/install_linux_azcmagent.sh
bash ~/install_linux_azcmagent.sh

Connect Machine to Azure Arc

#Register machine as Arc-enabled server.
sudo azcmagent connect \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --tenant-id "&amp;lt;tenant-id&amp;gt;" \
  --location "&amp;lt;azure-region&amp;gt;" \
  --subscription-id "&amp;lt;subscription-id&amp;gt;"

Verify Arc Agent Status

#Confirm successful Arc onboarding.
azcmagent show
Agent Status : Connected


Verify Arc Machine in Azure

#List Arc-enabled servers.
az connectedmachine list \ 
  --resource-group "&amp;lt;resource-group&amp;gt;"&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="muyrgt" data-start="7170" data-end="7206"&gt;Step 5 – Create the Azure Arc Site&lt;/H3&gt;
&lt;P data-start="7208" data-end="7275"&gt;The Arc Site acts as the logical container for edge infrastructure.&lt;/P&gt;
&lt;P data-start="7277" data-end="7290"&gt;During setup:&lt;/P&gt;
&lt;UL data-start="7291" data-end="7386"&gt;
&lt;LI data-section-id="9ustf" data-start="7291" data-end="7312"&gt;Select subscription&lt;/LI&gt;
&lt;LI data-section-id="12ydzvk" data-start="7313" data-end="7336"&gt;Choose resource group&lt;/LI&gt;
&lt;LI data-section-id="jblogl" data-start="7337" data-end="7352"&gt;Define region&lt;/LI&gt;
&lt;LI data-section-id="b96cnt" data-start="7353" data-end="7386"&gt;Register machines into the site&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="7388" data-end="7419"&gt;This enables Azure to organize:&lt;/P&gt;
&lt;UL data-start="7420" data-end="7498"&gt;
&lt;LI data-section-id="z5zsff" data-start="7420" data-end="7441"&gt;Provisioned devices&lt;/LI&gt;
&lt;LI data-section-id="l8u2oh" data-start="7442" data-end="7452"&gt;Clusters&lt;/LI&gt;
&lt;LI data-section-id="v6bfhr" data-start="7453" data-end="7475"&gt;Networking resources&lt;/LI&gt;
&lt;LI data-section-id="knwc71" data-start="7476" data-end="7498"&gt;Operational metadata&lt;/LI&gt;
&lt;/UL&gt;
&lt;LI-CODE lang=""&gt;Create Resource Group

#Logical container for Arc resources.
az group create \
  --name "&amp;lt;resource-group&amp;gt;" \
  --location "&amp;lt;azure-region&amp;gt;"


Register Required Providers

#Enable Arc and AKS Arc services.
az provider register --namespace Microsoft.HybridCompute
az provider register --namespace Microsoft.Kubernetes
az provider register --namespace Microsoft.KubernetesConfiguration
az provider register --namespace Microsoft.ExtendedLocation
az provider register --namespace Microsoft.ResourceConnector
az provider register --namespace Microsoft.ContainerService


Verify Provider Registration

#Ensure providers are fully available.
az provider show \
  --namespace Microsoft.Kubernetes \
  --query registrationState


Install Arc Extensions

#Enable AKS Arc management capabilities.
az extension add --name connectedk8s
az extension add --name customlocation
az extension add --name k8s-extension
az extension add --name aksarc


Create Custom Location

#Map Azure services to edge infrastructure.
az customlocation create \
  --name "&amp;lt;custom-location-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --host-resource-id "&amp;lt;connected-cluster-resource-id&amp;gt;" \
  --namespace "&amp;lt;namespace&amp;gt;" \
  --cluster-extension-ids "&amp;lt;extension-id&amp;gt;"


&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="nvws37" data-start="7505" data-end="7540"&gt;Step 6 – Verify Machine Readiness&lt;/H3&gt;
&lt;P data-start="7542" data-end="7559"&gt;After onboarding:&lt;/P&gt;
&lt;UL data-start="7560" data-end="7670"&gt;
&lt;LI data-section-id="jg6rdj" data-start="7560" data-end="7591"&gt;Machines undergo provisioning&lt;/LI&gt;
&lt;LI data-section-id="1m07fey" data-start="7592" data-end="7611"&gt;Agents initialize&lt;/LI&gt;
&lt;LI data-section-id="d1bmxp" data-start="7612" data-end="7644"&gt;Connectivity validation occurs&lt;/LI&gt;
&lt;LI data-section-id="1jw63em" data-start="7645" data-end="7670"&gt;Extensions are deployed&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="7672" data-end="7731"&gt;Eventually the machine reaches a healthy operational state.&lt;/P&gt;
&lt;P data-start="7733" data-end="7752"&gt;Typical indicators:&lt;/P&gt;
&lt;UL data-start="7753" data-end="7790"&gt;
&lt;LI data-section-id="279fiv" data-start="7753" data-end="7764"&gt;Connected&lt;/LI&gt;
&lt;LI data-section-id="179ha6b" data-start="7765" data-end="7772"&gt;Ready&lt;/LI&gt;
&lt;LI data-section-id="16qgd07" data-start="7773" data-end="7790"&gt;Cluster-capable&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="7792" data-end="7846"&gt;Provisioning time may vary significantly depending on:&lt;/P&gt;
&lt;UL data-start="7847" data-end="7948"&gt;
&lt;LI data-section-id="autmjf" data-start="7847" data-end="7864"&gt;Network quality&lt;/LI&gt;
&lt;LI data-section-id="ki2mvi" data-start="7865" data-end="7887"&gt;Hardware performance&lt;/LI&gt;
&lt;LI data-section-id="1km1oe0" data-start="7888" data-end="7917"&gt;Extension installation time&lt;/LI&gt;
&lt;LI data-section-id="utzz1h" data-start="7918" data-end="7948"&gt;Azure synchronization delays&lt;/LI&gt;
&lt;/UL&gt;
&lt;LI-CODE lang=""&gt;Check Arc Machine Connectivity

#Verify machine connection status.
az connectedmachine show \
  --name "&amp;lt;machine-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;"

#Look for:
#status : Connected&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="1f9c35t" data-start="7955" data-end="7992"&gt;Step 7 – Deploy the AKS Arc Cluster&lt;/H3&gt;
&lt;P data-start="7994" data-end="8049"&gt;Once infrastructure is ready:&lt;BR /&gt;begin cluster deployment.&lt;/P&gt;
&lt;P data-start="8051" data-end="8093"&gt;Deployment configuration usually includes:&lt;/P&gt;
&lt;UL data-start="8094" data-end="8209"&gt;
&lt;LI data-section-id="r5m8bp" data-start="8094" data-end="8108"&gt;Cluster name&lt;/LI&gt;
&lt;LI data-section-id="1yvcs88" data-start="8109" data-end="8125"&gt;Node selection&lt;/LI&gt;
&lt;LI data-section-id="16gc1uu" data-start="8126" data-end="8152"&gt;Networking configuration&lt;/LI&gt;
&lt;LI data-section-id="1yp6rpe" data-start="8153" data-end="8168"&gt;IP assignment&lt;/LI&gt;
&lt;LI data-section-id="1lmic01" data-start="8169" data-end="8188"&gt;DNS configuration&lt;/LI&gt;
&lt;LI data-section-id="1591g1x" data-start="8189" data-end="8209"&gt;Gateway definition&lt;/LI&gt;
&lt;/UL&gt;
&lt;LI-CODE lang=""&gt;Create Logical Network (LNET)

#Define networking for AKS Arc cluster.
az aksarc network create \
  --name "&amp;lt;lnet-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;"


Create AKS Arc Cluster

#Deploy Kubernetes cluster on Arc infrastructure.
az aksarc create \
  --name "&amp;lt;cluster-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --custom-location "&amp;lt;custom-location-id&amp;gt;" \
  --vnet-ids "&amp;lt;logical-network-id&amp;gt;"


Verify Kubernetes Connectivity

#Check Arc-enabled Kubernetes status.
az connectedk8s list \
  --resource-group "&amp;lt;resource-group&amp;gt;"

Check Installed Extensions

#Validate required Arc extensions.
az k8s-extension list \
  --cluster-name "&amp;lt;cluster-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --cluster-type connectedClusters


Check Node Readiness

#Validate Kubernetes node health.
kubectl get nodes&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="pif6ue" data-start="8216" data-end="8253"&gt;Understanding Networking Parameters&lt;/H3&gt;
&lt;P data-start="8255" data-end="8326"&gt;Networking is often the most misunderstood area in AKS Arc deployments.&lt;/P&gt;
&lt;P data-start="8328" data-end="8369"&gt;Let us simplify the important parameters.&lt;/P&gt;
&lt;H4&gt;Subnet&lt;/H4&gt;
&lt;P data-start="8387" data-end="8416"&gt;Defines the IP range used by:&lt;/P&gt;
&lt;UL data-start="8417" data-end="8479"&gt;
&lt;LI data-section-id="1qhiux" data-start="8417" data-end="8435"&gt;Kubernetes nodes&lt;/LI&gt;
&lt;LI data-section-id="1ohe2y4" data-start="8436" data-end="8454"&gt;Cluster services&lt;/LI&gt;
&lt;LI data-section-id="rn0npr" data-start="8455" data-end="8479"&gt;Internal communication&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="8481" data-end="8489"&gt;Example:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;192.168.1.0/24&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H4 data-section-id="1nnffbt" data-start="8523" data-end="8536"&gt;DNS Server&lt;/H4&gt;
&lt;P data-start="8538" data-end="8547"&gt;Used for:&lt;/P&gt;
&lt;UL data-start="8548" data-end="8637"&gt;
&lt;LI data-section-id="4haqu9" data-start="8548" data-end="8565"&gt;Name resolution&lt;/LI&gt;
&lt;LI data-section-id="mgpuic" data-start="8566" data-end="8586"&gt;Azure connectivity&lt;/LI&gt;
&lt;LI data-section-id="ily5ed" data-start="8587" data-end="8606"&gt;Package downloads&lt;/LI&gt;
&lt;LI data-section-id="frwrul" data-start="8607" data-end="8637"&gt;Kubernetes service discovery&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="8639" data-end="8659"&gt;Public DNS examples:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;8.8.8.8&lt;BR /&gt;1.1.1.1&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-start="8689" data-end="8751"&gt;Production environments typically use internal enterprise DNS.&lt;/P&gt;
&lt;H4 data-section-id="kpve8m" data-start="8758" data-end="8776"&gt;Default Gateway&lt;/H4&gt;
&lt;P data-start="8778" data-end="8830"&gt;The gateway routes traffic outside the local subnet.&lt;/P&gt;
&lt;P data-start="8832" data-end="8870"&gt;Without correct gateway configuration:&lt;/P&gt;
&lt;UL data-start="8871" data-end="8959"&gt;
&lt;LI data-section-id="pascat" data-start="8871" data-end="8897"&gt;Azure connectivity fails&lt;/LI&gt;
&lt;LI data-section-id="mdi7dp" data-start="8898" data-end="8926"&gt;Agent communication breaks&lt;/LI&gt;
&lt;LI data-section-id="14virko" data-start="8927" data-end="8959"&gt;Cluster provisioning may stall&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4 data-section-id="1gpkrx8" data-start="8966" data-end="8976"&gt;Host IP&lt;/H4&gt;
&lt;P data-start="8978" data-end="9019"&gt;Each machine requires a unique static IP.&lt;/P&gt;
&lt;P data-start="9021" data-end="9040"&gt;This IP identifies:&lt;/P&gt;
&lt;UL data-start="9041" data-end="9107"&gt;
&lt;LI data-section-id="1qhiux" data-start="9041" data-end="9059"&gt;Kubernetes nodes&lt;/LI&gt;
&lt;LI data-section-id="17t5ssx" data-start="9060" data-end="9075"&gt;Cluster hosts&lt;/LI&gt;
&lt;LI data-section-id="1bcu38c" data-start="9076" data-end="9107"&gt;Edge infrastructure endpoints&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4 data-section-id="tlagml" data-start="9114" data-end="9133"&gt;Control Plane IP&lt;/H4&gt;
&lt;P data-start="9135" data-end="9188"&gt;The Kubernetes API server requires a stable endpoint.&lt;/P&gt;
&lt;P data-start="9190" data-end="9242"&gt;This becomes the cluster management address used by:&lt;/P&gt;
&lt;UL data-start="9243" data-end="9287"&gt;
&lt;LI data-section-id="1r9sa4q" data-start="9243" data-end="9252"&gt;kubectl&lt;/LI&gt;
&lt;LI data-section-id="1o1o398" data-start="9253" data-end="9271"&gt;automation tools&lt;/LI&gt;
&lt;LI data-section-id="kfco0s" data-start="9272" data-end="9287"&gt;CI/CD systems&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="6cuwik" data-start="9294" data-end="9325"&gt;Step 8 – Cluster Provisioning by Azure&amp;nbsp;&lt;/H3&gt;
&lt;P data-start="9327" data-end="9365"&gt;Once deployment begins, Azure creates:&lt;/P&gt;
&lt;UL data-start="9366" data-end="9487"&gt;
&lt;LI data-section-id="1gccy5b" data-start="9366" data-end="9380"&gt;Device pools&lt;/LI&gt;
&lt;LI data-section-id="1gjbklx" data-start="9381" data-end="9399"&gt;Custom locations&lt;/LI&gt;
&lt;LI data-section-id="5zzsqu" data-start="9400" data-end="9418"&gt;Logical networks&lt;/LI&gt;
&lt;LI data-section-id="42gz42" data-start="9419" data-end="9455"&gt;Kubernetes control plane resources&lt;/LI&gt;
&lt;LI data-section-id="1cv0xol" data-start="9456" data-end="9487"&gt;Cluster integration resources&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="9489" data-end="9511"&gt;Provisioning can take:&lt;/P&gt;
&lt;UL data-start="9512" data-end="9551"&gt;
&lt;LI data-section-id="10i1g89" data-start="9512" data-end="9551"&gt;1 to 2 hours depending on environment&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="9553" data-end="9599"&gt;This duration surprises many first-time users.&lt;/P&gt;
&lt;P data-start="9601" data-end="9654"&gt;Unlike cloud-native AKS:&lt;BR /&gt;AKS Arc deployments involve:&lt;/P&gt;
&lt;UL data-start="9655" data-end="9779"&gt;
&lt;LI data-section-id="1qdtdnv" data-start="9655" data-end="9676"&gt;Hybrid coordination&lt;/LI&gt;
&lt;LI data-section-id="121001w" data-start="9677" data-end="9704"&gt;Infrastructure validation&lt;/LI&gt;
&lt;LI data-section-id="utwb09" data-start="9705" data-end="9727"&gt;Edge synchronization&lt;/LI&gt;
&lt;LI data-section-id="kdzfm0" data-start="9728" data-end="9746"&gt;Agent deployment&lt;/LI&gt;
&lt;LI data-section-id="ex6pfv" data-start="9747" data-end="9779"&gt;Local networking configuration&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="37qexy" data-start="9786" data-end="9824"&gt;Step 9 – Verify Cluster Connectivity&lt;/H3&gt;
&lt;P data-start="9826" data-end="9866"&gt;After deployment:&lt;BR /&gt;verify cluster health.&lt;/P&gt;
&lt;P data-start="9868" data-end="9892"&gt;Common validation steps:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;az aksarc get-credentials \
--name &amp;lt;cluster-name&amp;gt; \
--resource-group &amp;lt;resource-group&amp;gt;&lt;/LI-CODE&gt;
&lt;P data-start="9997" data-end="10043"&gt;This retrieves Kubernetes credentials locally.&lt;/P&gt;
&lt;P data-start="10050" data-end="10068"&gt;Then verify nodes:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;kubectl get nodes&lt;/LI-CODE&gt;
&lt;P data-start="10101" data-end="10132"&gt;Healthy output typically shows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;STATUS = Ready&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-start="10162" data-end="10190"&gt;for all participating nodes.&lt;/P&gt;
&lt;H2 data-section-id="6j9rmi" data-start="10197" data-end="10230"&gt;Operational Benefits of AKS Arc&lt;/H2&gt;
&lt;P data-start="10232" data-end="10292"&gt;Once operational, AKS Arc provides several major advantages.&lt;/P&gt;
&lt;H3 data-section-id="dt1ry1" data-start="10299" data-end="10323"&gt;Centralized Governance&lt;/H3&gt;
&lt;P data-start="10325" data-end="10344"&gt;Using Azure Policy:&lt;/P&gt;
&lt;UL data-start="10345" data-end="10424"&gt;
&lt;LI data-section-id="efp9na" data-start="10345" data-end="10365"&gt;Security baselines&lt;/LI&gt;
&lt;LI data-section-id="1yennrc" data-start="10366" data-end="10384"&gt;Compliance rules&lt;/LI&gt;
&lt;LI data-section-id="ujsl05" data-start="10385" data-end="10404"&gt;Tagging standards&lt;/LI&gt;
&lt;LI data-section-id="z2sgfq" data-start="10405" data-end="10424"&gt;Resource controls&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="10426" data-end="10455"&gt;can be enforced consistently.&lt;/P&gt;
&lt;H3 data-section-id="1fun186" data-start="10462" data-end="10482"&gt;Unified Monitoring&lt;/H3&gt;
&lt;P data-start="10484" data-end="10501"&gt;Integration with:&lt;/P&gt;
&lt;UL data-start="10502" data-end="10554"&gt;
&lt;LI data-section-id="1rbp5z1" data-start="10502" data-end="10517"&gt;Azure Monitor&lt;/LI&gt;
&lt;LI data-section-id="15ynm8q" data-start="10518" data-end="10538"&gt;Container Insights&lt;/LI&gt;
&lt;LI data-section-id="pg3mqi" data-start="10539" data-end="10554"&gt;Log Analytics&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="10556" data-end="10622"&gt;provides operational visibility across distributed infrastructure.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;az k8s-extension create \
  --name azuremonitor-containers \
  --cluster-name "&amp;lt;cluster-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --cluster-type connectedClusters \
  --extension-type Microsoft.AzureMonitor.Containers&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="1xyqznq" data-start="10629" data-end="10655"&gt;GitOps-Based Deployments&lt;/H3&gt;
&lt;P data-start="10657" data-end="10697"&gt;AKS Arc supports GitOps workflows where:&lt;/P&gt;
&lt;UL data-start="10698" data-end="10758"&gt;
&lt;LI data-section-id="1t3wzdi" data-start="10698" data-end="10720"&gt;Kubernetes manifests&lt;/LI&gt;
&lt;LI data-section-id="t9wvej" data-start="10721" data-end="10734"&gt;Helm charts&lt;/LI&gt;
&lt;LI data-section-id="1dtspga" data-start="10735" data-end="10758"&gt;Configuration updates&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="10760" data-end="10816"&gt;can be synchronized automatically from Git repositories.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;az k8s-configuration flux create \
  --cluster-name "&amp;lt;cluster-name&amp;gt;" \
  --resource-group "&amp;lt;resource-group&amp;gt;" \
  --name "&amp;lt;gitops-config&amp;gt;"&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3 data-section-id="hkepes" data-start="10823" data-end="10843"&gt;Hybrid Consistency&lt;/H3&gt;
&lt;P data-start="10845" data-end="10891"&gt;Teams can operate Kubernetes similarly across:&lt;/P&gt;
&lt;UL data-start="10892" data-end="10939"&gt;
&lt;LI data-section-id="cz545c" data-start="10892" data-end="10905"&gt;Azure cloud&lt;/LI&gt;
&lt;LI data-section-id="kh4cjm" data-start="10906" data-end="10919"&gt;On-premises&lt;/LI&gt;
&lt;LI data-section-id="b2pswd" data-start="10920" data-end="10939"&gt;Edge environments&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="10941" data-end="10980"&gt;This reduces operational fragmentation.&lt;/P&gt;
&lt;H2 data-section-id="1ut8ri7" data-start="10987" data-end="11029"&gt;Common Challenges in AKS Arc Deployments&lt;/H2&gt;
&lt;P data-start="11031" data-end="11078"&gt;Real-world deployments are rarely frictionless.&lt;/P&gt;
&lt;P data-start="11080" data-end="11137"&gt;Here are some practical issues engineers often encounter.&lt;/P&gt;
&lt;H3 data-section-id="bjyijk" data-start="11144" data-end="11176"&gt;1. Networking Misconfiguration&lt;/H3&gt;
&lt;P data-start="11178" data-end="11187"&gt;Symptoms:&lt;/P&gt;
&lt;UL data-start="11188" data-end="11252"&gt;
&lt;LI data-section-id="b3nxy3" data-start="11188" data-end="11208"&gt;Provisioning stuck&lt;/LI&gt;
&lt;LI data-section-id="1harq6h" data-start="11209" data-end="11233"&gt;Cluster not connecting&lt;/LI&gt;
&lt;LI data-section-id="1ph9zzw" data-start="11234" data-end="11252"&gt;Agents unhealthy&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="11254" data-end="11266"&gt;Root causes:&lt;/P&gt;
&lt;UL data-start="11267" data-end="11342"&gt;
&lt;LI data-section-id="15rybze" data-start="11267" data-end="11285"&gt;Incorrect subnet&lt;/LI&gt;
&lt;LI data-section-id="6auc1t" data-start="11286" data-end="11303"&gt;Invalid gateway&lt;/LI&gt;
&lt;LI data-section-id="1quvqf6" data-start="11304" data-end="11318"&gt;DNS failures&lt;/LI&gt;
&lt;LI data-section-id="sjkqe9" data-start="11319" data-end="11342"&gt;Firewall restrictions&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="10t2z1w" data-start="11349" data-end="11371"&gt;2. Slow Provisioning&lt;/H3&gt;
&lt;P data-start="11373" data-end="11404"&gt;Provisioning delays are common.&lt;/P&gt;
&lt;P data-start="11406" data-end="11422"&gt;Reasons include:&lt;/P&gt;
&lt;UL data-start="11423" data-end="11528"&gt;
&lt;LI data-section-id="1vwzrh9" data-start="11423" data-end="11450"&gt;Extension deployment time&lt;/LI&gt;
&lt;LI data-section-id="lwvdbc" data-start="11451" data-end="11468"&gt;Image downloads&lt;/LI&gt;
&lt;LI data-section-id="1gy3l2e" data-start="11469" data-end="11496"&gt;Edge connectivity latency&lt;/LI&gt;
&lt;LI data-section-id="1i6j1vj" data-start="11497" data-end="11528"&gt;Infrastructure initialization&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="11530" data-end="11583"&gt;Patience becomes important during initial deployment.&lt;/P&gt;
&lt;H3 data-section-id="xlhdhj" data-start="11590" data-end="11615"&gt;3. Resource Constraints&lt;/H3&gt;
&lt;P data-start="11617" data-end="11630"&gt;Insufficient:&lt;/P&gt;
&lt;UL data-start="11631" data-end="11652"&gt;
&lt;LI data-section-id="1o4tjq" data-start="11631" data-end="11636"&gt;RAM&lt;/LI&gt;
&lt;LI data-section-id="1o4e26" data-start="11637" data-end="11642"&gt;CPU&lt;/LI&gt;
&lt;LI data-section-id="1p4gu1d" data-start="11643" data-end="11652"&gt;Storage&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="11654" data-end="11697"&gt;can destabilize the Kubernetes environment.&lt;/P&gt;
&lt;P data-start="11699" data-end="11762"&gt;Edge clusters still require enterprise-grade resource planning.&lt;/P&gt;
&lt;H3 data-section-id="31dc02" data-start="11769" data-end="11801"&gt;4. Hybrid Debugging Complexity&lt;/H3&gt;
&lt;P data-start="11803" data-end="11825"&gt;Troubleshooting spans:&lt;/P&gt;
&lt;UL data-start="11826" data-end="11895"&gt;
&lt;LI data-section-id="16ywf75" data-start="11826" data-end="11833"&gt;Azure&lt;/LI&gt;
&lt;LI data-section-id="1hb2fca" data-start="11834" data-end="11846"&gt;Kubernetes&lt;/LI&gt;
&lt;LI data-section-id="fhbifq" data-start="11847" data-end="11859"&gt;Networking&lt;/LI&gt;
&lt;LI data-section-id="z408si" data-start="11860" data-end="11882"&gt;Local infrastructure&lt;/LI&gt;
&lt;LI data-section-id="piehxu" data-start="11883" data-end="11895"&gt;Arc agents&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="11897" data-end="11951"&gt;This requires multidisciplinary operational knowledge.&lt;/P&gt;
&lt;H2 data-section-id="kky646" data-start="11958" data-end="11998"&gt;Best Practices for AKS Arc Deployments&lt;/H2&gt;
&lt;H3 data-section-id="1ca0z1n" data-start="12005" data-end="12029"&gt;Plan Networking Early&lt;/H3&gt;
&lt;P data-start="12031" data-end="12086"&gt;Most deployment issues originate from poor IP planning.&lt;/P&gt;
&lt;P data-start="12088" data-end="12097"&gt;Document:&lt;/P&gt;
&lt;UL data-start="12098" data-end="12148"&gt;
&lt;LI data-section-id="1l2c08w" data-start="12098" data-end="12107"&gt;Subnets&lt;/LI&gt;
&lt;LI data-section-id="1o4e9d" data-start="12108" data-end="12113"&gt;DNS&lt;/LI&gt;
&lt;LI data-section-id="a2ymub" data-start="12114" data-end="12124"&gt;Gateways&lt;/LI&gt;
&lt;LI data-section-id="1lpdutm" data-start="12125" data-end="12148"&gt;Static IP allocations&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="12150" data-end="12175"&gt;before deployment begins.&lt;/P&gt;
&lt;H3 data-section-id="1c49g24" data-start="12182" data-end="12212"&gt;Start with Single-Node Labs&lt;/H3&gt;
&lt;P data-start="12214" data-end="12226"&gt;Begin small:&lt;/P&gt;
&lt;UL data-start="12227" data-end="12303"&gt;
&lt;LI data-section-id="1449diz" data-start="12227" data-end="12250"&gt;Validate architecture&lt;/LI&gt;
&lt;LI data-section-id="1f60tef" data-start="12251" data-end="12274"&gt;Learn deployment flow&lt;/LI&gt;
&lt;LI data-section-id="1c0fpqz" data-start="12275" data-end="12303"&gt;Test operational processes&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="12305" data-end="12349"&gt;Then scale toward production-grade clusters.&lt;/P&gt;
&lt;H3 data-section-id="6ouqw8" data-start="12356" data-end="12377"&gt;Monitor Everything&lt;/H3&gt;
&lt;P data-start="12379" data-end="12387"&gt;Collect:&lt;/P&gt;
&lt;UL data-start="12388" data-end="12460"&gt;
&lt;LI data-section-id="8tqeai" data-start="12388" data-end="12401"&gt;System logs&lt;/LI&gt;
&lt;LI data-section-id="1tr3o45" data-start="12402" data-end="12421"&gt;Kubernetes events&lt;/LI&gt;
&lt;LI data-section-id="1kshp9y" data-start="12422" data-end="12438"&gt;Arc agent logs&lt;/LI&gt;
&lt;LI data-section-id="9c7naa" data-start="12439" data-end="12460"&gt;Network diagnostics&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="12462" data-end="12511"&gt;Hybrid environments require strong observability.&lt;/P&gt;
&lt;H3 data-section-id="1jdva3j" data-start="12518" data-end="12562"&gt;Treat Edge Like Production Infrastructure&lt;/H3&gt;
&lt;P data-start="12564" data-end="12603"&gt;Even lab environments should implement:&lt;/P&gt;
&lt;UL data-start="12604" data-end="12683"&gt;
&lt;LI data-section-id="d2hv9m" data-start="12604" data-end="12623"&gt;Security controls&lt;/LI&gt;
&lt;LI data-section-id="32sb1" data-start="12624" data-end="12645"&gt;Identity management&lt;/LI&gt;
&lt;LI data-section-id="15j0o4b" data-start="12646" data-end="12663"&gt;Backup planning&lt;/LI&gt;
&lt;LI data-section-id="uv89gi" data-start="12664" data-end="12683"&gt;Access governance&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="dqht4n" data-start="12690" data-end="12712"&gt;Real-World Use Cases&lt;/H3&gt;
&lt;P data-start="12714" data-end="12813"&gt;AKS Arc is especially valuable in environments where low latency or disconnected operations matter.&lt;/P&gt;
&lt;P data-start="12815" data-end="12832"&gt;Examples include:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Industry&lt;/th&gt;&lt;th&gt;Use Case&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Manufacturing&lt;/td&gt;&lt;td&gt;Factory automation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Retail&lt;/td&gt;&lt;td&gt;Store analytics&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Energy&lt;/td&gt;&lt;td&gt;Remote substations&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Healthcare&lt;/td&gt;&lt;td&gt;Local processing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Logistics&lt;/td&gt;&lt;td&gt;Warehouse orchestration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Telecom&lt;/td&gt;&lt;td&gt;Edge compute platforms&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3 data-section-id="1329ug4" data-start="13085" data-end="13101"&gt;Final Thoughts&lt;/H3&gt;
&lt;P data-start="13103" data-end="13219"&gt;Azure Arc fundamentally changes how organizations think about infrastructure management.&lt;/P&gt;
&lt;P data-start="13221" data-end="13368"&gt;Instead of forcing workloads entirely into the cloud, Azure Arc extends Azure’s operational capabilities to wherever infrastructure already exists.&lt;/P&gt;
&lt;P data-start="13370" data-end="13442"&gt;Combined with Azure Kubernetes Service, organizations gain:&lt;/P&gt;
&lt;UL data-start="13443" data-end="13591"&gt;
&lt;LI data-section-id="m38zic" data-start="13443" data-end="13467"&gt;Kubernetes consistency&lt;/LI&gt;
&lt;LI data-section-id="1clmywa" data-start="13468" data-end="13487"&gt;Hybrid governance&lt;/LI&gt;
&lt;LI data-section-id="j0hglb" data-start="13488" data-end="13512"&gt;Centralized operations&lt;/LI&gt;
&lt;LI data-section-id="uirybm" data-start="13513" data-end="13541"&gt;Edge deployment capability&lt;/LI&gt;
&lt;LI data-section-id="1t3pfoy" data-start="13542" data-end="13591"&gt;Cloud-native management beyond cloud boundaries&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="13593" data-end="13729" data-is-last-node="" data-is-only-node=""&gt;As edge computing adoption grows, AKS Arc is becoming an increasingly important platform for modern hybrid infrastructure architectures.&lt;/P&gt;
&lt;P data-start="2351" data-end="2407"&gt;Azure Arc extends Azure management capabilities beyond Azure cloud boundaries, while AKS Arc enables Kubernetes clusters to run consistently across edge, on-premises, and hybrid environments.&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;Tags:&amp;nbsp;&lt;/P&gt;
&lt;P data-pm-slice="1 1 []"&gt;Azure Arc&lt;BR /&gt;Azure Kubernetes Service&lt;BR /&gt;Azure Arc AKS&lt;BR /&gt;Hybrid Cloud&lt;BR /&gt;Edge Computing&lt;BR /&gt;Azure Local&lt;/P&gt;</description>
      <pubDate>Tue, 12 May 2026 02:57:30 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/azure-arc-aks-explained-run-kubernetes-beyond-azure-cloud/ba-p/4518443</guid>
      <dc:creator>mohit-kanojia</dc:creator>
      <dc:date>2026-05-12T02:57:30Z</dc:date>
    </item>
    <item>
      <title>Scaling GitHub Advanced Security in Azure DevOps with a single reusable YAML template</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/scaling-github-advanced-security-in-azure-devops-with-a-single/ba-p/4518410</link>
      <description>&lt;H2&gt;Scaling GitHub Advanced Security in Azure DevOps with a single reusable YAML template&lt;/H2&gt;
&lt;P&gt;Managing security scanning across dozens of repositories can quickly become complex—especially when each repository uses different languages, frameworks, and infrastructure patterns.&lt;/P&gt;
&lt;P&gt;In our environment, we needed a scalable way to apply &lt;STRONG&gt;GitHub Advanced Security (GHAS)&lt;/STRONG&gt; consistently across:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Application code (Python, C#, Java, JavaScript)&lt;/LI&gt;
&lt;LI&gt;Infrastructure as Code (Terraform, ARM, Bicep)&lt;/LI&gt;
&lt;LI&gt;Mixed (polyglot) repositories&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Instead of maintaining multiple pipelines, we built a &lt;STRONG&gt;single reusable Azure DevOps YAML template&lt;/STRONG&gt; that dynamically adapts to any repository.&lt;/P&gt;
&lt;H2&gt;The problem&lt;/H2&gt;
&lt;P&gt;Most teams struggle with:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Multiple pipelines for different tech stacks&lt;/LI&gt;
&lt;LI&gt;Inconsistent security coverage&lt;/LI&gt;
&lt;LI&gt;Maintenance overhead across repositories&lt;/LI&gt;
&lt;LI&gt;Unnecessary scans increasing build time&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;We needed a solution that:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Detects repository content automatically&lt;/LI&gt;
&lt;LI&gt;Runs only relevant scans&lt;/LI&gt;
&lt;LI&gt;Standardizes security across all repos&lt;/LI&gt;
&lt;LI&gt;Minimizes duplication&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Solution overview&lt;/H2&gt;
&lt;P&gt;The solution is a &lt;STRONG&gt;single-stage pipeline template&lt;/STRONG&gt; with three key jobs:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Detect repository content&lt;/LI&gt;
&lt;LI&gt;Run CodeQL for application code&lt;/LI&gt;
&lt;LI&gt;Run IaC security scanning&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Scanning behavior is driven entirely by detection outputs.&lt;/P&gt;
&lt;H2&gt;Architecture&lt;/H2&gt;
&lt;H3&gt;🟦 High-level flow&lt;/H3&gt;
&lt;img /&gt;&lt;img /&gt;
&lt;H2&gt;Key design patterns&lt;/H2&gt;
&lt;H3&gt;1. Detection-driven execution&lt;/H3&gt;
&lt;P&gt;Instead of hardcoding logic, the pipeline first detects repository content.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;✅ Runs only when code is present&lt;BR /&gt;✅ Avoids unnecessary execution&lt;/P&gt;
&lt;H3&gt;2. Single template for all repositories&lt;/H3&gt;
&lt;P&gt;A single YAML template works for:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Backend services&lt;/LI&gt;
&lt;LI&gt;Frontend apps&lt;/LI&gt;
&lt;LI&gt;IaC repositories&lt;/LI&gt;
&lt;LI&gt;Mixed projects&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;No duplication. No branching logic across repos.&lt;/P&gt;
&lt;H3&gt;3. Dynamic CodeQL configuration&lt;/H3&gt;
&lt;P&gt;The pipeline generates a &lt;STRONG&gt;runtime CodeQL config file&lt;/STRONG&gt;:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;✅ Keeps configuration centralized&lt;BR /&gt;✅ Avoids scan failures due to irrelevant directories&lt;/P&gt;
&lt;H3&gt;4. Language-aware setup&lt;/H3&gt;
&lt;P&gt;The pipeline dynamically prepares environments:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;✅ No need for separate pipelines&lt;BR /&gt;✅ Works across polyglot repos&lt;/P&gt;
&lt;H3&gt;5. Correct CodeQL build strategy&lt;/H3&gt;
&lt;P&gt;For compiled languages like C#, the pipeline performs build tracing:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;✅ Ensures proper CodeQL extraction&lt;BR /&gt;✅ Avoids empty-database failures&lt;/P&gt;
&lt;H3&gt;6. Integrated IaC security scanning&lt;/H3&gt;
&lt;P&gt;Infrastructure scanning is handled in the same pipeline:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;✅ Covers Terraform, ARM, Bicep&lt;BR /&gt;✅ Unified reporting across code and infrastructure&lt;/P&gt;
&lt;H3&gt;7. Centralized reporting&lt;/H3&gt;
&lt;P&gt;Artifacts are published for traceability:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Code scanning results → CodeScanningReports&lt;/LI&gt;
&lt;LI&gt;IaC results → IaCSecurityReports&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;✅ Easy audit and troubleshooting&lt;BR /&gt;✅ Retains SARIF outputs&lt;/P&gt;
&lt;H2&gt;Benefits&lt;/H2&gt;
&lt;P&gt;This approach delivers:&lt;/P&gt;
&lt;P&gt;✔ One pipeline for all repositories&lt;BR /&gt;✔ Reduced maintenance overhead&lt;BR /&gt;✔ Consistent security enforcement&lt;BR /&gt;✔ Faster pipeline execution&lt;BR /&gt;✔ Scalable DevSecOps model&lt;/P&gt;
&lt;H2&gt;Lessons learned&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;Detection-first pipelines are critical for scale&lt;/LI&gt;
&lt;LI&gt;Config-driven CodeQL execution prevents failures&lt;/LI&gt;
&lt;LI&gt;Build tracing must be handled explicitly for compiled languages&lt;/LI&gt;
&lt;LI&gt;IaC scanning should not be a separate workflow&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Conclusion&lt;/H2&gt;
&lt;P&gt;Scaling GitHub Advanced Security across Azure DevOps doesn’t require multiple pipelines—it requires the right architecture.&lt;/P&gt;
&lt;P&gt;By combining:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Detection-driven execution&lt;/LI&gt;
&lt;LI&gt;Dynamic configuration&lt;/LI&gt;
&lt;LI&gt;Conditional setup&lt;/LI&gt;
&lt;LI&gt;Unified scanning&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;You can operationalize security at scale with a &lt;STRONG&gt;single reusable YAML template&lt;/STRONG&gt;.&lt;/P&gt;</description>
      <pubDate>Mon, 11 May 2026 10:47:04 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/scaling-github-advanced-security-in-azure-devops-with-a-single/ba-p/4518410</guid>
      <dc:creator>Paulams732</dc:creator>
      <dc:date>2026-05-11T10:47:04Z</dc:date>
    </item>
    <item>
      <title>Understanding the deployment quota limitation (800) Error in Azure Bicep and ARM Deployments</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/understanding-the-deployment-quota-limitation-800-error-in-azure/ba-p/4518262</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Understanding deployment quota limitation (800) Error in Azure Deployments (Bicep/ARM)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Introduction&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;When working with Infrastructure as Code (IaC) using Azure Bicep or ARM templates, deployment failures are a common part of day-to-day operations—especially in large-scale enterprise environments.&lt;/P&gt;
&lt;P&gt;One such frequently encountered but often misunderstood issue is the quota limitation (800) error, which typically occurs during repeated or automated deployments.&lt;/P&gt;
&lt;img /&gt;&lt;img&gt;Figure: Azure Bicep deployment failure showing DeploymentQuotaExceeded error after reaching the 800 deployment history limit, with reference to aka.ms/800 for remediation.&lt;/img&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="yaml"&gt;{
  "code": "DeploymentFailed",
  "target": "/subscriptions/cxxx8e00-0add-4f8a-8709-xxxxxxxxxxxx/resourceGroups/pxs-azure-connectivity-d-gwc-dnszone-rg/providers/Microsoft.Resources/deployments/ppiwwpkn7kkla-pdns-zone-deployment",
  "message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-deployment-operations for usage details.",
  "details": [
    {
      "code": "DeploymentQuotaExceeded",
      "message": "Creating the deployment '46d3xbcp.res.network-privatednszone.0-6-0.rysq' would exceed the quota of '800'. The current deployment count is '800'. Please delete some deployments before creating a new one, or see https://aka.ms/800LimitFix for information on managing deployment limits."
    }
  ]
}&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This blog explains:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;What this error means&lt;/LI&gt;
&lt;LI&gt;A practical Bicep deployment use case&lt;/LI&gt;
&lt;LI&gt;Root causes&lt;/LI&gt;
&lt;LI&gt;Resolution approaches&lt;/LI&gt;
&lt;LI&gt;Preventive best practices&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;What is the quota limitation (800) Error?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The quota limitation (800) reference is commonly associated with a deployment quota limitation in Azure Resource Manager (ARM).&lt;/P&gt;
&lt;P&gt;In simple terms:&lt;BR /&gt;Azure limits the number of deployment records that can be stored per resource group.&lt;/P&gt;
&lt;P&gt;Key detail:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Maximum allowed deployment history entries per resource group:&amp;nbsp;&lt;STRONG&gt;800&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Once this limit is exceeded:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;New deployments fail&lt;/LI&gt;
&lt;LI&gt;Error messages such as the following are observed:&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;“DeploymentQuotaExceeded”&lt;/P&gt;
&lt;P&gt;The current deployment count is '800'. Please delete some deployments before creating a new one.&lt;/P&gt;
&lt;P&gt;This happens because Azure maintains deployment history for auditing, tracking, and troubleshooting purposes. [aka.ms/800]&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Use Case: Bicep Deployment Failure in CI/CD&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Scenario&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;An organization is deploying infrastructure using a Bicep template through an automated pipeline.&lt;/P&gt;
&lt;P&gt;Example command:&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;az deployment group create \
  --resource-group prod-rg \
  --template-file main.bicep \
  --parameters @params.bicepparam&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Environment Characteristics&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Continuous deployment using pipelines (Azure DevOps / GitHub Actions)&lt;/LI&gt;
&lt;LI&gt;Multiple deployments triggered daily&lt;/LI&gt;
&lt;LI&gt;Incremental deployment mode enabled&lt;/LI&gt;
&lt;LI&gt;A shared resource group used across multiple deployments&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Issue Encountered&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After repeated deployments over time, the following failure occurs:&lt;/P&gt;
&lt;P&gt;Error: DeploymentQuotaExceeded&lt;/P&gt;
&lt;P&gt;The current deployment count is '800'&lt;/P&gt;
&lt;P&gt;See aka.ms/800 for more information&lt;/P&gt;
&lt;P&gt;At this point, no further deployments succeed in that resource group.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Root Cause Analysis&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Deployment History Limit&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Azure stores every deployment execution as a record under:&lt;/P&gt;
&lt;P&gt;Resource Group → Deployments&lt;/P&gt;
&lt;P&gt;These records accumulate over time, and once the count reaches 800, new deployments are blocked.&lt;/P&gt;
&lt;P&gt;Important clarification:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This is not a resource limit (VMs, VNets, etc.)&lt;/LI&gt;
&lt;LI&gt;This is a metadata limit related to deployment history&lt;/LI&gt;
&lt;/UL&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;High Frequency CI/CD Deployments&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;In enterprise environments, pipelines may run frequently due to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Minor configuration updates&lt;/LI&gt;
&lt;LI&gt;Validation runs&lt;/LI&gt;
&lt;LI&gt;Automated releases&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Each run contributes to the deployment count.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Absence of Cleanup Mechanism&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Although Azure manages some cleanup automatically, it is not always sufficient in high-frequency environments. Manual or automated cleanup is often required.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Resolution Approaches&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Option 1: Manual Cleanup from Azure Portal&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Navigate to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Azure Portal&lt;/LI&gt;
&lt;LI&gt;Resource Group&lt;/LI&gt;
&lt;LI&gt;Deployments&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Delete older deployment entries manually to free up space.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Option 2: Cleanup Using Azure CLI&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;#List deployments:

az deployment group list \
  --resource-group prod-rg \
  --query "[].name" -o tsv

#Delete a deployment:

az deployment group delete \
  --resource-group prod-rg \
  --name &amp;lt;deployment-name&amp;gt;&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Option 3: Automated Cleanup (Recommended)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Example PowerShell approach:&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;$deployments = Get-AzResourceGroupDeployment -ResourceGroupName "prod-rg"

if ($deployments.Count -gt 700) {
    $deployments | Sort-Object Timestamp | Select-Object -First 100 | ForEach-Object {
        Remove-AzResourceGroupDeployment -ResourceGroupName "prod-rg" -Name $_.DeploymentName
    }
}&lt;/LI-CODE&gt;
&lt;P&gt;This approach ensures that older deployments are periodically removed, preventing quota exhaustion.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Option 4: Use Multiple Resource Groups&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Instead of using a single resource group for all deployments:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Separate environments (Dev, Test, Prod)&lt;/LI&gt;
&lt;LI&gt;Temporary or experimental deployments&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;This helps distribute deployment records across multiple scopes.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Best Practices&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Implement Deployment Retention Policy&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;UL&gt;
&lt;LI&gt;Maintain only recent deployments (for example, last 100–200)&lt;/LI&gt;
&lt;LI&gt;Automate deletion of older entries&lt;/LI&gt;
&lt;/UL&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Control Deployment Frequency&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;UL&gt;
&lt;LI&gt;Avoid unnecessary pipeline triggers&lt;/LI&gt;
&lt;LI&gt;Batch multiple changes into a single deployment&lt;/LI&gt;
&lt;/UL&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Use Predictable Deployment Naming&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Example:&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;name: 'deploy-${utcNow()}'&lt;/LI-CODE&gt;
&lt;P&gt;This improves traceability and cleanup management.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Monitor Deployment Count&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Example:&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;az deployment group list \
  --resource-group prod-rg \
  --query "length(@)"&lt;/LI-CODE&gt;
&lt;P&gt;Set alerts or monitoring thresholds if required.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Understand Deployment Mode Behavior&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;Incremental deployments prevent unwanted deletions of resources but still increase the deployment history count.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Common Misconceptions&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Misconception&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Reality&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Resource quota exceeded&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;The issue is related to deployment history&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Template is invalid&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;The template can be valid but blocked by quota&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Permission issue&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Not related to RBAC&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Regional limitation&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Independent of region&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;Related Deployment Errors&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;While troubleshooting deployments, other common errors may appear, such as:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Authorization failures (insufficient permissions)&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/common-deployment-errors" target="_blank"&gt;[learn.microsoft.com]&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Invalid template errors (syntax or parameter mismatch)&lt;/LI&gt;
&lt;LI&gt;Concurrent deployment conflicts&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;It is important to analyze deployment logs to identify the exact failure reason.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Area&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Key Insight&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Error Type&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Deployment quota limitation&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Limit&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;800 deployments per resource group&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Primary Cause&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Frequent CI/CD executions&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Resolution&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Delete older deployment history&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;Prevention&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Automate cleanup and monitor usage&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;Closing Thoughts&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;For teams operating at scale with Azure Bicep and automated pipelines, this issue is common but preventable.&lt;/P&gt;
&lt;P&gt;The key takeaway is to treat deployment history as an actively managed component of your environment. Without proper governance, it can become a blocking factor for ongoing automation efforts.&lt;/P&gt;</description>
      <pubDate>Mon, 11 May 2026 05:12:56 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/understanding-the-deployment-quota-limitation-800-error-in-azure/ba-p/4518262</guid>
      <dc:creator>ranjan_ashish</dc:creator>
      <dc:date>2026-05-11T05:12:56Z</dc:date>
    </item>
    <item>
      <title>CHERIoT-Ibex: Closing the door on memory safety vulnerabilities with hardware-enforced protection</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/cheriot-ibex-closing-the-door-on-memory-safety-vulnerabilities/ba-p/4517904</link>
      <description>&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;Memory safety vulnerabilities—largely arising&amp;nbsp;from widely used programming languages such as C and C++—remain&amp;nbsp;a leading cause of exploitable software defects across systems, from embedded devices to&amp;nbsp;cloud-scale&amp;nbsp;infrastructure. In simple terms, memory safety ensures that software accesses only the data it is intended to use; when this protection fails, attackers can exploit these defects to gain control of devices or disrupt critical services. &lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;Industry data shows that&amp;nbsp;about 70 percent&amp;nbsp;of the vulnerabilities Microsoft assigns as&amp;nbsp;Common Vulnerabilities and Exposures (CVE)&amp;nbsp;each year are memory safety issues, highlighting how&amp;nbsp;frequently&amp;nbsp;these software defects translate into&amp;nbsp;real-world&amp;nbsp;security risk (&lt;/SPAN&gt;&lt;A href="https://www.cisa.gov/news-events/news/urgent-need-memory-safety-software-products" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;CISA – The Urgent Need for Memory Safety in Software Products&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;). Hardware-enforced&amp;nbsp;protections such&amp;nbsp;as&amp;nbsp;CHERIoT&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;-&lt;/SPAN&gt;&lt;SPAN data-contrast="auto"&gt;Ibex&amp;nbsp;can help&amp;nbsp;eliminate&amp;nbsp;these vulnerabilities at their source, reducing the likelihood that low-level software flaws can be exploited to compromise devices or disrupt workloads, supporting more trustworthy infrastructure by design. &lt;/SPAN&gt;&amp;nbsp;&lt;BR /&gt;&amp;nbsp;&lt;BR /&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;An open and certified foundation for memory-safe embedded systems&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;201341983&amp;quot;:0,&amp;quot;335559739&amp;quot;:0,&amp;quot;335559740&amp;quot;:300}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;CHERIoT-Ibex is the first open-source production-quality implementation of the&amp;nbsp;CHERIoT&amp;nbsp;instruction set architecture and among the first cores certified by the CHERI Alliance (&lt;/SPAN&gt;&lt;A href="https://cheri-alliance.org/cheri-enabled/cheriot/" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;CHERI Alliance – CHERIoT&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;). CHERIoT is an extension of&amp;nbsp;the&amp;nbsp;CHERI&amp;nbsp;(Capability Hardware Enhanced RISC Instructions)&amp;nbsp;instruction&amp;nbsp;set,&amp;nbsp;with&amp;nbsp;a focus on embedded and Internet of Things (IoT) applications.&amp;nbsp;Ibex is&amp;nbsp;an&amp;nbsp;open&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;source&amp;nbsp;32&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;bit RISC&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;V core developed by&amp;nbsp;LowRISC.&amp;nbsp;CHERIoT&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;Ibex&amp;nbsp;builds on Ibex by including CHERIoT capability extensions to provide&amp;nbsp;hardware&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;enforced&amp;nbsp;memory safety and&amp;nbsp;fine&lt;/SPAN&gt;‑&lt;SPAN data-contrast="auto"&gt;grained&amp;nbsp;compartmentalization.&amp;nbsp;It&amp;nbsp;is the result of a close partnership between Microsoft Research and Azure Hardware Systems &amp;amp; Infrastructure, combining advanced research innovation with industry-leading silicon IP development expertise. &lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;In 2023, Microsoft&amp;nbsp;open-sourced&amp;nbsp;the CHERIoT&amp;nbsp;Platform&amp;nbsp;to bring hardware-enforced memory safety to embedded systems, including an instruction set architecture, toolchain, real-time operating system, and the&amp;nbsp;RTL implementation of the CHERIoT-Ibex core. The CHERI Alliance certification recognizes its ability to provide spatial and temporal memory safety, fine-grained compartmentalization, and compatibility with the broader CHERI ecosystem. Critically, CHERIoT-Ibex achieves these security guarantees with power and area efficiency comparable to low-cost microcontrollers,&amp;nbsp;demonstrating&amp;nbsp;that security&amp;nbsp;doesn’t&amp;nbsp;have to come at a premium. &lt;/SPAN&gt;&amp;nbsp;&lt;BR /&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;Why memory safety&amp;nbsp;remains&amp;nbsp;a&amp;nbsp;foundational security challenge&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;Traditional embedded and&amp;nbsp;microcontroller-class&amp;nbsp;designs rely on software hardening and&amp;nbsp;coarse-grained&amp;nbsp;hardware protections that struggle to prevent attacks such as buffer overflows and&amp;nbsp;use-after-free&amp;nbsp;vulnerabilities, often adding complexity while still leaving gaps in protection. &lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;Consider a controller that runs privileged firmware responsible for device initialization, telemetry, and system health monitoring, while also hosting networking functionality exposed to external inputs. A&amp;nbsp;memory-safe&amp;nbsp;vulnerability in the networking stack could allow attackers to execute unauthorized code within the firmware environment, potentially affecting other critical services on the device. In tightly integrated&amp;nbsp;systems,&amp;nbsp;these failures can propagate beyond a single&amp;nbsp;component, increasing overall risk.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;BR /&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;Constraining failures with&amp;nbsp;hardware-enforced&amp;nbsp;isolation&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;CHERIoT-Ibex&amp;nbsp;enables&amp;nbsp;hardware-enforced&amp;nbsp;isolation between these components, helping ensure that even if the networking stack is compromised, its ability to&amp;nbsp;impact&amp;nbsp;system initialization or telemetry functions&amp;nbsp;remains&amp;nbsp;constrained. By limiting the blast radius of software failures,&amp;nbsp;CHERIoT-Ibex&amp;nbsp;supports a system-level approach to security rather than relying on individual components to defend themselves in isolation.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;BR /&gt;&lt;STRONG&gt;&lt;SPAN data-contrast="auto"&gt;Advancing&amp;nbsp;memory-safe&amp;nbsp;infrastructure by design&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{&amp;quot;201341983&amp;quot;:0,&amp;quot;335559740&amp;quot;:300}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;CHERIoT-Ibex’s certification by the CHERI Alliance marks an important milestone for open-source&amp;nbsp;memory-safe solutions. It&amp;nbsp;validates&amp;nbsp;that strong security guarantees can coexist with efficiency and transparency, reflecting Microsoft’s broader silicon-to-systems strategy&amp;nbsp;of&amp;nbsp;embedding&amp;nbsp;security into&amp;nbsp;the&amp;nbsp;foundational hardware infrastructure.&lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-contrast="auto"&gt;Explore and engage with the open-source CHERIoT ecosystem by visiting the CHERIoT Platform and the CHERIoT-Ibex GitHub repository (&lt;/SPAN&gt;&lt;A href="https://github.com/microsoft/cheriot-ibex" target="_blank" rel="noopener"&gt;&lt;SPAN data-contrast="none"&gt;&lt;SPAN data-ccp-charstyle="Hyperlink"&gt;microsoft/cheriot-ibex&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN data-contrast="auto"&gt;). The repositories enable developers and researchers to experiment with, contribute to, and&amp;nbsp;build on&amp;nbsp;memory-safe hardware and software foundations. &lt;/SPAN&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-ccp-props="{}"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Sat, 09 May 2026 05:08:11 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/cheriot-ibex-closing-the-door-on-memory-safety-vulnerabilities/ba-p/4517904</guid>
      <dc:creator>kunyanliu</dc:creator>
      <dc:date>2026-05-09T05:08:11Z</dc:date>
    </item>
    <item>
      <title>Safely Migrating Terraform Managed Disks on Azure Using Stable Keys and Copilot</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/safely-migrating-terraform-managed-disks-on-azure-using-stable/ba-p/4517509</link>
      <description>&lt;H2&gt;&lt;SPAN style="color: rgb(30, 30, 30); font-size: 32px;"&gt;The Root Cause: Index-Based "for_each" Keys:&lt;/SPAN&gt;&lt;/H2&gt;
&lt;H4&gt;Many Terraform modules flatten VM and disk definitions into a list and use the list index as the for_each key:&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;for_each = { for index, sp in local.managed_disks : index =&amp;gt; sp }&lt;/STRONG&gt;&lt;/H4&gt;
&lt;H4&gt;This pattern looks harmless, but the index is not stable:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Adding a disk to one VM shifts downstream indices&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Reordering environment JSON changes flatten order&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Terraform treats shifted indices as new resources&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;The result: Terraform plans to destroy and recreate all affected managed disks—even though nothing changed in Azure.&lt;/H4&gt;
&lt;H2&gt;Why This Is Especially Risky on Azure:&lt;/H2&gt;
&lt;H4&gt;Azure managed disks are often:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Attached to stateful application tiers&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Used for databases, middleware, or batch workloads&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Deployed across zones for resiliency&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;A forced disk replacement can mean:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Data loss&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Extended outages&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Failed change windows&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;This makes state stability a first-class design concern—not an implementation detail.&lt;/H4&gt;
&lt;H2&gt;The Stable Key Pattern:&lt;/H2&gt;
&lt;H4&gt;The fix is conceptually simple: use a domain-stable identifier for each disk.&lt;/H4&gt;
&lt;H4&gt;A proven pattern is:&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;"${sp.vm}-${sp.data_disk.lun}"&lt;/STRONG&gt;&lt;/H4&gt;
&lt;H4&gt;This key is:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;Deterministic&lt;/LI&gt;
&lt;LI&gt;Independent of ordering&lt;/LI&gt;
&lt;LI&gt;Human-readable&lt;/LI&gt;
&lt;LI&gt;Stable across environments&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;Example:&lt;/H4&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;VM&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;LUN&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Stable Key&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;vm1&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;0&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;vm1-0&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;vm1&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;1&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;vm1-1&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;vm2&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;0&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;vm2-0&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H4&gt;Once applied, adding a new disk results in exactly one new resource, with zero churn.&lt;/H4&gt;
&lt;H2&gt;The Migration Challenge: Terraform State:&lt;/H2&gt;
&lt;H4&gt;Changing &lt;STRONG&gt;for_each&lt;/STRONG&gt; keys alone is not enough.&lt;/H4&gt;
&lt;H4&gt;Terraform tracks resources by their state address, not by Azure resource ID. When keys change, Terraform believes:&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;“The old disks were deleted, and new ones must be created.”&lt;/STRONG&gt;&lt;/H4&gt;
&lt;H4&gt;To prevent this, we must move the state, not recreate the resource.&lt;/H4&gt;
&lt;H4&gt;That is where terraform state mv comes in.&lt;/H4&gt;
&lt;H2&gt;Automating the Migration with GitHub Copilot Skills:&lt;/H2&gt;
&lt;H4&gt;To remove risk and human error, the team created a reusable Copilot skill for managed disk key migration.&lt;/H4&gt;
&lt;H3&gt;What the Skill Does:&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Inspects Terraform modules for index-based for_each&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Reads environment JSON files (such as ALZ variable abstractions)&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Reconstructs the exact flatten order used by Terraform&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Generates precise terraform state mv commands&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5&gt;This ensures:&lt;/H5&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;No guessing&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;No manual address mapping&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;No production surprises&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5&gt;The skill is stored directly inside the repository under .github/skills, making it:&lt;/H5&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Discoverable&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Versioned&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Shareable across teams&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Example: Generating State Move Commands:&lt;/H2&gt;
&lt;H4&gt;Based on environment JSON, Copilot can generate commands like:&lt;/H4&gt;
&lt;P&gt;&lt;STRONG&gt;terraform state mv \&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp; 'module.managed_disk_windowsvm_app["0"]' \&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp; 'module.managed_disk_windowsvm_app["vm1-0"]'&lt;/STRONG&gt;&lt;/P&gt;
&lt;H4&gt;This is repeated deterministically for every existing disk—before any plan or apply.&lt;/H4&gt;
&lt;H2&gt;Recommended Migration Workflow:&lt;/H2&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;H5&gt;Confirm clean state&lt;/H5&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;terraform plan shows no pending changes&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;H5&gt;Update the module&lt;/H5&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Replace index-based keys with stable keys&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;H4&gt;Back up the state&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Especially critical with remote backends (Azure Storage)&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;H4&gt;Run terraform state mv&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Only after terraform init is connected to the correct backend&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;H4&gt;Re-run plan&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Existing disks should show no changes&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;H4&gt;Add new disks safely&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Terraform creates only the new disk&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;H2&gt;CI/CD and Remote Backend Considerations:&lt;/H2&gt;
&lt;H4&gt;A critical finding from this migration:&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;terraform state mv&lt;/STRONG&gt; always modifies the currently initialized backend.&lt;/H4&gt;
&lt;H4&gt;In pipeline-driven environments:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Ensure the correct environment is initialized&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Run migrations once per environment&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Never merge stable-key code before migrating all environments&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;Failing to align code and state can cause disk destruction in production.&lt;/H4&gt;
&lt;H2&gt;Key Takeaways:&lt;/H2&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;EM&gt;Index-based for_each keys are unsafe for long-lived Azure disks&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Stable keys such as vm-lun eliminate accidental resource churn&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;State migration is mandatory—not optional&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Copilot skills are powerful for institutionalizing safe patterns&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Small Terraform design choices can have enterprise-scale impact&lt;/EM&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Closing Thoughts:&lt;/H2&gt;
&lt;H4&gt;This pattern is broadly applicable beyond disks—to NICs, extensions, and any resource where identity must outlive ordering.&lt;/H4&gt;
&lt;H4&gt;By combining:&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;&lt;EM&gt;Stable Terraform design&lt;/EM&gt;&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;EM&gt;State-aware migrations&lt;/EM&gt;&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;EM&gt;GitHub Copilot automation&lt;/EM&gt;&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;Teams can make infrastructure changes boring again—and that is the ultimate reliability goal.&lt;/H4&gt;</description>
      <pubDate>Fri, 08 May 2026 16:02:01 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/safely-migrating-terraform-managed-disks-on-azure-using-stable/ba-p/4517509</guid>
      <dc:creator>shwetayadav</dc:creator>
      <dc:date>2026-05-08T16:02:01Z</dc:date>
    </item>
    <item>
      <title>Building Secure AI Platforms in Banking Using Azure Enterprise Architecture</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-secure-ai-platforms-in-banking-using-azure-enterprise/ba-p/4517531</link>
      <description>&lt;H4&gt;&lt;STRONG&gt;1. Introduction: AI in Banking Is Not Just a Model Problem&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Modern banking institutions are no longer asking &lt;EM data-start="1449" data-end="1467"&gt;“Can we use AI?”&lt;/EM&gt;&lt;BR data-start="1467" data-end="1470" /&gt;The real question is:&lt;BR /&gt;&lt;STRONG data-start="1496" data-end="1587"&gt;“Can we use AI without violating regulatory, security, and data residency constraints?”&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Unlike public AI applications, banking systems must ensure:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;No public internet exposure&lt;/LI&gt;
&lt;LI&gt;Strict identity-based access control&lt;/LI&gt;
&lt;LI&gt;End-to-end auditability&lt;/LI&gt;
&lt;LI&gt;Data residency compliance&lt;/LI&gt;
&lt;LI&gt;Fully controlled inference pipelines&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;👉 In enterprise environments, &lt;STRONG&gt;AI success is driven by secure infrastructure—not just model accuracy&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;2. Core Design Principle: Controlled Intelligence System&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Every AI request must follow a &lt;STRONG&gt;security-enforced execution pipeline&lt;/STRONG&gt;:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;User Request
   ↓
Secure Edge (Application Gateway + WAF)
   ↓
API Governance Layer (API Management - Internal Mode)
   ↓
AI Orchestration Layer (AKS / App Services)
   ↓
Retrieval + Policy Layer (RAG + Guardrails)
   ↓
Private AI Services (Azure OpenAI)
   ↓
Observability Layer (AMPLS)
   ↓
Final Response&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Key Insight:&lt;/STRONG&gt;&lt;BR /&gt;This is not just an architecture—it is a &lt;STRONG&gt;controlled and auditable execution model&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;3. Azure Enterprise AI Architecture (Production-Ready Pattern)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;A real-world architecture used in banking environments:&lt;/P&gt;
&lt;img /&gt;
&lt;H4&gt;&lt;STRONG&gt;4. Private Connectivity Model (Critical for Compliance)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Key components:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Private Endpoints&lt;/STRONG&gt; → Secure PaaS isolation&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Private DNS Zones&lt;/STRONG&gt; → Controlled name resolution&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;VNet Integration&lt;/STRONG&gt; → Internal service communication&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure Firewall&lt;/STRONG&gt; → Traffic inspection and control&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;⚠️ &lt;STRONG&gt;Common Production Failure:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;AKS pods fail to resolve Azure OpenAI private endpoint&lt;/LI&gt;
&lt;LI&gt;Root cause:
&lt;UL&gt;
&lt;LI&gt;Missing Private DNS links&lt;/LI&gt;
&lt;LI&gt;Incorrect VNet configuration&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;👉 This is one of the most frequent failures in enterprise AI deployments.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt; “Debugging Private Endpoint Failures” &lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-start="2681" data-end="2689"&gt;Include:&lt;/P&gt;
&lt;UL data-start="2691" data-end="2800"&gt;
&lt;LI data-start="2691" data-end="2717"&gt;nslookup behavior in AKS&lt;/LI&gt;
&lt;LI data-start="2718" data-end="2742"&gt;DNS zone linking check&lt;/LI&gt;
&lt;LI data-start="2743" data-end="2772"&gt;VNet integration validation&lt;/LI&gt;
&lt;LI data-start="2773" data-end="2800"&gt;UDR / Firewall inspection&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&lt;STRONG&gt;5. Identity-First Security Model (No Secrets Architecture)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Modern banking architectures eliminate static credentials entirely.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Authentication Flow:&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang=""&gt;AKS Workload → Managed Identity → Azure AD → Azure Services&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Key Principle:&lt;/STRONG&gt;&lt;BR /&gt;👉 &lt;EM&gt;Identity is the new security perimeter.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Benefits:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;No API keys or secrets&lt;/LI&gt;
&lt;LI&gt;Simplified access management&lt;/LI&gt;
&lt;LI&gt;RBAC-based governance&lt;/LI&gt;
&lt;LI&gt;Fully auditable access&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&lt;STRONG&gt;6. Secure AI Inference Pipeline&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;A production AI request flow:&lt;/P&gt;
&lt;LI-CODE lang="python"&gt;def process_request(user_request):
    # 1. Authenticate user via Azure AD
    identity = authenticate_aad(user_request.token)
    if not identity or not identity.is_valid:
        return "ACCESS_DENIED"
    # 2. Enforce rate limiting per identity
    if not rate_limit(identity):
        return "RATE_LIMIT_EXCEEDED"
    # 3. Apply prompt security guardrails (injection protection)
    safe_prompt = apply_prompt_guardrails(user_request.prompt)
    # 4. Content safety filtering (PII / harmful content detection)
    if not content_filter(safe_prompt):
        return "CONTENT_BLOCKED"
    # 5. Retrieve secure RAG context
    context = retrieve_rag_context(
        query=safe_prompt,
        secure_mode=True
    )
    # 6. Build final prompt
    final_prompt = merge_prompt_and_context(safe_prompt, context)
    # 7. Call Azure OpenAI with circuit breaker protection
    response = circuit_breaker(
        lambda: call_openai(
            prompt=final_prompt,
            identity=ManagedIdentity()
        )
    )
    # 8. Validate and sanitize model output
    validated_output = sanitize(response)
    # 9. Log everything for audit + compliance (AMPLS / SIEM)
    log_to_ampls(
        identity=identity,
        request=user_request,
        response=validated_output
    )
    return validated_output&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Security controls include:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Prompt injection filtering&lt;/LI&gt;
&lt;LI&gt;Context grounding (RAG)&lt;/LI&gt;
&lt;LI&gt;Output sanitization&lt;/LI&gt;
&lt;LI&gt;Full audit logging&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&lt;STRONG&gt;7. RAG Architecture: Enterprise AI Backbone&lt;/STRONG&gt;&lt;/H4&gt;
&lt;LI-CODE lang=""&gt;User Query → Embedding Model → Azure AI Search (Vector Store) → Context Retrieval → Azure OpenAI → Final Response&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Why RAG is preferred in banking:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;No model retraining required&lt;/LI&gt;
&lt;LI&gt;Controlled data exposure&lt;/LI&gt;
&lt;LI&gt;Easier compliance validation&lt;/LI&gt;
&lt;LI&gt;Real-time knowledge updates&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;In banking systems, retrieval is not just about relevance—it is about &lt;STRONG data-start="3993" data-end="4039"&gt;controlled disclosure of sensitive context&lt;/STRONG&gt;&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;8. Observability with AMPLS (A Critical Yet Overlooked Layer)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;AI telemetry flows through:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;Azure Services → Private Link → AMPLS → Log Analytics / App Insights&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Why this matters:&lt;/STRONG&gt; Logs may contain:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Sensitive financial data&lt;/LI&gt;
&lt;LI&gt;PII&lt;/LI&gt;
&lt;LI&gt;Prompt inputs&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;👉 AMPLS ensures &lt;STRONG&gt;telemetry remains private and compliant&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;9. Regulatory Mapping: Banking Requirements to Azure Capabilities&lt;/STRONG&gt;&lt;/H4&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Requirement&lt;/th&gt;&lt;th&gt;Azure Implementation&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;No public exposure&lt;/td&gt;&lt;td&gt;Private Endpoints&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Identity-based security&lt;/td&gt;&lt;td&gt;Azure AD + Managed Identity&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Audit compliance&lt;/td&gt;&lt;td&gt;Log Analytics + AMPLS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Data protection&lt;/td&gt;&lt;td&gt;Customer-Managed Keys (CMK)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Network isolation&lt;/td&gt;&lt;td&gt;VNet + Firewall&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Access governance&lt;/td&gt;&lt;td&gt;RBAC + PIM&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;
&lt;H4&gt;&lt;STRONG&gt;10. Real-World Production Challenges&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Common failure points in enterprise AI systems:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;DNS Misconfiguration&lt;/STRONG&gt; – Private endpoints fail resolution&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Latency Chains&lt;/STRONG&gt; – Excessive service hops&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;OpenAI Rate Limits&lt;/STRONG&gt; – High enterprise load&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Identity Propagation Issues&lt;/STRONG&gt; – Cross-subscription failures&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Observability Gaps&lt;/STRONG&gt; – Missing distributed tracing&lt;/LI&gt;
&lt;/OL&gt;
&lt;H4&gt;&lt;STRONG&gt;11. Enterprise Architecture Best Practices&lt;/STRONG&gt;&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;Design with &lt;STRONG&gt;zero-trust principles&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Treat AI as a &lt;STRONG&gt;distributed system&lt;/STRONG&gt;, not a single component&lt;/LI&gt;
&lt;LI&gt;Centralize governance using API Management&lt;/LI&gt;
&lt;LI&gt;Never expose AI services publicly&lt;/LI&gt;
&lt;LI&gt;Use &lt;STRONG&gt;identity everywhere—no secrets&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Separate:
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Control Plane&lt;/STRONG&gt; (governance)&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Data Plane&lt;/STRONG&gt; (inference execution)&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&lt;STRONG&gt;12. Azure Service Mapping (Quick Reference)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Layer&lt;/th&gt;&lt;th&gt;Azure Services&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Edge Security&lt;/td&gt;&lt;td&gt;Application Gateway (WAF)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;API Layer&lt;/td&gt;&lt;td&gt;API Management&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compute&lt;/td&gt;&lt;td&gt;AKS / App Services&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AI Services&lt;/td&gt;&lt;td&gt;Azure OpenAI&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Retrieval&lt;/td&gt;&lt;td&gt;Azure AI Search&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Data&lt;/td&gt;&lt;td&gt;Azure Storage / SQL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Identity&lt;/td&gt;&lt;td&gt;Azure AD + Managed Identity&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Networking&lt;/td&gt;&lt;td&gt;Private Link + VNet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Observability&lt;/td&gt;&lt;td&gt;AMPLS + Log Analytics&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;
&lt;H4&gt;&lt;STRONG&gt;13. Common Failure Patterns&lt;/STRONG&gt;&lt;/H4&gt;
&lt;table border="1" style="border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Issue&lt;/th&gt;&lt;th&gt;Root Cause&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AI endpoint unreachable&lt;/td&gt;&lt;td&gt;DNS / Private endpoint misconfig&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Data leakage risk&lt;/td&gt;&lt;td&gt;Missing prompt filtering&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;High latency&lt;/td&gt;&lt;td&gt;Over-layered architecture&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Unauthorized access&lt;/td&gt;&lt;td&gt;Identity misconfiguration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Poor response quality&lt;/td&gt;&lt;td&gt;Weak RAG implementation&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;
&lt;H4&gt;&lt;STRONG&gt;14. Final Thought&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;In enterprise banking AI systems:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Models are replaceable. Architecture is not.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The real challenge is designing a system where AI is:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Secure&lt;/LI&gt;
&lt;LI&gt;Controlled&lt;/LI&gt;
&lt;LI&gt;Observable&lt;/LI&gt;
&lt;LI&gt;Fully compliant&lt;/LI&gt;
&lt;/UL&gt;
&lt;/DIV&gt;</description>
      <pubDate>Thu, 07 May 2026 16:03:01 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-secure-ai-platforms-in-banking-using-azure-enterprise/ba-p/4517531</guid>
      <dc:creator>divyanshi_varshney</dc:creator>
      <dc:date>2026-05-07T16:03:01Z</dc:date>
    </item>
    <item>
      <title>How Validation‑Driven Terraform Made Our Azure Function Deployments Predictable</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/how-validation-driven-terraform-made-our-azure-function/ba-p/4517375</link>
      <description>&lt;P&gt;When Terraform deploys Azure Functions, the most expensive failures are rarely “syntax” problems. They’re environmental mismatches discovered too late—during&amp;nbsp;&lt;STRONG&gt;terraform apply&lt;/STRONG&gt;, after approvals, after a change window starts, and often after multiple teams are already watching the pipeline.&lt;/P&gt;
&lt;P&gt;After a few painful production-grade rollouts, we shifted to a &lt;STRONG&gt;validation-driven&lt;/STRONG&gt; approach: instead of letting Azure reject misconfigurations at apply time, we &lt;STRONG&gt;fail fast at PR/plan time&lt;/STRONG&gt; with clear messages that engineers can fix immediately.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What we mean by “validation‑driven”&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Validation-driven Terraform uses three guardrails together:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;PR checks&lt;/STRONG&gt;: formatting, linting, security scanning, module contract tests&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Pre-flight checks&lt;/STRONG&gt;: quick Azure sanity checks (provider registration, storage prerequisites, RBAC basics)&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform-native validations&lt;/STRONG&gt;: input validations + preconditions that stop invalid configurations before they reach Azure&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The idea is simple: &lt;STRONG&gt;apply should be boring&lt;/STRONG&gt;. If something is going to fail, it should fail &lt;EM&gt;earlier&lt;/EM&gt; with &lt;EM&gt;better&lt;/EM&gt; errors.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Azure Functions as the example: where failures actually happen&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Azure Functions bring a few recurring “gotchas” that tend to show up late:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;mismatch between &lt;STRONG&gt;plan/SKU&lt;/STRONG&gt; and features (e.g., VNET integration expectations)&lt;/LI&gt;
&lt;LI&gt;missing or inaccessible &lt;STRONG&gt;storage account settings&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;unsupported/incorrect &lt;STRONG&gt;runtime stack/version&lt;/STRONG&gt; for a chosen hosting model/region/policy&lt;/LI&gt;
&lt;LI&gt;inconsistent &lt;STRONG&gt;app settings&lt;/STRONG&gt; required by your org platform standards&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;We converted these into guardrails with &lt;STRONG&gt;minimal code&lt;/STRONG&gt; and clearer pipeline signals.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Case study 1: Wrong plan SKU causing runtime capability failures&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Problem&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;A team deployed a Function App expecting network integration behavior, but the selected plan/SKU didn’t align with what the workload required. The pipeline failed late, after approvals, and the rollback discussion took longer than the fix.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What we changed&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;We added a small validation/precondition rule: if a team enables a capability that requires a certain class of plan, Terraform fails early with a targeted message.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Outcome&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Failure moved from apply-time → plan-time&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;2+ hours&lt;/STRONG&gt; saved per failed deployment cycle&lt;/LI&gt;
&lt;LI&gt;Zero repeat incidents for that class of issue&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Case study 2: Missing storage configuration blocking deployments&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Problem&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Function Apps depend heavily on storage configuration. We saw intermittent failures when storage settings pointed to deleted/incorrect resources, or when access expectations didn’t match reality.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What we changed&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;We introduced a &lt;STRONG&gt;pre-flight check&lt;/STRONG&gt; step in Azure DevOps: verify storage existence/access and fail fast before plan/apply.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Outcome&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Deployments stopped failing mid-run&lt;/LI&gt;
&lt;LI&gt;Fewer “investigation loops” across teams&lt;/LI&gt;
&lt;LI&gt;Reduced incident noise (the pipeline became self-explanatory)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Case study 3: Unsupported runtime version (region/org guardrails mismatch)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Problem&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Engineers selected a runtime stack/version that was valid in isolation, but not aligned with platform support or readiness in the target environment. Failures appeared in apply or after release.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;What we changed&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;We centralized an “allowed runtime list” (per org standards) and validated runtime inputs at plan time.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Outcome&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Plan failed fast with clear explanation&lt;/LI&gt;
&lt;LI&gt;No redeploy cycles&lt;/LI&gt;
&lt;LI&gt;Better compliance posture (standards became enforceable code)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Why this matters (beyond “fewer red pipelines”)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Validation-driven Terraform improved more than deployment success rate:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Developer experience&lt;/STRONG&gt;: errors became precise and actionable&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Operational safety&lt;/STRONG&gt;: fewer emergency approvals and late-night fixes&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Standardization&lt;/STRONG&gt;: platform rules stopped living in tribal knowledge and wikis&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Manager-visible impact&lt;/STRONG&gt;: less delivery friction, fewer escalations, faster releases&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;The best part: this wasn’t achieved by writing massive frameworks. It was achieved by adding &lt;STRONG&gt;small, high-leverage validations&lt;/STRONG&gt; in the right places.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Minimal code approach (what we actually used)&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;We intentionally kept Terraform code small:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A few &lt;STRONG&gt;input validations&lt;/STRONG&gt; (environment, runtime, naming contracts)&lt;/LI&gt;
&lt;LI&gt;A few &lt;STRONG&gt;preconditions&lt;/STRONG&gt; (must-have settings and plan constraints)&lt;/LI&gt;
&lt;LI&gt;A light &lt;STRONG&gt;Azure DevOps pre-flight&lt;/STRONG&gt; step for checks Terraform can’t reliably infer (like “does this dependency exist and is it accessible?”)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;This way, the module stays readable, and the pipeline remains fast.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Conclusion&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;In one of our Azure Function platforms, repeated deployment failures were not caused by bugs in application code or gaps in Terraform itself—they were caused by &lt;STRONG&gt;discovering platform constraints too late&lt;/STRONG&gt;. Each failed terraform apply triggered rework, additional approvals, and unnecessary operational noise across teams.&lt;/P&gt;
&lt;P&gt;By introducing a validation‑driven approach—combining Terraform input validations, targeted preconditions, and lightweight Azure DevOps pre‑flight checks—we moved failure discovery to the right place: &lt;STRONG&gt;pull requests and plan stages&lt;/STRONG&gt;. Azure Function‑specific issues such as incorrect plan capabilities, unsupported runtimes, and missing storage prerequisites were surfaced early, with clear, actionable messages.&lt;/P&gt;
&lt;P&gt;If your Azure DevOps pipelines still use terraform apply as a discovery mechanism, validation is not an optimization—it’s a foundational platform capability.&lt;/P&gt;</description>
      <pubDate>Thu, 07 May 2026 05:12:06 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/how-validation-driven-terraform-made-our-azure-function/ba-p/4517375</guid>
      <dc:creator>AkshitaBajpai</dc:creator>
      <dc:date>2026-05-07T05:12:06Z</dc:date>
    </item>
    <item>
      <title>Operationalizing Responsible AI in Microsoft Foundry within Enterprise Network Boundaries</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/operationalizing-responsible-ai-in-microsoft-foundry-within/ba-p/4516869</link>
      <description>&lt;H2&gt;Strategic Overview&lt;/H2&gt;
&lt;P class="lia-align-justify"&gt;&lt;SPAN data-teams="true"&gt;Deploying &lt;STRONG&gt;Microsoft Foundry&lt;/STRONG&gt; within a VNet-integrated landing zone requires a thoughtful balance between innovation and enterprise-grade security, especially in highly regulated industries like banking. This architecture enforces Responsible AI (RAI) principles and robust content safety controls while aligning with stringent security and compliance requirements. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="lia-align-justify"&gt;&lt;SPAN data-teams="true"&gt;By adopting a dual-stream design - comprising an AI Platform Layer and a Data Integration Layer, you can decouple model orchestration from data ingestion, enabling flexibility and scalability. Leveraging private networking constructs such as VNets, subnets, NSGs, and controlled routing ensures that all AI workloads operate within secure boundaries, while seamless integration with services like Azure AI Search, Azure Cosmos DB, Azure SQL Database, and Azure Document Intelligence enhances data accessibility and intelligence. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="lia-align-justify"&gt;&lt;SPAN data-teams="true"&gt;Event-driven ingestion patterns powered by Azure Data Factory and Azure Event Grid further enable real-time responsiveness. At the same time, real-world constraints - such as IP range allowlisting for Microsoft Foundry and private networking limitations—must be carefully accounted for. Ultimately, this approach ensures a secure, compliant, and scalable foundation for enterprise AI adoption.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="lia-align-justify"&gt;&lt;SPAN data-teams="true"&gt;Below are the pointers that this blog focuses:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Deploy Azure Microsoft Foundry in a &lt;STRONG&gt;VNet-integrated landing zone&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Enforce &lt;STRONG&gt;Responsible AI (RAI) policies and content safety controls&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Align AI architecture with &lt;STRONG&gt;enterprise (banking) security requirements&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Implement a dual-stream architecture:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;&lt;STRONG&gt;AI Platform Layer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Data Integration Layer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Use private networking with &lt;STRONG&gt;VNet, subnets, NSGs, and routing&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Integrate with &lt;STRONG&gt;Azure AI Search, Cosmos DB, SQL, and Document Intelligence&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Enable event-driven ingestion using &lt;STRONG&gt;Azure Data Factory and Event Grid&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Account for real-world constraints:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;&lt;STRONG&gt;IP range allowlisting for Microsoft Foundry&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Private networking limitations&lt;/LI&gt;
&lt;/UL&gt;
&lt;/DIV&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class="lia-align-justify"&gt;Design for &lt;STRONG&gt;secure, compliant, and scalable AI consumption&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Problem Statement&lt;/H2&gt;
&lt;P&gt;Operationalizing Responsible AI in enterprise environments requires more than defining policies.&lt;/P&gt;
&lt;P&gt;Key challenges include:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Translating Responsible AI principles into &lt;STRONG&gt;enforceable platform controls&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Deploying AI services within &lt;STRONG&gt;private, enterprise-grade networks&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Managing &lt;STRONG&gt;network constraints and service limitations&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Ensuring consistent integration across:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;AI services&lt;/LI&gt;
&lt;LI&gt;Data pipelines&lt;/LI&gt;
&lt;LI&gt;Application layers&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Without a structured approach, AI platforms risk being &lt;STRONG&gt;non-compliant, insecure, or difficult to scale&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H2&gt;Goals&lt;/H2&gt;
&lt;P&gt;Design an AI landing zone that:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Enforces &lt;STRONG&gt;Responsible AI at the platform level&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Enables &lt;STRONG&gt;secure model deployment and access&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Operates fully within &lt;STRONG&gt;private network boundaries&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Integrates &lt;STRONG&gt;AI and Data services seamlessly&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Provides &lt;STRONG&gt;governed and controlled AI consumption&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Architecture Overview&lt;/H2&gt;
&lt;P&gt;Structure the platform into four layers:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;&lt;STRONG&gt;Network Layer&lt;/STRONG&gt; → VNet, subnets, NSGs, routing&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;AI Platform Layer&lt;/STRONG&gt; → Microsoft Foundry, models, RAI policies&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Data Layer&lt;/STRONG&gt; → ADF, SHIR, Event Grid&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Application Layer&lt;/STRONG&gt; → Function Apps, Web Apps&lt;/LI&gt;
&lt;/UL&gt;
&lt;img /&gt;
&lt;H2&gt;Microsoft Foundry Setup in Enterprise Context&lt;/H2&gt;
&lt;P&gt;Set up Azure Microsoft Foundry as the &lt;STRONG&gt;core AI platform layer&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H3&gt;Key steps:&lt;/H3&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Create Microsoft&lt;STRONG&gt;&amp;nbsp;Foundry projects&lt;/STRONG&gt; to isolate use cases&lt;/LI&gt;
&lt;LI&gt;Deploy models within controlled project boundaries&lt;/LI&gt;
&lt;LI&gt;Restrict access using:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;VNet integration&lt;/LI&gt;
&lt;LI&gt;Private endpoints&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;Disable public access wherever possible&lt;/LI&gt;
&lt;LI&gt;Integrate with supporting services:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Azure AI Search (retrieval)&lt;/LI&gt;
&lt;LI&gt;Cosmos DB / SQL (data storage)&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Design Principle&lt;/H3&gt;
&lt;P&gt;Treat AI services as &lt;STRONG&gt;governed platform components&lt;/STRONG&gt;, not standalone resources.&lt;/P&gt;
&lt;H2&gt;Responsible AI Implementation&lt;/H2&gt;
&lt;H3&gt;1. RAI Policies&lt;/H3&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Define policies at the &lt;STRONG&gt;model interaction layer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Configure controls for:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Output moderation&lt;/LI&gt;
&lt;LI&gt;Prompt handling&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;Align policies with &lt;STRONG&gt;organizational compliance requirements&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;2. Content Safety&lt;/H3&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Integrate content safety as a &lt;STRONG&gt;mandatory runtime layer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Ensure all model outputs pass through filtering before reaching applications&lt;/LI&gt;
&lt;/UL&gt;
&lt;img&gt;&lt;STRONG&gt; Content Safety Flow&lt;/STRONG&gt;&lt;/img&gt;
&lt;H3&gt;3. Model Governance&lt;/H3&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Control model deployment via Microsoft Foundry&lt;/LI&gt;
&lt;LI&gt;Restrict direct access to models&lt;/LI&gt;
&lt;LI&gt;Route all interactions through:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Function Apps&lt;/LI&gt;
&lt;LI&gt;API layers&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Handling VNet-Integrated Deployment Challenges&lt;/H2&gt;
&lt;P&gt;Enterprise deployments introduce constraints that must be addressed early.&lt;/P&gt;
&lt;H5&gt;Challenge 1: Microsoft Foundry VNet Integration&lt;/H5&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Microsoft Foundry requires &lt;STRONG&gt;careful network planning&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Standard enterprise patterns may not work without validation&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5&gt;Challenge 2: IP Range Constraints&lt;/H5&gt;
&lt;P&gt;When designing the VNet:&lt;/P&gt;
&lt;UL data-spread="true"&gt;
&lt;LI&gt;10.x.x.x range&lt;BR /&gt;→ Not GA for all Azure regions by default&lt;/LI&gt;
&lt;LI&gt;Requires:&lt;BR /&gt;→ &lt;STRONG&gt;Allowlisting via Microsoft Product Group&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Supported ranges (commonly observed):
&lt;UL data-spread="false"&gt;
&lt;LI&gt;172.x.x.x&lt;/LI&gt;
&lt;LI&gt;192.x.x.x&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Recommended Approach&lt;/H3&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Validate supported IP ranges &lt;STRONG&gt;before finalizing network design&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Avoid assuming default enterprise CIDR blocks will work&lt;/LI&gt;
&lt;LI&gt;Plan subnets specifically for &lt;STRONG&gt;AI workloads&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5&gt;Challenge 3: Platform Constraints&lt;/H5&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;AI services may behave differently compared to traditional PaaS services&lt;/LI&gt;
&lt;LI&gt;Validate:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Private endpoint compatibility&lt;/LI&gt;
&lt;LI&gt;Service integration within VNet&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H5&gt;Challenge 4: Security vs Accessibility&lt;/H5&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Private deployments improve security but add complexity&lt;/LI&gt;
&lt;LI&gt;Address this by:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Providing controlled access paths&lt;/LI&gt;
&lt;LI&gt;Using jump hosts or secure access mechanisms&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Key Design Considerations&lt;/H2&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Treat networking as a &lt;STRONG&gt;core dependency for AI platforms&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Enforce Responsible AI across:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Model layer&lt;/LI&gt;
&lt;LI&gt;Platform layer&lt;/LI&gt;
&lt;LI&gt;Runtime layer&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;Use &lt;STRONG&gt;layered security architecture&lt;/STRONG&gt;:
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Network isolation&lt;/LI&gt;
&lt;LI&gt;Policy enforcement&lt;/LI&gt;
&lt;LI&gt;Content filtering&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;Validate constraints early to avoid redesign&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Best Practices&lt;/H2&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Plan IP addressing specifically for &lt;STRONG&gt;AI workloads&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Use &lt;STRONG&gt;private endpoints and VNet integration by default&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Centralize model access through &lt;STRONG&gt;application layers&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Apply Responsible AI controls as &lt;STRONG&gt;mandatory, not optional&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;Design AI platforms with &lt;STRONG&gt;governance built-in from the start&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;Conclusion&lt;/H2&gt;
&lt;P&gt;&lt;SPAN data-teams="true"&gt;Operationalizing Responsible AI in Microsoft Azure goes beyond defining policies—it demands tight alignment across AI services, infrastructure, networking, and governance controls. A well-architected AI landing zone provides the foundation for securely deploying models, enforcing content filtering on outputs, and ensuring that access remains strictly within enterprise-defined boundaries.&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;AI services&lt;/LI&gt;
&lt;LI&gt;Infrastructure&lt;/LI&gt;
&lt;LI&gt;Networking&lt;/LI&gt;
&lt;LI&gt;Governance controls&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;A well-designed AI landing zone ensures that:&lt;/P&gt;
&lt;UL data-spread="false"&gt;
&lt;LI&gt;Models are deployed securely&lt;/LI&gt;
&lt;LI&gt;Outputs are governed and filtered&lt;/LI&gt;
&lt;LI&gt;Access is controlled within enterprise boundaries&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Responsible AI is not just a policy—it is an &lt;STRONG&gt;architectural outcome driven by platform design, network constraints, and enforcement mechanisms&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;&lt;SPAN data-teams="true"&gt;This holistic approach transforms Responsible AI from a conceptual guideline into a practical, enforceable outcome of system design. Crucially, early architectural decisions—particularly those related to networking, private access, and service compatibility—have a lasting impact on how effectively Responsible AI can be scaled across the organization.&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Wed, 06 May 2026 05:23:44 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/operationalizing-responsible-ai-in-microsoft-foundry-within/ba-p/4516869</guid>
      <dc:creator>Shruti9162</dc:creator>
      <dc:date>2026-05-06T05:23:44Z</dc:date>
    </item>
    <item>
      <title>Deploying Azure Resources with Managed HSM Keys Using Bicep</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/deploying-azure-resources-with-managed-hsm-keys-using-bicep/ba-p/4516971</link>
      <description>&lt;H2 data-section-id="14kwlto" data-start="766" data-end="793"&gt;Architecture Overview&lt;/H2&gt;
&lt;P data-start="795" data-end="819"&gt;The deployment includes:&lt;/P&gt;
&lt;UL data-start="821" data-end="1029"&gt;
&lt;LI data-section-id="12vqy4y" data-start="821" data-end="845"&gt;Managed HSM instance&lt;/LI&gt;
&lt;LI data-section-id="16xrtlo" data-start="846" data-end="873"&gt;Key creation inside HSM&lt;/LI&gt;
&lt;LI data-section-id="8xx89z" data-start="874" data-end="928"&gt;User-assigned managed identity / service principal&lt;/LI&gt;
&lt;LI data-section-id="19unc8k" data-start="929" data-end="964"&gt;Role assignments for key access&lt;/LI&gt;
&lt;LI data-section-id="1ulu1bd" data-start="965" data-end="1029"&gt;Azure resource (e.g., Storage / Databricks / Disk) using CMK&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1031" data-end="1040"&gt;&lt;STRONG data-start="1031" data-end="1040"&gt;Flow:&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL data-start="1041" data-end="1155"&gt;
&lt;LI data-section-id="1xiu8q5" data-start="1041" data-end="1064"&gt;Create Managed HSM&lt;/LI&gt;
&lt;LI data-section-id="bt4lol" data-start="1065" data-end="1091"&gt;Create encryption key&lt;/LI&gt;
&lt;LI data-section-id="q080sh" data-start="1092" data-end="1115"&gt;Assign permissions&lt;/LI&gt;
&lt;LI data-section-id="7f9jyq" data-start="1116" data-end="1155"&gt;Deploy resource with CMK reference&lt;/LI&gt;
&lt;/OL&gt;
&lt;H2 data-section-id="16qpaeu" data-start="1162" data-end="1181"&gt;Prerequisites&lt;/H2&gt;
&lt;P data-start="1183" data-end="1207"&gt;Before starting, ensure:&lt;/P&gt;
&lt;UL data-start="1208" data-end="1352"&gt;
&lt;LI data-section-id="1qk79he" data-start="1208" data-end="1254"&gt;Azure subscription with proper permissions&lt;/LI&gt;
&lt;LI data-section-id="6c9rgg" data-start="1255" data-end="1287"&gt;Access to create Managed HSM&lt;/LI&gt;
&lt;LI data-section-id="1i2075y" data-start="1288" data-end="1328"&gt;Knowledge of RBAC vs access policies&lt;/LI&gt;
&lt;LI data-section-id="lccr77" data-start="1329" data-end="1352"&gt;Bicep CLI installed&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="18wqp5s" data-start="1359" data-end="1392"&gt;Step 1: Deploy Managed HSM&lt;/H2&gt;
&lt;P data-start="1394" data-end="1442"&gt;Managed HSM is different from regular Key Vault:&lt;/P&gt;
&lt;UL data-start="1443" data-end="1530"&gt;
&lt;LI data-section-id="zmvddo" data-start="1443" data-end="1484"&gt;Uses &lt;STRONG data-start="1450" data-end="1463"&gt;RBAC only&lt;/STRONG&gt; (no access policies)&lt;/LI&gt;
&lt;LI data-section-id="lmut00" data-start="1485" data-end="1530"&gt;Requires &lt;STRONG data-start="1496" data-end="1530"&gt;security domain initialization&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1532" data-end="1550"&gt;&lt;STRONG data-start="1532" data-end="1550"&gt;Bicep snippet:&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;EM&gt;resource managedHsm 'Microsoft.KeyVault/managedHSMs@2023-02-01' = {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: hsmName&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;location: location&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;sku: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: 'Standard_B1'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;family: 'B'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;properties: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;tenantId: tenant().tenantId&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;initialAdminObjectIds: [&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;adminObjectId&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;]&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-section-id="18wqp5s" data-start="1359" data-end="1392"&gt;Step 2: Create Key in Managed HSM&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;EM&gt;resource key 'Microsoft.KeyVault/managedHSMs/keys@2023-02-01' = {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: '${managedHsm.name}/cmk-key'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;properties: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;kty: 'RSA-HSM'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;keySize: 2048&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-section-id="daskzu" data-start="2059" data-end="2091"&gt;Step 3: Assign Permissions&lt;/H2&gt;
&lt;P data-start="2093" data-end="2140"&gt;Since Managed HSM uses RBAC, assign roles like:&lt;/P&gt;
&lt;UL data-start="2142" data-end="2204"&gt;
&lt;LI data-section-id="ttxtbd" data-start="2142" data-end="2171"&gt;&lt;STRONG data-start="2144" data-end="2171"&gt;Managed HSM Crypto User&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="h48emi" data-start="2172" data-end="2204"&gt;&lt;STRONG data-start="2174" data-end="2204"&gt;Managed HSM Crypto Officer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;EM&gt;resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: guid(resourceGroup().id, principalId, roleDefinitionId)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;properties: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;principalId: principalId&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;roleDefinitionId: roleDefinitionId&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;scope: managedHsm&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-section-id="1da8j2j" data-start="2482" data-end="2523"&gt;Step 4: Configure Resource with CMK&lt;/H2&gt;
&lt;P data-start="2525" data-end="2560"&gt;Example: Storage Account encryption&lt;/P&gt;
&lt;P data-start="2525" data-end="2560"&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 100%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;EM&gt;resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: storageName&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;location: location&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;kind: 'StorageV2'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;sku: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;name: 'Standard_LRS'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;properties: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;encryption: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;keySource: 'Microsoft.Keyvault'&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;keyvaultproperties: {&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;keyname: key.name&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;keyvaulturi: managedHsm.properties.hsmUri&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;}&lt;/EM&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2 data-section-id="8bi4hj" data-start="2944" data-end="2967"&gt;Common Challenges&lt;/H2&gt;
&lt;H3 data-section-id="161slp4" data-start="2969" data-end="2993"&gt;1. Permission Issues&lt;/H3&gt;
&lt;UL data-start="2994" data-end="3081"&gt;
&lt;LI data-section-id="ijcy0f" data-start="2994" data-end="3043"&gt;Resource identity must have access to HSM key&lt;/LI&gt;
&lt;LI data-section-id="jwzwfn" data-start="3044" data-end="3081"&gt;Missing role → deployment failure&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="11r9wu3" data-start="3083" data-end="3109"&gt;2. Key Rotation Impact&lt;/H3&gt;
&lt;P data-start="3110" data-end="3132"&gt;When keys are rotated:&lt;/P&gt;
&lt;UL data-start="3133" data-end="3242"&gt;
&lt;LI data-section-id="1j42t7b" data-start="3133" data-end="3189"&gt;Resource may &lt;STRONG data-start="3148" data-end="3189"&gt;not automatically pick latest version&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="11i2ju7" data-start="3190" data-end="3242"&gt;You may need to redeploy or update configuration&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="1g57nqh" data-start="3244" data-end="3268"&gt;3. Deployment Errors&lt;/H3&gt;
&lt;P data-start="3269" data-end="3283"&gt;Typical issue:&lt;/P&gt;
&lt;P data-start="3286" data-end="3328"&gt;Storage/Databricks cannot access HSM key&lt;/P&gt;
&lt;P data-start="3330" data-end="3334"&gt;Fix:&lt;/P&gt;
&lt;UL data-start="3335" data-end="3427"&gt;
&lt;LI data-section-id="1og5zq1" data-start="3335" data-end="3376"&gt;Ensure correct &lt;STRONG data-start="3352" data-end="3376"&gt;RBAC role assignment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="lhn1m4" data-start="3377" data-end="3427"&gt;Validate &lt;STRONG data-start="3388" data-end="3427"&gt;principal ID used during deployment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2 data-section-id="j8by84" data-start="3434" data-end="3461"&gt;Key Rotation Strategy&lt;/H2&gt;
&lt;P data-start="3463" data-end="3484"&gt;Managed HSM supports:&lt;/P&gt;
&lt;UL data-start="3485" data-end="3526"&gt;
&lt;LI data-section-id="xlgvnq" data-start="3485" data-end="3504"&gt;Manual rotation&lt;/LI&gt;
&lt;LI data-section-id="jetw2i" data-start="3505" data-end="3526"&gt;Rotation policies&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="3528" data-end="3542"&gt;Best practice:&lt;/P&gt;
&lt;UL data-start="3543" data-end="3619"&gt;
&lt;LI data-section-id="yh468d" data-start="3543" data-end="3584"&gt;Use version-less key URI if supported&lt;/LI&gt;
&lt;LI data-section-id="2lnggm" data-start="3585" data-end="3619"&gt;Automate redeployment pipeline&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2 data-section-id="1im216t" data-start="3898" data-end="3940"&gt;When to Use Managed HSM vs Key Vault&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;/th&gt;&lt;th&gt;Managed HSM&lt;/th&gt;&lt;th&gt;Key Vault&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;FIPS Level&lt;/td&gt;&lt;td&gt;Level 3&lt;/td&gt;&lt;td&gt;Level 2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multi-tenant isolation&lt;/td&gt;&lt;td&gt;No (dedicated)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RBAC only&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Optional&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cost&lt;/td&gt;&lt;td&gt;Higher&lt;/td&gt;&lt;td&gt;Lower&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2 data-section-id="20nd6j" data-start="4163" data-end="4179"&gt;Conclusion&lt;/H2&gt;
&lt;P data-start="4181" data-end="4218"&gt;Using Managed HSM with Bicep enables:&lt;/P&gt;
&lt;UL data-start="4219" data-end="4345"&gt;
&lt;LI data-section-id="11thqyt" data-start="4219" data-end="4266"&gt;Stronger security with hardware-backed keys&lt;/LI&gt;
&lt;LI data-section-id="1w99h6q" data-start="4267" data-end="4313"&gt;Full automation via Infrastructure as Code&lt;/LI&gt;
&lt;LI data-section-id="1dqn9x4" data-start="4314" data-end="4345"&gt;Enterprise-grade compliance&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4347" data-end="4388"&gt;However, it requires careful handling of:&lt;/P&gt;
&lt;UL data-start="4389" data-end="4451"&gt;
&lt;LI data-section-id="16zsxky" data-start="4389" data-end="4409"&gt;RBAC permissions&lt;/LI&gt;
&lt;LI data-section-id="1yu906j" data-start="4410" data-end="4426"&gt;Key rotation&lt;/LI&gt;
&lt;LI data-section-id="vs4gxo" data-start="4427" data-end="4451"&gt;Resource integration&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Tue, 05 May 2026 09:30:46 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/deploying-azure-resources-with-managed-hsm-keys-using-bicep/ba-p/4516971</guid>
      <dc:creator>Roslin_Nivetha</dc:creator>
      <dc:date>2026-05-05T09:30:46Z</dc:date>
    </item>
    <item>
      <title>Building an AI Agent for Azure Infrastructure Validation</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-an-ai-agent-for-azure-infrastructure-validation/ba-p/4516936</link>
      <description>&lt;img&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;1. Introduction&lt;/H2&gt;
&lt;P&gt;&lt;STRONG&gt;Infrastructure consistency is critical in large-scale Azure environments, especially in migration programs and DevOps-driven deployments. While Infrastructure as Code (IaC) using Terraform improves reproducibility, it does not fully eliminate:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Manual errors in design specifications&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Drift between Terraform and deployed resources&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Misalignment between approved design (Excel/architecture docs) and deployed state&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;To address this, we propose building an AI-powered Infrastructure Validation Agent that continuously validates and reconciles:&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Excel (Source of Truth)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform (.tf files)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure Deployed Resources&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;STRONG&gt;This blog explains the architecture, implementation, validation logic, and real-world applicability of such an agent.&lt;/STRONG&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;
&lt;H2&gt;2. Problem Statement&lt;/H2&gt;
&lt;P&gt;&lt;STRONG&gt;In enterprise environments, infrastructure data flows through multiple stages:&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;
&lt;TABLE style="" border="1"&gt;
&lt;TBODY&gt;
&lt;TR style=""&gt;
&lt;TH style=""&gt;&lt;STRONG&gt;Source&lt;/STRONG&gt;&lt;/TH&gt;
&lt;TH style=""&gt;&lt;STRONG&gt;Purpose&lt;/STRONG&gt;&lt;/TH&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Excel / Design Sheets&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Approved architecture specifications&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Terraform&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Infrastructure as Code implementation&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Azure Portal&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Actual deployed infrastructure&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;COLGROUP&gt;&lt;COL style="width: 50.00%" /&gt;&lt;COL style="width: 50.00%" /&gt;&lt;/COLGROUP&gt;&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;H3&gt;3.Common Challenges&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Configuration mismatches across stages&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Drift due to manual portal changes&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Incorrect SKU, region, or configuration deployment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Lack of automated validation before and after deployment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;The absence of unified validation leads to compliance risks, deployment errors, and operational inefficiencies.&lt;/STRONG&gt;&lt;/P&gt;
&lt;H2&gt;4. Solution Overview&lt;/H2&gt;
&lt;P&gt;&lt;STRONG&gt;The proposed solution is an AI-powered validation agent that:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Ingests Excel as configuration input&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Parses Terraform configurations&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Fetches deployed resource details from Azure&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2&gt;5. Architecture Overview&lt;/H2&gt;
&lt;H3&gt;High-Level Architecture Components&lt;/H3&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;Input Layer&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Excel file (configuration source)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Processing Layer&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Terraform Parser&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure Resource Fetcher&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;AI-based Validator (optional reasoning layer)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Comparison Engine&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Schema-based comparison&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Drift detection logic&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Output Layer&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Validation report (JSON / Excel / HTML)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Hosting&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure Function App&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Optional Enhancements&lt;/STRONG&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Azure AI Search for semantic matching and reasoning&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;H2&gt;6. Agent Design (Modular Components)&lt;/H2&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;
&lt;TABLE style="" border="1"&gt;
&lt;TBODY&gt;
&lt;TR style=""&gt;
&lt;TH style=""&gt;&lt;STRONG&gt;Module&lt;/STRONG&gt;&lt;/TH&gt;
&lt;TH style=""&gt;&lt;STRONG&gt;Description&lt;/STRONG&gt;&lt;/TH&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Excel Reader&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Reads and standardizes input&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Terraform Parser&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Extracts resource configuration&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Azure Fetcher&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Queries deployed resources&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Comparator Engine&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Identifies mismatches&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;AI Validator&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Enhances validation and recommendations&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Report Generator&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD style=""&gt;&lt;STRONG&gt;Produces actionable outputs&lt;/STRONG&gt;&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;COLGROUP&gt;&lt;COL style="width: 50.00%" /&gt;&lt;COL style="width: 50.00%" /&gt;&lt;/COLGROUP&gt;&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;
&lt;P&gt;`&lt;/P&gt;
&lt;/DIV&gt;
&lt;H2&gt;7. Agent Design&lt;BR /&gt;Step 1: Read Excel Input&lt;/H2&gt;
&lt;P&gt;import pandas as pd&lt;/P&gt;
&lt;P&gt;ef read_excel(file_path):&lt;/P&gt;
&lt;P&gt;df = pd.read_excel(file_path)&lt;/P&gt;
&lt;P&gt;df.columns = df.columns.str.strip()&lt;/P&gt;
&lt;P&gt;return df&lt;/P&gt;
&lt;P&gt;excel_df = read_excel("infra_config.xlsx")&lt;/P&gt;
&lt;P&gt;print(excel_df.head())&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;
&lt;H2&gt;Step 2:Parse Terraform Files&lt;/H2&gt;
&lt;P&gt;import hcl2&lt;/P&gt;
&lt;P&gt;def parse_terraform(file_path):&lt;/P&gt;
&lt;P&gt;with open(file_path, 'r') as file:&lt;/P&gt;
&lt;P&gt;data = hcl2.load(file)&lt;/P&gt;
&lt;P&gt;resources = []&lt;/P&gt;
&lt;P&gt;for resource_type in data.get('resource', []):&lt;/P&gt;
&lt;P&gt;for rtype, instances in resource_type.items():&lt;/P&gt;
&lt;P&gt;for name, config in instances.items():&lt;/P&gt;
&lt;P&gt;resource = {&lt;/P&gt;
&lt;P&gt;"resource_type": rtype,&lt;/P&gt;
&lt;P&gt;"resource_name": name,&lt;/P&gt;
&lt;P&gt;"config": config&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;resources.append(resource)&lt;/P&gt;
&lt;P&gt;return resources&lt;/P&gt;
&lt;P&gt;tf_resources = parse_terraform("main.tf")&lt;/P&gt;
&lt;P&gt;print(tf_resources)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;Step 3:Parse Terraform Files&lt;/H2&gt;
&lt;P&gt;from azure.identity import DefaultAzureCredential&lt;/P&gt;
&lt;P&gt;from azure.mgmt.resource import ResourceManagementClient&lt;/P&gt;
&lt;P&gt;credential = DefaultAzureCredential()&lt;/P&gt;
&lt;P&gt;subscription_id = "your-subscription-id"&lt;/P&gt;
&lt;P&gt;resource_client = ResourceManagementClient(credential, subscription_id)&lt;/P&gt;
&lt;P&gt;def fetch_azure_resources():&lt;/P&gt;
&lt;P&gt;resources = []&lt;/P&gt;
&lt;P&gt;for resource in resource_client.resources.list():&lt;/P&gt;
&lt;P&gt;res = {&lt;/P&gt;
&lt;P&gt;"name": resource.name,&lt;/P&gt;
&lt;P&gt;"type": resource.type,&lt;/P&gt;
&lt;P&gt;"location": resource.location,&lt;/P&gt;
&lt;P&gt;"id": resource.id&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;resources.append(res)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;return resources&lt;/P&gt;
&lt;P&gt;azure_resources = fetch_azure_resources()&lt;/P&gt;
&lt;P&gt;print(azure_resources)&lt;/P&gt;
&lt;H2&gt;Step 4:Normalize Data&lt;/H2&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;def normalize_excel(df):&lt;/P&gt;
&lt;P&gt;return df.to_dict(orient='records')&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;def normalize_tf(tf_resources):&lt;/P&gt;
&lt;P&gt;normalized = []&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;for res in tf_resources:&lt;/P&gt;
&lt;P&gt;normalized.append({&lt;/P&gt;
&lt;P&gt;"resource_name": res["resource_name"],&lt;/P&gt;
&lt;P&gt;"resource_type": res["resource_type"],&lt;/P&gt;
&lt;P&gt;"config": res["config"]&lt;/P&gt;
&lt;P&gt;})&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;return normalized&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;def normalize_azure(azure_resources):&lt;/P&gt;
&lt;P&gt;normalized = []&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;for res in azure_resources:&lt;/P&gt;
&lt;P&gt;normalized.append({&lt;/P&gt;
&lt;P&gt;"resource_name": res["name"],&lt;/P&gt;
&lt;P&gt;"resource_type": res["type"],&lt;/P&gt;
&lt;P&gt;"location": res["location"]&lt;/P&gt;
&lt;P&gt;})&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;return normalized&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;Step 5: Validation Logic (Drift Detection)&lt;/H2&gt;
&lt;P&gt;def compare_resources(excel_data, tf_data, azure_data):&lt;/P&gt;
&lt;P&gt;issues = []&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;for excel_res in excel_data:&lt;/P&gt;
&lt;P&gt;name = excel_res['resource_name']&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;tf_match = next((r for r in tf_data if r['resource_name'] == name), None)&lt;/P&gt;
&lt;P&gt;az_match = next((r for r in azure_data if r['resource_name'] == name), None)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;if not tf_match:&lt;/P&gt;
&lt;P&gt;issues.append({&lt;/P&gt;
&lt;P&gt;"resource": name,&lt;/P&gt;
&lt;P&gt;"issue": "Missing in Terraform",&lt;/P&gt;
&lt;P&gt;"severity": "High"&lt;/P&gt;
&lt;P&gt;})&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;if not az_match:&lt;/P&gt;
&lt;P&gt;issues.append({&lt;/P&gt;
&lt;P&gt;"resource": name,&lt;/P&gt;
&lt;P&gt;"issue": "Missing in Azure",&lt;/P&gt;
&lt;P&gt;"severity": "Critical"&lt;/P&gt;
&lt;P&gt;})&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;if tf_match and az_match:&lt;/P&gt;
&lt;P&gt;if excel_res['region'] != az_match.get('location'):&lt;/P&gt;
&lt;P&gt;issues.append({&lt;/P&gt;
&lt;P&gt;"resource": name,&lt;/P&gt;
&lt;P&gt;"issue": "Region mismatch",&lt;/P&gt;
&lt;P&gt;"expected": excel_res['region'],&lt;/P&gt;
&lt;P&gt;"actual": az_match.get('location')&lt;/P&gt;
&lt;P&gt;})&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;return issues&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;drift_report = compare_resources(&lt;/P&gt;
&lt;P&gt;normalize_excel(excel_df),&lt;/P&gt;
&lt;P&gt;normalize_tf(tf_resources),&lt;/P&gt;
&lt;P&gt;normalize_azure(azure_resources)&lt;/P&gt;
&lt;P&gt;)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;print(drift_report)&lt;/P&gt;
&lt;H2&gt;Step 6: Export Report to Excel&lt;/H2&gt;
&lt;P&gt;Sample validation&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;
&lt;TABLE style="" border="1"&gt;
&lt;THEAD&gt;
&lt;TR style=""&gt;
&lt;TH style=""&gt;Resource&lt;/TH&gt;
&lt;TH style=""&gt;Issue&lt;/TH&gt;
&lt;TH style=""&gt;Expected&lt;/TH&gt;
&lt;TH style=""&gt;Actual&lt;/TH&gt;
&lt;TH style=""&gt;Severity&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;func-app-01&lt;/TD&gt;
&lt;TD style=""&gt;Missing in Terraform&lt;/TD&gt;
&lt;TD style=""&gt;-&lt;/TD&gt;
&lt;TD style=""&gt;-&lt;/TD&gt;
&lt;TD style=""&gt;High&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;search-01&lt;/TD&gt;
&lt;TD style=""&gt;SKU mismatch&lt;/TD&gt;
&lt;TD style=""&gt;Standard&lt;/TD&gt;
&lt;TD style=""&gt;Basic&lt;/TD&gt;
&lt;TD style=""&gt;Medium&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR style=""&gt;
&lt;TD style=""&gt;webapp-01&lt;/TD&gt;
&lt;TD style=""&gt;Region mismatch&lt;/TD&gt;
&lt;TD style=""&gt;East US&lt;/TD&gt;
&lt;TD style=""&gt;West Europe&lt;/TD&gt;
&lt;TD style=""&gt;High&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;COLGROUP&gt;&lt;COL style="width: 20.00%" /&gt;&lt;COL style="width: 20.00%" /&gt;&lt;COL style="width: 20.00%" /&gt;&lt;COL style="width: 20.00%" /&gt;&lt;COL style="width: 20.00%" /&gt;&lt;/COLGROUP&gt;&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;BR /&gt;&lt;BR /&gt;&lt;/img&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 05 May 2026 06:05:23 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-an-ai-agent-for-azure-infrastructure-validation/ba-p/4516936</guid>
      <dc:creator>ranjsharma</dc:creator>
      <dc:date>2026-05-05T06:05:23Z</dc:date>
    </item>
    <item>
      <title>Building Multi-File Refactoring Agents with GitHub Copilot Workspace</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-multi-file-refactoring-agents-with-github-copilot/ba-p/4516932</link>
      <description>&lt;H2 data-section-id="13ax1s5" data-start="266" data-end="281"&gt;Introduction&lt;/H2&gt;
&lt;P data-start="283" data-end="626"&gt;AI-assisted development continues to evolve beyond inline code suggestions toward &lt;STRONG data-start="365" data-end="401"&gt;end-to-end engineering workflows&lt;/STRONG&gt;. While tools such as GitHub Copilot have significantly improved developer productivity at the function and file level, modern applications demand capabilities that operate across the entire repository.&lt;/P&gt;
&lt;P data-start="628" data-end="790"&gt;Refactoring, modernization, and architectural changes rarely occur in isolation. They require &lt;STRONG data-start="722" data-end="789"&gt;coordinated updates across multiple files, services, and layers&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P data-start="792" data-end="946"&gt;With GitHub Copilot Workspace, developers can now move from incremental edits to &lt;STRONG data-start="886" data-end="931"&gt;intent-driven, multi-file transformations&lt;/STRONG&gt; powered by AI.&lt;/P&gt;
&lt;P data-start="948" data-end="975"&gt;This article walks through:&lt;/P&gt;
&lt;UL data-start="976" data-end="1201"&gt;
&lt;LI data-section-id="1g6i0g0" data-start="976" data-end="1041"&gt;The role of Copilot Workspace in modern development workflows&lt;/LI&gt;
&lt;LI data-section-id="tti5ql" data-start="1042" data-end="1092"&gt;How to access and use the Workspace experience&lt;/LI&gt;
&lt;LI data-section-id="7layzd" data-start="1093" data-end="1141"&gt;A practical, end-to-end refactoring scenario&lt;/LI&gt;
&lt;LI data-section-id="tafst" data-start="1142" data-end="1201"&gt;Key benefits and considerations for enterprise adoption&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="12pib85" data-start="1208" data-end="1253"&gt;From Code Assistance to Code Orchestration&lt;/H2&gt;
&lt;P data-start="1255" data-end="1418"&gt;Traditional AI-assisted development focuses on generating code snippets in response to local context. While effective, this approach is limited when tasks require:&lt;/P&gt;
&lt;UL data-start="1420" data-end="1502"&gt;
&lt;LI data-section-id="ico30z" data-start="1420" data-end="1446"&gt;Cross-file consistency&lt;/LI&gt;
&lt;LI data-section-id="1oocydm" data-start="1447" data-end="1474"&gt;Architectural alignment&lt;/LI&gt;
&lt;LI data-section-id="199ms3e" data-start="1475" data-end="1502"&gt;Large-scale refactoring&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="1504" data-end="1551"&gt;Copilot Workspace introduces a different model:&lt;/P&gt;
&lt;P data-start="1555" data-end="1631"&gt;Developers define &lt;EM data-start="1573" data-end="1581"&gt;intent&lt;/EM&gt;, and AI orchestrates &lt;EM data-start="1603" data-end="1630"&gt;repository-wide execution&lt;/EM&gt;.&lt;/P&gt;
&lt;P data-start="1633" data-end="1661"&gt;This enables a shift toward:&lt;/P&gt;
&lt;UL data-start="1662" data-end="1767"&gt;
&lt;LI data-section-id="dwf1qp" data-start="1662" data-end="1691"&gt;Task-oriented development&lt;/LI&gt;
&lt;LI data-section-id="10enixb" data-start="1692" data-end="1732"&gt;Structured planning before execution&lt;/LI&gt;
&lt;LI data-section-id="vdkmoe" data-start="1733" data-end="1767"&gt;Coordinated multi-file updates&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="9fc943" data-start="1774" data-end="1815"&gt;Getting Started with Copilot Workspace&lt;/H2&gt;
&lt;P data-start="1817" data-end="1973"&gt;Access to GitHub Copilot Workspace depends on feature availability and organizational enablement. The following entry points are commonly used:&lt;/P&gt;
&lt;H3 data-section-id="r1un9z" data-start="1975" data-end="2003"&gt;Access from a Repository&lt;/H3&gt;
&lt;UL data-start="2005" data-end="2133"&gt;
&lt;LI data-section-id="1wi2ga5" data-start="2005" data-end="2074"&gt;Navigate to a repository in GitHub&lt;/LI&gt;
&lt;LI data-section-id="1enzcsz" data-start="2075" data-end="2133"&gt;Select the &lt;STRONG data-start="2088" data-end="2099"&gt;Copilot&lt;/STRONG&gt; option or &lt;STRONG data-start="2110" data-end="2131"&gt;Open in Workspace&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3 data-section-id="ow11gq" data-start="2330" data-end="2357"&gt;Direct Workspace Access&lt;/H3&gt;
&lt;P data-start="2359" data-end="2384"&gt;You can also navigate to:&lt;/P&gt;
&lt;P&gt;https://github.com/copilot/workspace&lt;/P&gt;
&lt;P data-start="2431" data-end="2478"&gt;If enabled, this opens the Workspace interface.&lt;/P&gt;
&lt;H2 data-section-id="1hin9pf" data-start="2485" data-end="2526"&gt;Understanding the Workspace Experience&lt;/H2&gt;
&lt;P data-start="2528" data-end="2606"&gt;Copilot Workspace provides a structured interface designed for task execution:&lt;/P&gt;
&lt;UL data-start="2608" data-end="2830"&gt;
&lt;LI data-section-id="1ci5sm7" data-start="2608" data-end="2657"&gt;&lt;STRONG data-start="2610" data-end="2626"&gt;Intent Panel&lt;/STRONG&gt; – Define the desired outcome&lt;/LI&gt;
&lt;LI data-section-id="5nkqje" data-start="2658" data-end="2707"&gt;&lt;STRONG data-start="2660" data-end="2677"&gt;Planning View&lt;/STRONG&gt; – Review AI-generated steps&lt;/LI&gt;
&lt;LI data-section-id="yw1p0j" data-start="2708" data-end="2762"&gt;&lt;STRONG data-start="2710" data-end="2731"&gt;Multi-file Editor&lt;/STRONG&gt; – Inspect and refine changes&lt;/LI&gt;
&lt;LI data-section-id="y2ujnn" data-start="2763" data-end="2830"&gt;&lt;STRONG data-start="2765" data-end="2787"&gt;Execution Controls&lt;/STRONG&gt; – Apply updates and create pull requests&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="2832" data-end="2926"&gt;This workflow emphasizes &lt;STRONG data-start="2857" data-end="2885"&gt;transparency and control&lt;/STRONG&gt;, ensuring developers remain in the loop.&lt;/P&gt;
&lt;H2 data-section-id="17xbmye" data-start="2933" data-end="2948"&gt;Key Benefits&lt;/H2&gt;
&lt;H3 data-section-id="1dmkajg" data-start="2950" data-end="2985"&gt;Repository-Aware Intelligence&lt;/H3&gt;
&lt;P data-start="2986" data-end="3095"&gt;Copilot Workspace analyzes relationships across files, enabling more accurate and consistent transformations.&lt;/P&gt;
&lt;H3 data-section-id="snf45" data-start="3102" data-end="3131"&gt;Intent-Driven Workflows&lt;/H3&gt;
&lt;P data-start="3132" data-end="3225"&gt;Developers focus on &lt;EM data-start="3152" data-end="3175"&gt;what needs to be done&lt;/EM&gt;, while the system determines &lt;EM data-start="3205" data-end="3224"&gt;how to execute it&lt;/EM&gt;.&lt;/P&gt;
&lt;H3 data-section-id="1ysdw4m" data-start="3232" data-end="3267"&gt;Consistent Multi-File Updates&lt;/H3&gt;
&lt;P data-start="3268" data-end="3354"&gt;Changes are applied uniformly across controllers, services, and supporting components.&lt;/P&gt;
&lt;H3 data-section-id="1ac01hp" data-start="3361" data-end="3408"&gt;Accelerated Refactoring and Modernization&lt;/H3&gt;
&lt;P data-start="3409" data-end="3490"&gt;Large-scale changes can be executed efficiently, reducing manual effort and risk.&lt;/P&gt;
&lt;H2 data-section-id="qxsl9q" data-start="3497" data-end="3546"&gt;Practical Scenario: Modernizing Authentication&lt;/H2&gt;
&lt;P data-start="3548" data-end="3639"&gt;To illustrate the capabilities of Copilot Workspace, consider a common enterprise scenario:&lt;/P&gt;
&lt;P data-start="3641" data-end="3835"&gt;An application currently uses &lt;STRONG data-start="3671" data-end="3704"&gt;password-based authentication&lt;/STRONG&gt;, implemented across multiple layers. The goal is to migrate to a &lt;STRONG data-start="3770" data-end="3806"&gt;token-based authentication model&lt;/STRONG&gt; using a centralized service.&lt;/P&gt;
&lt;H2 data-section-id="in2amk" data-start="3842" data-end="3858"&gt;Initial State&lt;/H2&gt;
&lt;P data-start="3860" data-end="3919"&gt;Authentication logic is distributed across the application:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;ValidateUser(username, password)&lt;/LI-CODE&gt;
&lt;P&gt;ValidateUser(username, password)&lt;/P&gt;
&lt;P data-start="3969" data-end="3993"&gt;This pattern appears in:&lt;/P&gt;
&lt;UL data-start="3994" data-end="4037"&gt;
&lt;LI data-section-id="60xd7r" data-start="3994" data-end="4009"&gt;Controllers&lt;/LI&gt;
&lt;LI data-section-id="1cyzp5y" data-start="4010" data-end="4022"&gt;Services&lt;/LI&gt;
&lt;LI data-section-id="eiujd0" data-start="4023" data-end="4037"&gt;Middleware&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="6sdecw" data-start="4044" data-end="4066"&gt;Defining the Intent&lt;/H2&gt;
&lt;P data-start="4068" data-end="4162"&gt;Within GitHub Copilot Workspace, the developer provides a structured instruction:&lt;/P&gt;
&lt;P data-start="4166" data-end="4360"&gt;Replace all password-based authentication with token-based authentication using AuthService. Update all references, introduce dependency injection, and ensure consistency across the application.&lt;/P&gt;
&lt;H2 data-section-id="scpyak" data-start="4367" data-end="4387"&gt;AI-Generated Plan&lt;/H2&gt;
&lt;P data-start="4389" data-end="4465"&gt;Copilot Workspace analyzes the repository and produces a plan that includes:&lt;/P&gt;
&lt;UL data-start="4467" data-end="4691"&gt;
&lt;LI data-section-id="n8q085" data-start="4467" data-end="4511"&gt;Identifying all usages of ValidateUser&lt;/LI&gt;
&lt;LI data-section-id="1gcti0p" data-start="4512" data-end="4564"&gt;Introducing a centralized authentication service&lt;/LI&gt;
&lt;LI data-section-id="bjw9oq" data-start="4565" data-end="4606"&gt;Updating controllers to return tokens&lt;/LI&gt;
&lt;LI data-section-id="l424ad" data-start="4607" data-end="4654"&gt;Refactoring middleware for token validation&lt;/LI&gt;
&lt;LI data-section-id="1qp0s59" data-start="4655" data-end="4691"&gt;Configuring dependency injection&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-start="4693" data-end="4766"&gt;This plan provides a &lt;STRONG data-start="4714" data-end="4765"&gt;transparent view of the proposed transformation&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H2 data-section-id="xvky6h" data-start="4773" data-end="4792"&gt;Refactored State&lt;/H2&gt;
&lt;H3 data-section-id="y2g7m2" data-start="4794" data-end="4832"&gt;Centralized Authentication Service&lt;/H3&gt;
&lt;LI-CODE lang="csharp"&gt;public interface IAuthService
{
    string GenerateToken(string username);
    bool ValidateToken(string token);
}&lt;/LI-CODE&gt;&lt;LI-CODE lang="csharp"&gt;public class AuthService : IAuthService
{
    public string GenerateToken(string username)
    {
        return Convert.ToBase64String(Encoding.UTF8.GetBytes(username));
    }

    public bool ValidateToken(string token)
    {
        return !string.IsNullOrEmpty(token);
    }
}&lt;/LI-CODE&gt;
&lt;H3 data-section-id="1lduxpr" data-start="5264" data-end="5286"&gt;Updated Controller&lt;/H3&gt;
&lt;LI-CODE lang="csharp"&gt;public class UserController : Controller
{
private readonly IAuthService _authService;

public UserController(IAuthService authService)
{
_authService = authService;
}

public IActionResult Login(string username, string password)
{
var token = _authService.GenerateToken(username);
return Ok(new { Token = token });
}&lt;/LI-CODE&gt;
&lt;H3 data-section-id="pewolb" data-start="5680" data-end="5702"&gt;Updated Middleware&lt;/H3&gt;
&lt;LI-CODE lang="csharp"&gt;public class AuthMiddleware
{
private readonly RequestDelegate _next;
private readonly IAuthService _authService;

public AuthMiddleware(RequestDelegate next, IAuthService authService)
{
_next = next;
_authService = authService;
}

public async Task Invoke(HttpContext context)
{
var token = context.Request.Headers["Authorization"];

if (!_authService.ValidateToken(token))
{
context.Response.StatusCode = 401;
return;
}

await _next(context);
}
}&lt;/LI-CODE&gt;
&lt;H3 data-section-id="stfrq6" data-start="6285" data-end="6309"&gt;Dependency Injection&lt;/H3&gt;
&lt;LI-CODE lang="csharp"&gt;services.AddScoped&amp;lt;IAuthService, AuthService&amp;gt;();&lt;/LI-CODE&gt;
&lt;H2 data-section-id="1273t9r" data-start="6380" data-end="6390"&gt;Outcome&lt;/H2&gt;
&lt;P data-start="6392" data-end="6444"&gt;The transformation delivers measurable improvements:&lt;/P&gt;
&lt;UL data-start="6446" data-end="6597"&gt;
&lt;LI data-section-id="y6ac6v" data-start="6446" data-end="6486"&gt;&lt;STRONG data-start="6448" data-end="6484"&gt;Centralized authentication logic&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="4lsd73" data-start="6487" data-end="6518"&gt;&lt;STRONG data-start="6489" data-end="6516"&gt;Improved security model&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="p1xvzp" data-start="6519" data-end="6566"&gt;&lt;STRONG data-start="6521" data-end="6564"&gt;Consistent implementation across layers&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="10a1wyw" data-start="6567" data-end="6597"&gt;&lt;STRONG data-start="6569" data-end="6595"&gt;Reduced technical debt&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="1syppf4" data-start="6604" data-end="6634"&gt;Best Practices for Adoption&lt;/H2&gt;
&lt;P data-start="6636" data-end="6662"&gt;To maximize effectiveness:&lt;/P&gt;
&lt;UL data-start="6664" data-end="6854"&gt;
&lt;LI data-section-id="b3o9yr" data-start="6664" data-end="6704"&gt;Provide &lt;STRONG data-start="6674" data-end="6702"&gt;clear, structured intent&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-section-id="fy9ddi" data-start="6705" data-end="6748"&gt;Review generated plans before execution&lt;/LI&gt;
&lt;LI data-section-id="7yicq2" data-start="6749" data-end="6801"&gt;Validate changes through testing and code review&lt;/LI&gt;
&lt;LI data-section-id="xdb84j" data-start="6802" data-end="6854"&gt;Start with &lt;STRONG data-start="6815" data-end="6837"&gt;targeted scenarios&lt;/STRONG&gt; before scaling&lt;/LI&gt;
&lt;/UL&gt;
&lt;H2 data-section-id="8dtpi" data-start="7101" data-end="7114"&gt;Conclusion&lt;/H2&gt;
&lt;P data-start="7116" data-end="7370"&gt;GitHub Copilot Workspace represents a meaningful advancement in AI-assisted development. By enabling developers to define intent and delegate execution, it supports &lt;STRONG data-start="7294" data-end="7369"&gt;repository-wide transformations with greater consistency and efficiency&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P data-start="7372" data-end="7540"&gt;As development workflows continue to evolve, tools that combine &lt;STRONG data-start="7436" data-end="7482"&gt;context awareness, planning, and execution&lt;/STRONG&gt; will play a central role in modern engineering practices.&lt;/P&gt;</description>
      <pubDate>Tue, 05 May 2026 03:49:40 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/building-multi-file-refactoring-agents-with-github-copilot/ba-p/4516932</guid>
      <dc:creator>Devi_Priya</dc:creator>
      <dc:date>2026-05-05T03:49:40Z</dc:date>
    </item>
    <item>
      <title>Build and Deploy Logic App Workflows Using Visual Studio Code and CI/CD Pipeline</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/build-and-deploy-logic-app-workflows-using-visual-studio-code/ba-p/4516931</link>
      <description>&lt;P&gt;Throughout this guide, you'll create a Standard logic app workspace and project, build your workflow, and deploy it as a Standard logic app resource in Azure. This enables your workflow to run in a single-tenant Azure Logic Apps environment or within an App Service Environment v3 (restricted to Windows-based App Service plans).&lt;/P&gt;
&lt;P&gt;Key advantages of Standard logic apps include:&lt;/P&gt;
&lt;P&gt;You can locally develop, debug, run, and test workflows within the Visual Studio Code environment. Although both the Azure portal and Visual Studio Code support building, running, and deploying Standard logic app resources and workflows, Visual Studio Code allows you to perform all these actions locally, offering greater flexibility during development.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Prerequisites&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Visual Studio Code&lt;/LI&gt;
&lt;LI&gt;Azure Account extension for Visual Studio Code&lt;/LI&gt;
&lt;LI&gt;Download and install the following Visual Studio Code dependencies for your specific operating system using either method:&lt;/LI&gt;
&lt;/OL&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;U&gt;Install all dependencies manually&lt;/U&gt;&amp;nbsp;--&amp;gt;&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/azure/logic-apps/create-single-tenant-workflows-visual-studio-code#dependency-installer:~:text=ignore%20this%20message.-,Install%20each%20dependency%20separately,Expand%20table,-Dependency" target="_blank"&gt;For manual installation&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;U&gt;Install all dependencies automatically.&lt;/U&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Starting with version&amp;nbsp;&lt;STRONG&gt;2.81.5&lt;/STRONG&gt;, the&amp;nbsp;&lt;STRONG&gt;Azure Logic Apps (Standard) extension&lt;/STRONG&gt;&amp;nbsp;for Visual Studio Code includes a dependency installer that automatically installs all the required dependencies in a new binary folder and leaves any existing dependencies unchanged.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;For more information, see&amp;nbsp;&lt;A href="https://techcommunity.microsoft.com/t5/azure-integration-services-blog/making-it-easy-to-get-started-with-the-azure-logic-apps-standard/ba-p/3979643" target="_blank"&gt;Get started more easily with the Azure Logic Apps (Standard) extension for Visual Studio Code&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;This extension includes the following dependencies:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Dependency&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Description&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;A href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp" target="_blank"&gt;C# for Visual Studio Code&lt;/A&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Enables F5 functionality to run your workflow.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;A href="https://github.com/Azure/Azurite#visual-studio-code-extension" target="_blank"&gt;Azurite for Visual Studio Code&lt;/A&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Provides a local data store and emulator to use with Visual Studio Code so that you can work on your logic app project and run your workflows in your local development environment. If you don't want Azurite to automatically start, you can disable this option:&lt;BR /&gt;&lt;BR /&gt;1. On the&amp;nbsp;File&amp;nbsp;menu, select&amp;nbsp;Preferences&amp;nbsp;&amp;gt;&amp;nbsp;Settings.&lt;BR /&gt;&lt;BR /&gt;2. On the&amp;nbsp;User&amp;nbsp;tab, select&amp;nbsp;Extensions&amp;nbsp;&amp;gt;&amp;nbsp;Azure Logic Apps (Standard).&lt;BR /&gt;&lt;BR /&gt;3. Find the setting named&amp;nbsp;Azure Logic Apps Standard: Auto Start Azurite, and clear the selected checkbox.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;A href="https://dotnet.microsoft.com/download/dotnet/6.0" target="_blank"&gt;.NET SDK 6.x.x&lt;/A&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Includes the .NET Runtime 6.x.x, a prerequisite for the Azure Logic Apps (Standard) runtime.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Azure Functions Core Tools - 4.x version&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Installs the version based on your operating system (&lt;A href="https://github.com/Azure/azure-functions-core-tools/releases" target="_blank"&gt;Windows&lt;/A&gt;,&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=macos#install-the-azure-functions-core-tools" target="_blank"&gt;macOS&lt;/A&gt;, or&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=linux#install-the-azure-functions-core-tools" target="_blank"&gt;Linux&lt;/A&gt;).&lt;BR /&gt;&lt;BR /&gt;These tools include a version of the same runtime that powers the Azure Functions runtime, which the Azure Logic Apps (Standard) extension uses in Visual Studio Code.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;A href="https://nodejs.org/en/download/releases/" target="_blank"&gt;Node.js version 16.x.x unless a newer version is already installed&lt;/A&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Required to enable the&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-add-run-inline-code" target="_blank"&gt;Inline Code Operations action&lt;/A&gt; that runs JavaScript.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;Set up Visual Studio code&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;To make sure that all the extensions are correctly installed, reload or restart Visual Studio Code.&lt;/LI&gt;
&lt;/UL&gt;
&lt;UL&gt;
&lt;LI&gt;Confirm that the&amp;nbsp;&lt;STRONG&gt;Azure Logic Apps Standard: Project Runtime&lt;/STRONG&gt;&amp;nbsp;setting for the Azure Logic Apps (Standard) extension is set to version&amp;nbsp;&lt;STRONG&gt;~4&lt;/STRONG&gt;:&lt;/LI&gt;
&lt;LI&gt;On the File menu, go to Preferences &amp;gt; Settings.&lt;/LI&gt;
&lt;LI&gt;On the User tab, go to &amp;gt; Extensions &amp;gt; Azure Logic Apps (Standard).&lt;/LI&gt;
&lt;LI&gt;You can find the Azure Logic Apps Standard: Project Runtime setting here or use the search box to find other settings:&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Connect to your Azure account&lt;/STRONG&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;On the Visual Studio Code Activity Bar, select the Azure icon.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In the&amp;nbsp;&lt;STRONG&gt;Azure&lt;/STRONG&gt;&amp;nbsp;window, on the&amp;nbsp;&lt;STRONG&gt;Workspace&lt;/STRONG&gt;&amp;nbsp;section toolbar, from the&amp;nbsp;&lt;STRONG&gt;Azure Logic Apps&lt;/STRONG&gt;&amp;nbsp;menu, select&amp;nbsp;&lt;STRONG&gt;Create New Project&lt;/STRONG&gt;.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;From the templates list that appears, select either&amp;nbsp;&lt;STRONG&gt;Stateful Workflow&lt;/STRONG&gt;or&amp;nbsp;&lt;STRONG&gt;Stateless Workflow&lt;/STRONG&gt;.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;Provide a name for your workflow and press Enter.&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;If Visual Studio Code prompts you to open your project in the current Visual Studio Code or in a new Visual Studio Code window, select&amp;nbsp;&lt;STRONG&gt;Open in current window&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;Visual Studio Code finishes creating your project.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;The Explorer pane shows your project, which now includes automatically generated project files. For example, the project has a folder that shows your workflow's name. Inside this folder, the&amp;nbsp;&lt;STRONG&gt;workflow.json&lt;/STRONG&gt; file contains your workflow's underlying JSON definition.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;Open the&amp;nbsp;&lt;STRONG&gt;workflow.json&lt;/STRONG&gt;&amp;nbsp;file's shortcut menu, and select&amp;nbsp;&lt;STRONG&gt;Open Designer&lt;/STRONG&gt;.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;If it asks for&amp;nbsp;&lt;STRONG&gt;Enable connectors in Azure&lt;/STRONG&gt;, select&amp;nbsp;&lt;STRONG&gt;Use connectors from Azure&lt;/STRONG&gt;&lt;/P&gt;
&lt;img /&gt;
&lt;UL&gt;
&lt;LI&gt;After the&amp;nbsp;Select subscription&amp;nbsp;list opens, select the Azure subscription to use for your logic app project.&lt;/LI&gt;
&lt;LI&gt;After the resource groups list opens, select&amp;nbsp;RG to use for your logic app project.&lt;/LI&gt;
&lt;LI&gt;After you perform this step, Visual Studio Code opens the workflow designer.&lt;/LI&gt;
&lt;/UL&gt;
&lt;img /&gt;
&lt;P&gt;After you open a blank workflow in the designer, the Add a trigger prompt appears on the designer. You can now start creating your workflow by adding a trigger and actions and save it.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;Run, test, and debug locally&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Make sure to start the emulator before you run your workflow:&lt;/LI&gt;
&lt;LI&gt;In Visual Studio Code, from the&amp;nbsp;View&amp;nbsp;menu, select&amp;nbsp;Command Palette.&lt;/LI&gt;
&lt;LI&gt;After the command palette appears, enter&amp;nbsp;Azurite: Start.&lt;/LI&gt;
&lt;LI&gt;On the Visual Studio Code Activity Bar, open the Run menu, and select Start Debugging (F5).&lt;/LI&gt;
&lt;/OL&gt;
&lt;img /&gt;
&lt;P&gt;The Terminal window opens so that you can review the debugging session.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;Now, find the callback URL for the endpoint on the Request trigger.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Reopen the Explorer pane so that you can view your project.&lt;/LI&gt;
&lt;LI&gt;From the jsonfile's shortcut menu, select Overview.&lt;/LI&gt;
&lt;/OL&gt;
&lt;img /&gt;&lt;img /&gt;
&lt;P&gt;Click on Run trigger&lt;/P&gt;
&lt;P&gt;If it is stateful workflow, you’ll be able to see the status as shown below.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;To view it, click on identifier.&lt;/P&gt;
&lt;P&gt;It will open a new window with the results.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;Note: Incase while using storage account in your workflow if you get any forbidden error then whitelist your IP in that storage account and rerun the workflow by choosing Run and debug in VS code.&lt;/P&gt;
&lt;P&gt;Upon completion stop the debug by choosing the stop button and push the code to azure repo using git commands to push the code.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Use a Pipeline to Deploy the Created Workflow&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Build.yaml&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="yaml"&gt;jobs: - job: logic_app_build displayName: "Build and publish Logic App" steps: - script: sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y zip displayName: 'Install zip utility' - task: CopyFiles@2 displayName: 'Create project folder' inputs: sourceFolder: '$(System.DefaultWorkingDirectory)' contents: | azure_logicapps/** targetFolder: 'project_output' - task: ArchiveFiles@2 displayName: 'Create project Zip' inputs: rootFolderOrFile: '$(System.DefaultWorkingDirectory)/project_output/azure_logicapps' includeRootFolder: false archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip' replaceExistingArchive: true - task: PublishPipelineArtifact@1 displayName: 'Publish project zip artifact' inputs: targetPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip' artifact: 'logicAppCIArtifact' publishLocation: 'pipeline'&lt;/LI-CODE&gt;
&lt;P&gt;&lt;STRONG&gt;Deploy.yaml&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang="yaml"&gt;jobs: - deployment: deploy_logicapp_resources displayName: Deploy Logic App environment: ${{ parameters.environmentToDeploy }} strategy: runOnce: deploy: steps: - download: current artifact: logicAppCIArtifact - task: AzureFunctionApp@1 displayName: 'Deploy Logic App workflows' inputs: azureSubscription: ${{ parameters.azureServiceConnection }} appType: 'functionApp' appName: ${{ parameters.vars.LogicAppName }} package: '$(Pipeline.Workspace)/logicAppCIArtifact/$(Build.BuildId).zip' deploymentMethod: 'zipDeploy'&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 05 May 2026 03:39:26 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/build-and-deploy-logic-app-workflows-using-visual-studio-code/ba-p/4516931</guid>
      <dc:creator>Devi_Priya</dc:creator>
      <dc:date>2026-05-05T03:39:26Z</dc:date>
    </item>
    <item>
      <title>Running GitHub Actions Runners on Azure Container Apps with KEDA Autoscaling</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/running-github-actions-runners-on-azure-container-apps-with-keda/ba-p/4512980</link>
      <description>&lt;P data-line="8"&gt;GitHub-hosted runners work well for most scenarios. But as workloads grow, teams often need:&lt;/P&gt;
&lt;UL data-line="10"&gt;
&lt;LI data-line="10"&gt;&lt;STRONG&gt;Better cost optimization&lt;/STRONG&gt;&amp;nbsp;— pay only when jobs run&lt;/LI&gt;
&lt;LI data-line="11"&gt;&lt;STRONG&gt;More control&lt;/STRONG&gt;&amp;nbsp;over execution environments and installed tools&lt;/LI&gt;
&lt;LI data-line="12"&gt;&lt;STRONG&gt;Scalable parallel execution&lt;/STRONG&gt;&amp;nbsp;— run 10, 20, or 50 jobs simultaneously&lt;/LI&gt;
&lt;LI data-line="13"&gt;&lt;STRONG&gt;Network access&lt;/STRONG&gt;&amp;nbsp;to private resources (databases, internal APIs)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="15"&gt;Traditionally, this is solved using&amp;nbsp;&lt;STRONG&gt;self-hosted runners on Virtual Machines&lt;/STRONG&gt;. But VMs come with challenges — always-on cost, manual scaling, patching, and maintenance overhead.&lt;/P&gt;
&lt;P data-line="17"&gt;In this guide, we'll walk through a&amp;nbsp;&lt;STRONG&gt;modern, serverless alternative&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P data-line="19"&gt;👉&amp;nbsp;&lt;STRONG&gt;Running self-hosted GitHub runners on Azure Container Apps Jobs with KEDA autoscaling&lt;/STRONG&gt;&lt;/P&gt;
&lt;H3 data-line="21"&gt;What You Will Build&lt;/H3&gt;
&lt;P data-line="23"&gt;By the end of this guide:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Capability&lt;/th&gt;&lt;th&gt;What You Get&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Runner type&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Self-hosted, ephemeral (one job = one container)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Scaling&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Automatic via KEDA — scales to zero when idle&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Cost&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Zero cost when no jobs are running&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Infrastructure&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Fully managed by Azure Container Apps&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Security&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Secrets stored in Azure Key Vault, Managed Identity for auth&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H1 data-section-id="1xnsmb8" data-start="1135" data-end="1162"&gt;Architecture Overview&lt;/H1&gt;
&lt;P&gt;Here's how the system works at a high level:&lt;/P&gt;
&lt;img /&gt;&lt;img /&gt;
&lt;H3 data-line="51"&gt;How It Works (Step by Step):&lt;/H3&gt;
&lt;OL data-line="53"&gt;
&lt;LI data-line="53"&gt;A developer pushes code or triggers a GitHub Actions workflow&lt;/LI&gt;
&lt;LI data-line="54"&gt;GitHub queues the job and looks for a runner with matching labels&lt;/LI&gt;
&lt;LI data-line="55"&gt;&lt;STRONG&gt;KEDA&lt;/STRONG&gt;&amp;nbsp;(built into Container Apps) polls the GitHub Actions API for pending jobs&lt;/LI&gt;
&lt;LI data-line="56"&gt;When a pending job is detected, KEDA triggers the&amp;nbsp;&lt;STRONG&gt;Container App Job&lt;/STRONG&gt;&amp;nbsp;to start a new execution&lt;/LI&gt;
&lt;LI data-line="57"&gt;A fresh container starts, registers itself as a&amp;nbsp;&lt;STRONG&gt;self-hosted runner&lt;/STRONG&gt;&amp;nbsp;with GitHub&lt;/LI&gt;
&lt;LI data-line="58"&gt;The runner picks up the job, executes it, and reports results back to GitHub&lt;/LI&gt;
&lt;LI data-line="59"&gt;The container&amp;nbsp;&lt;STRONG&gt;shuts down and is destroyed&lt;/STRONG&gt;&amp;nbsp;— fully ephemeral&lt;/LI&gt;
&lt;LI data-line="60"&gt;When no jobs are pending, KEDA scales back to&amp;nbsp;&lt;STRONG&gt;zero&lt;/STRONG&gt; — no cost&lt;/LI&gt;
&lt;/OL&gt;
&lt;H1 data-section-id="yczsi9" data-start="1378" data-end="1395"&gt;Runtime Flow&lt;/H1&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;&lt;img /&gt;
&lt;H1 data-section-id="mj9kq3" data-start="1444" data-end="1462"&gt;Pre-requisites&lt;/H1&gt;
&lt;P data-line="66"&gt;Before you begin, make sure you have:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Requirement&lt;/th&gt;&lt;th&gt;Details&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;GitHub account&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;With a repository or organization where you want to run workflows&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Azure subscription&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;With permissions to create resources (Contributor role or higher)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Azure CLI&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Installed locally, OR use Azure Cloud Shell (no install needed)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Basic knowledge&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Familiarity with GitHub Actions and Azure Portal&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3 data-line="75"&gt;Where You'll Run Commands&lt;/H3&gt;
&lt;P data-line="77"&gt;Throughout this guide, you'll need a terminal to create files and run CLI commands. You have&amp;nbsp;&lt;STRONG&gt;three options&lt;/STRONG&gt;:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;When to Use&lt;/th&gt;&lt;th&gt;How to Open&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;VS Code Terminal&lt;/STRONG&gt;&amp;nbsp; (Recommended)&lt;/td&gt;&lt;td&gt;You have VS Code installed locally&lt;/td&gt;&lt;td&gt;Open VS Code →&amp;nbsp;Ctrl + ``&amp;nbsp;(backtick) → Terminal opens at the bottom&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Azure Cloud Shell&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;No local tools installed, or restricted machine&lt;/td&gt;&lt;td&gt;Go to&amp;nbsp;&lt;A href="https://portal.azure.com/" target="_blank" rel="noopener" data-href="https://portal.azure.com"&gt;portal.azure.com&lt;/A&gt;&amp;nbsp;→ click the&amp;nbsp;&amp;gt;_&amp;nbsp;icon in the top toolbar&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Any terminal&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;PowerShell, CMD, Bash — whatever you prefer&lt;/td&gt;&lt;td&gt;Just ensure Azure CLI (az) is installed&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="85"&gt;💡&lt;STRONG&gt;recommended to use VS Code&lt;/STRONG&gt;&amp;nbsp;because you'll create files (Dockerfile, start.sh) AND run commands — VS Code lets you do both in one place.&lt;/P&gt;
&lt;H3 data-line="87"&gt;Azure Resources We Will Create&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Resource&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Resource Group&lt;/td&gt;&lt;td&gt;Logical container for all resources&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure Container Registry (ACR)&lt;/td&gt;&lt;td&gt;Stores the runner Docker image&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure Container Apps Environment&lt;/td&gt;&lt;td&gt;Hosting environment for container jobs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure Container App Job&lt;/td&gt;&lt;td&gt;The actual runner job definition&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure Key Vault&lt;/td&gt;&lt;td&gt;Securely stores the GitHub PAT token&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Managed Identity&lt;/td&gt;&lt;td&gt;Allows the container job to access ACR and Key Vault without passwords&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="98"&gt;💡&amp;nbsp;&lt;STRONG&gt;Note&lt;/STRONG&gt;: This guide covers&amp;nbsp;&lt;STRONG&gt;organization-level runners&lt;/STRONG&gt;. For&amp;nbsp;&lt;STRONG&gt;repository-level runners&lt;/STRONG&gt;, the only difference is the GitHub API endpoint used for registration. We'll call out the differences where applicable.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="102"&gt;Step 1: Create a GitHub Personal Access Token (PAT)&lt;/H2&gt;
&lt;P data-line="104"&gt;Before we touch Azure, we need a token that allows our runner to register with GitHub. You can use either a&amp;nbsp;&lt;STRONG&gt;Fine-grained token&lt;/STRONG&gt;&amp;nbsp;(recommended) or a&amp;nbsp;&lt;STRONG&gt;Classic token&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H3 data-line="106"&gt;Option A: Fine-Grained PAT&amp;nbsp; (Recommended)&lt;/H3&gt;
&lt;P data-line="108"&gt;Fine-grained tokens let you scope access to&amp;nbsp;&lt;STRONG&gt;specific repositories only&lt;/STRONG&gt;. This is critical for two reasons:&lt;/P&gt;
&lt;OL data-line="110"&gt;
&lt;LI data-line="110"&gt;&lt;STRONG&gt;Avoid GitHub API rate limits:&lt;/STRONG&gt;&amp;nbsp;KEDA continuously polls the GitHub API for pending jobs. If your token has access to your entire org (potentially hundreds of repos), KEDA scans all of them on every polling cycle. GitHub allows only&amp;nbsp;&lt;STRONG&gt;5,000 API requests/hour&lt;/STRONG&gt;&amp;nbsp;— with broad access, you'll hit this limit quickly and KEDA will stop detecting jobs.&lt;/LI&gt;
&lt;LI data-line="111"&gt;&lt;STRONG&gt;Security:&lt;/STRONG&gt;&amp;nbsp;Least-privilege access — the token only works on the repos you explicitly select.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P data-line="113"&gt;🔑&amp;nbsp;&lt;STRONG&gt;This is why we recommend fine-grained tokens over classic tokens.&lt;/STRONG&gt;&amp;nbsp;By selecting only the repos that need runners, KEDA polls fewer repos and stays well within API limits.&lt;/P&gt;
&lt;OL data-line="115"&gt;
&lt;LI data-line="115"&gt;Go to&amp;nbsp;&lt;A href="https://github.com/" target="_blank" rel="noopener" data-href="https://github.com"&gt;github.com&lt;/A&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Developer settings&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="116"&gt;Click&amp;nbsp;&lt;STRONG&gt;Personal access tokens&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Fine-grained tokens&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="117"&gt;Click&amp;nbsp;&lt;STRONG&gt;Generate new token&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="118"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Token name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;container-app-runner&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Expiration&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Choose based on your needs (e.g., 90 days)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Resource owner&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Your GitHub username or org&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Repository access&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Only select repositories&lt;/STRONG&gt;&amp;nbsp;→ pick the repos where you want runners&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="127"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;IMPORTANT — Remember these repo names!&lt;/STRONG&gt;&amp;nbsp;The repos you select here are the ONLY repos this token can access. Later in&amp;nbsp;&lt;STRONG&gt;Step 8&lt;/STRONG&gt;, when you configure the KEDA scale rule, you must list these&amp;nbsp;&lt;STRONG&gt;exact same repos&lt;/STRONG&gt;&amp;nbsp;in the&amp;nbsp;repos&amp;nbsp;metadata field. KEDA uses this token to poll GitHub for pending jobs — if a repo isn't included in the token, KEDA can't see its jobs and your runners won't scale for it.&lt;/P&gt;
&lt;P data-line="129"&gt;&lt;STRONG&gt;Example:&lt;/STRONG&gt;&amp;nbsp;If you select&amp;nbsp;my-app&amp;nbsp;and&amp;nbsp;my-api&amp;nbsp;here, your KEDA config must have&amp;nbsp;repos: my-app,my-api.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="131"&gt;
&lt;LI data-line="131"&gt;Under&amp;nbsp;&lt;STRONG&gt;Permissions&lt;/STRONG&gt;, set the following:&lt;/LI&gt;
&lt;/OL&gt;
&lt;P data-line="133"&gt;&lt;STRONG&gt;Repository permissions&lt;/STRONG&gt;&amp;nbsp;(required):&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Permission&lt;/th&gt;&lt;th&gt;Access Level&lt;/th&gt;&lt;th&gt;Why It's Needed&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Actions&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Read and write&lt;/td&gt;&lt;td&gt;Manage workflow runs and artifacts&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Administration&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Read and write&lt;/td&gt;&lt;td&gt;Register and manage self-hosted runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Metadata&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Read-only&lt;/td&gt;&lt;td&gt;&lt;EM&gt;(Auto-selected, required)&lt;/EM&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Workflows&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Read and write&lt;/td&gt;&lt;td&gt;Update GitHub Action workflow files&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="142"&gt;&lt;STRONG&gt;Organization permissions&lt;/STRONG&gt;&amp;nbsp;(only if using org-level runners):&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Permission&lt;/th&gt;&lt;th&gt;Access Level&lt;/th&gt;&lt;th&gt;Why It's Needed&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Self-hosted runners&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Read and write&lt;/td&gt;&lt;td&gt;Register runners at the org level&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="148"&gt;📝&amp;nbsp;&lt;STRONG&gt;For personal accounts (no org):&lt;/STRONG&gt;&amp;nbsp;You only need the&amp;nbsp;&lt;STRONG&gt;Repository permissions&lt;/STRONG&gt;&amp;nbsp;above. Skip the Organization permissions.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="150"&gt;
&lt;LI data-line="150"&gt;Click&amp;nbsp;&lt;STRONG&gt;Generate token&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="151"&gt;&lt;STRONG&gt;⚠️ IMPORTANT: Copy the token NOW&lt;/STRONG&gt;&amp;nbsp;— you won't be able to see it again!&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="153"&gt;Option B: Classic PAT&lt;/H3&gt;
&lt;P data-line="155"&gt;If you prefer a classic token (simpler but broader access):&lt;/P&gt;
&lt;OL data-line="157"&gt;
&lt;LI data-line="157"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Developer settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Personal access tokens&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Tokens (classic)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="158"&gt;Click&amp;nbsp;&lt;STRONG&gt;Generate new token (classic)&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="159"&gt;Select these scopes:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scope&lt;/th&gt;&lt;th&gt;Why It's Needed&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;✅&amp;nbsp;repo&lt;/td&gt;&lt;td&gt;Full access to repositories&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;✅&amp;nbsp;workflow&lt;/td&gt;&lt;td&gt;Manage workflows&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;✅&amp;nbsp;admin:org&lt;/td&gt;&lt;td&gt;Required for org-level runners (skip for personal repos)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="167"&gt;
&lt;LI data-line="167"&gt;Click&amp;nbsp;&lt;STRONG&gt;Generate token&lt;/STRONG&gt;&amp;nbsp;and copy it immediately&lt;/LI&gt;
&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="169"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;Classic tokens give access to ALL repositories&lt;/STRONG&gt;&amp;nbsp;in your account. For better security and to avoid API rate limits, prefer fine-grained tokens scoped to specific repos.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-line="171"&gt;Save the token somewhere safe temporarily. We'll store it in Azure Key Vault in the next steps.&lt;/P&gt;
&lt;H3 data-line="172"&gt;Where Will Runners Appear on GitHub?&lt;/H3&gt;
&lt;P data-line="174"&gt;Once runners are deployed and register with GitHub, you can see them here:&lt;/P&gt;
&lt;P data-line="176"&gt;&lt;STRONG&gt;For repository-level runners:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL data-line="177"&gt;
&lt;LI data-line="177"&gt;Go to your repo →&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Actions&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Runners&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="179"&gt;&lt;STRONG&gt;For organization-level runners:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL data-line="180"&gt;
&lt;LI data-line="180"&gt;Go to your org →&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Actions&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Runners&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="182"&gt;Runners&amp;nbsp;&lt;STRONG&gt;automatically register themselves&lt;/STRONG&gt;&amp;nbsp;when the container starts. You'll see them appear as "Idle" or "Active" in the Runners list. You do&amp;nbsp;&lt;STRONG&gt;NOT&lt;/STRONG&gt;&amp;nbsp;need to manually create individual runners on GitHub.&lt;/P&gt;
&lt;H3 data-line="184"&gt;Setting Up Runner Groups (Organization-Level) — Recommended&lt;/H3&gt;
&lt;P data-line="186"&gt;Since this guide is for&amp;nbsp;&lt;STRONG&gt;organization-level runners&lt;/STRONG&gt;, it's recommended to create a&amp;nbsp;&lt;STRONG&gt;Runner Group&lt;/STRONG&gt;&amp;nbsp;on GitHub. Runner Groups let you control&amp;nbsp;&lt;STRONG&gt;which repositories&lt;/STRONG&gt;&amp;nbsp;in your org can use these runners.&lt;/P&gt;
&lt;H4 data-line="188"&gt;Steps to Create a Runner Group:&lt;/H4&gt;
&lt;OL data-line="190"&gt;
&lt;LI data-line="190"&gt;Go to your&amp;nbsp;&lt;STRONG&gt;GitHub Organization&lt;/STRONG&gt;&amp;nbsp;page (e.g.,&amp;nbsp;https://github.com/your-org)&lt;/LI&gt;
&lt;LI data-line="191"&gt;Click&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;(top menu bar)&lt;/LI&gt;
&lt;LI data-line="192"&gt;In the left sidebar, expand&amp;nbsp;&lt;STRONG&gt;Actions&lt;/STRONG&gt;&amp;nbsp;→ click&amp;nbsp;&lt;STRONG&gt;Runner groups&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="193"&gt;Click&amp;nbsp;&lt;STRONG&gt;New runner group&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="194"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;container-app-runners&amp;nbsp;(or any descriptive name)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Repository access&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Choose one:&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;•&amp;nbsp;&lt;STRONG&gt;All repositories&lt;/STRONG&gt;&amp;nbsp;— any repo in the org can use these runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;•&amp;nbsp;&lt;STRONG&gt;Selected repositories&lt;/STRONG&gt;&amp;nbsp;— pick specific repos (recommended for control)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Allow public repositories&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Uncheck this for security (unless needed)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Workflow access&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Leave default (all workflows)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="205"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;CRITICAL: If ANY of the repositories using these runners are PUBLIC, you MUST check "Allow public repositories".&lt;/STRONG&gt;&amp;nbsp;If this is unchecked, GitHub will silently refuse to dispatch jobs from public repos to runners in this group — the runner will register and show as "Idle", but workflows will stay stuck in "Queued" forever. This is the&amp;nbsp;&lt;STRONG&gt;most common and hardest-to-debug issue&lt;/STRONG&gt;&amp;nbsp;with runner groups.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="207"&gt;
&lt;LI data-line="207"&gt;Click&amp;nbsp;&lt;STRONG&gt;Create group&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H4 data-line="209"&gt;Why Create a Runner Group?&lt;/H4&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Without Runner Group&lt;/th&gt;&lt;th&gt;With Runner Group&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Any repo in the org can use your runners&lt;/td&gt;&lt;td&gt;Only selected repos can use them&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Harder to track which teams use runners&lt;/td&gt;&lt;td&gt;Clear visibility and access control&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Potential security risk for public repos&lt;/td&gt;&lt;td&gt;Can block public repos from using runners&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="217"&gt;📝&amp;nbsp;&lt;STRONG&gt;For personal GitHub accounts:&lt;/STRONG&gt;&amp;nbsp;Runner groups are not available. Runners will automatically appear under your repo's&amp;nbsp;&lt;STRONG&gt;Settings → Actions → Runners&lt;/STRONG&gt;. No extra setup needed.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="220"&gt;Step 2: Create Azure Resources (Portal)&lt;/H2&gt;
&lt;P data-line="222"&gt;We'll create all the Azure infrastructure through the Azure Portal. If you prefer CLI, see the&amp;nbsp;&lt;A href="https://file+.vscode-resource.vscode-cdn.net/c%3A/Users/shubhij/KEDA-Runners/CAJ-runners/blog/techcommunity-blog.md#appendix-a-cli-commands-for-all-steps" target="_blank" rel="noopener" data-href="#appendix-a-cli-commands-for-all-steps"&gt;CLI alternative&lt;/A&gt;&amp;nbsp;at the end.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="224"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;IMPORTANT: All Azure resources (Resource Group, ACR, Key Vault, Container Apps Environment, Container App Job) must be in the SAME region.&lt;/STRONG&gt;&amp;nbsp;Pick one region (e.g.,&amp;nbsp;Central US&amp;nbsp;or&amp;nbsp;West US 2) and use it for everything. Mixing regions can cause connectivity issues and increased latency.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3 data-line="226"&gt;2.1: Create a Resource Group&lt;/H3&gt;
&lt;OL data-line="228"&gt;
&lt;LI data-line="228"&gt;Go to&amp;nbsp;&lt;A href="https://portal.azure.com/" target="_blank" rel="noopener" data-href="https://portal.azure.com"&gt;Azure Portal&lt;/A&gt;&lt;/LI&gt;
&lt;LI data-line="229"&gt;Search for&amp;nbsp;&lt;STRONG&gt;"Resource groups"&lt;/STRONG&gt;&amp;nbsp;in the top search bar&lt;/LI&gt;
&lt;LI data-line="230"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="231"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Subscription&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Select your Azure subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Resource group&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;rg-github-runners&amp;nbsp;(or your preferred name)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Region&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;West US 2&amp;nbsp;(or any region that supports Container Apps)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="239"&gt;
&lt;LI data-line="239"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + create&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="241"&gt;2.2: Create an Azure Container Registry (ACR)&lt;/H3&gt;
&lt;P data-line="243"&gt;This is where we'll store our runner Docker image.&lt;/P&gt;
&lt;OL data-line="245"&gt;
&lt;LI data-line="245"&gt;Search for&amp;nbsp;&lt;STRONG&gt;"Container registries"&lt;/STRONG&gt;&amp;nbsp;in the Azure Portal&lt;/LI&gt;
&lt;LI data-line="246"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="247"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Subscription&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Your subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Resource group&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;rg-github-runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Registry name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;yourregistryname&amp;nbsp;(must be globally unique, lowercase, letters and numbers only)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Location&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Same as your resource group (e.g.,&amp;nbsp;West US 2)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Pricing plan&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Basic&lt;/STRONG&gt;&amp;nbsp;(sufficient for this guide; use Standard/Premium for production)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="257"&gt;
&lt;LI data-line="257"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + create&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="258"&gt;Once created, note down the&amp;nbsp;&lt;STRONG&gt;Login server&lt;/STRONG&gt;&amp;nbsp;(e.g.,&amp;nbsp;yourregistryname.azurecr.io) — you'll need this later&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="260"&gt;2.3: Create an Azure Key Vault&lt;/H3&gt;
&lt;OL data-line="262"&gt;
&lt;LI data-line="262"&gt;Search for&amp;nbsp;&lt;STRONG&gt;"Key vaults"&lt;/STRONG&gt;&amp;nbsp;in the Azure Portal&lt;/LI&gt;
&lt;LI data-line="263"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="264"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Subscription&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Your subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Resource group&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;rg-github-runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Key vault name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;kv-github-runners&amp;nbsp;(must be globally unique)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Region&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Same region&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Pricing tier&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Standard&lt;/STRONG&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="274"&gt;
&lt;LI data-line="274"&gt;Go to the&amp;nbsp;&lt;STRONG&gt;Access configuration&lt;/STRONG&gt;&amp;nbsp;tab:
&lt;UL data-line="275"&gt;
&lt;LI data-line="275"&gt;Select&amp;nbsp;&lt;STRONG&gt;Azure role-based access control (RBAC)&lt;/STRONG&gt;&amp;nbsp;as the permission model&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI data-line="276"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + create&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="278"&gt;2.4: Store the GitHub PAT in Key Vault&lt;/H3&gt;
&lt;OL data-line="280"&gt;
&lt;LI data-line="280"&gt;Open your newly created Key Vault&lt;/LI&gt;
&lt;LI data-line="281"&gt;First, give yourself permission:
&lt;UL data-line="282"&gt;
&lt;LI data-line="282"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Access Control (IAM)&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;+ Add role assignment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="283"&gt;Role:&amp;nbsp;&lt;STRONG&gt;Key Vault Secrets Officer&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="284"&gt;Assign to: Your own Azure account&lt;/LI&gt;
&lt;LI data-line="285"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + assign&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI data-line="286"&gt;Now go to&amp;nbsp;&lt;STRONG&gt;Objects&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Secrets&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;+ Generate/Import&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="287"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Upload options&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-pat&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Secret value&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Paste your GitHub PAT from Step 1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="295"&gt;
&lt;LI data-line="295"&gt;Click&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H2 data-line="299"&gt;Step 3: Create the Runner Docker Image&lt;/H2&gt;
&lt;P data-line="301"&gt;This is the Docker image that will run as your GitHub Actions runner. We need two files: a&amp;nbsp;Dockerfile&amp;nbsp;and a&amp;nbsp;start.sh&amp;nbsp;script.&lt;/P&gt;
&lt;H3 data-line="303"&gt;3.1: Set Up Your Working Directory&lt;/H3&gt;
&lt;OL data-line="305"&gt;
&lt;LI data-line="305"&gt;Open&amp;nbsp;&lt;STRONG&gt;VS Code&lt;/STRONG&gt;&amp;nbsp;on your local machine&lt;/LI&gt;
&lt;LI data-line="306"&gt;Open the integrated terminal:&amp;nbsp;&lt;STRONG&gt;Ctrl + `&lt;/STRONG&gt;&amp;nbsp;(backtick) or&amp;nbsp;&lt;STRONG&gt;Terminal → New Terminal&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="307"&gt;Create a new folder and navigate into it:&lt;/LI&gt;
&lt;/OL&gt;
&lt;LI-CODE lang=""&gt;mkdir github-runner-image 
cd github-runner-image&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;OL data-line="314"&gt;
&lt;LI data-line="314"&gt;You'll create two files in this folder:&amp;nbsp;Dockerfile&amp;nbsp;and&amp;nbsp;start.sh&lt;/LI&gt;
&lt;LI data-line="315"&gt;In VS Code, click&amp;nbsp;&lt;STRONG&gt;File → Open Folder&lt;/STRONG&gt;&amp;nbsp;and open the&amp;nbsp;github-runner-image&amp;nbsp;folder (so you can edit files easily)&lt;/LI&gt;
&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="317"&gt;📌&amp;nbsp;&lt;STRONG&gt;All commands in Step 3 and Step 4 should be run from inside this&amp;nbsp;github-runner-image&amp;nbsp;folder.&lt;/STRONG&gt;&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3 data-line="319"&gt;3.2: Choose Your Approach&lt;/H3&gt;
&lt;P data-line="321"&gt;There are two approaches to creating the runner image:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Approach&lt;/th&gt;&lt;th&gt;Best For&lt;/th&gt;&lt;th&gt;Docker Required Locally?&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Option A&lt;/STRONG&gt;: Build locally with Docker&lt;/td&gt;&lt;td&gt;Development/testing&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Option B&lt;/STRONG&gt;: Build remotely with ACR Tasks&lt;/td&gt;&lt;td&gt;Production / no Docker access&lt;/td&gt;&lt;td&gt;❌ No&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="328"&gt;We'll create the same files for both approaches. The only difference is the&amp;nbsp;&lt;STRONG&gt;build command&lt;/STRONG&gt;.&lt;/P&gt;
&lt;H3 data-line="330"&gt;3.3: Create the&amp;nbsp;start.sh&amp;nbsp;Script&lt;/H3&gt;
&lt;P data-line="332"&gt;This script runs when the container starts. It registers the runner with GitHub, executes the job, and then the container shuts down.&lt;/P&gt;
&lt;P data-line="334"&gt;Create a file named &lt;STRONG&gt;start.sh:&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang=""&gt;#!/bin/bash
set -e

# ────────────────────────────────────────────
# CONFIGURATION
# ────────────────────────────────────────────
# These values are passed as environment variables
# GITHUB_PAT    → Your GitHub Personal Access Token
# GITHUB_OWNER  → Your GitHub org or username
# GITHUB_REPO   → (Optional) Repository name for repo-level runners
# RUNNER_SCOPE  → "org" or "repo"
# RUNNER_LABELS → Comma-separated labels (e.g., "container-app,linux")
# RUNNER_GROUP  → Runner group name (org-level only, default: "Default")
#                  Set this to the runner group you created in Step 1 (e.g., "container-app-runners")
#                  If not set, runners register in GitHub's "Default" group — which means
#                  ANY repo in the org can use them and you lose access control.

RUNNER_SCOPE="${RUNNER_SCOPE:-org}"
RUNNER_LABELS="${RUNNER_LABELS:-container-app}"
RUNNER_GROUP="${RUNNER_GROUP:-Default}"

# ⚠️ IMPORTANT: Always set the RUNNER_GROUP environment variable on your Container App Job
#    to match the runner group you created on GitHub (e.g., "container-app-runners").
#    The "Default" fallback above is only a safety net — do NOT rely on it.

# ────────────────────────────────────────────
# GET REGISTRATION TOKEN
# ────────────────────────────────────────────
if [ "$RUNNER_SCOPE" == "org" ]; then
    echo "🔑 Requesting registration token for organization: $GITHUB_OWNER"
    REG_TOKEN=$(curl -s -X POST \
        -H "Authorization: token $GITHUB_PAT" \
        -H "Accept: application/vnd.github+json" \
        "https://api.github.com/orgs/${GITHUB_OWNER}/actions/runners/registration-token" \
        | jq -r .token)
    RUNNER_URL="https://github.com/${GITHUB_OWNER}"
else
    echo "🔑 Requesting registration token for repository: $GITHUB_OWNER/$GITHUB_REPO"
    REG_TOKEN=$(curl -s -X POST \
        -H "Authorization: token $GITHUB_PAT" \
        -H "Accept: application/vnd.github+json" \
        "https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/actions/runners/registration-token" \
        | jq -r .token)
    RUNNER_URL="https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}"
fi

if [ -z "$REG_TOKEN" ] || [ "$REG_TOKEN" == "null" ]; then
    echo "❌ Failed to get registration token. Check your GITHUB_PAT and permissions."
    exit 1
fi

echo "✅ Registration token obtained successfully"

# ────────────────────────────────────────────
# CONFIGURE RUNNER
# ────────────────────────────────────────────
echo "⚙️ Configuring runner..."
./config.sh --unattended \
    --name "runner-$(hostname)" \
    --url "$RUNNER_URL" \
    --token "$REG_TOKEN" \
    --runnergroup "$RUNNER_GROUP" \
    --ephemeral \
    --labels "$RUNNER_LABELS" \
    --replace

echo "🚀 Starting runner..."
./run.sh&lt;/LI-CODE&gt;
&lt;P data-line="407"&gt;&lt;STRONG&gt;Key flags explained:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL data-line="408"&gt;
&lt;LI data-line="408"&gt;
&lt;BLOCKQUOTE&gt;--ephemeral: Runner processes&amp;nbsp;&lt;STRONG&gt;one job&lt;/STRONG&gt;&amp;nbsp;then exits (container stops)&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="409"&gt;
&lt;BLOCKQUOTE&gt;--runnergroup: Registers the runner in a specific runner group (org-level only)&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="410"&gt;
&lt;BLOCKQUOTE&gt;--replace: Replaces any existing runner with the same name&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="411"&gt;
&lt;BLOCKQUOTE&gt;--unattended: No interactive prompts&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="413"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;Do NOT use&amp;nbsp;--disableupdate!&lt;/STRONG&gt;&amp;nbsp;In newer GitHub versions, this flag prevents GitHub from dispatching jobs to the runner. The runner will appear as "Idle" but never pick up work.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3 data-line="415"&gt;3.4: Create the&amp;nbsp;Dockerfile&lt;/H3&gt;
&lt;P data-line="417"&gt;Create a file named&amp;nbsp;&lt;STRONG&gt;Dockerfile&lt;/STRONG&gt;:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;FROM ubuntu:22.04

# Prevent interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive

# Install required dependencies
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    curl \
    git \
    jq \
    ca-certificates \
    unzip \
    wget \
    apt-transport-https \
    software-properties-common \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

# Create a non-root user for the runner (GitHub requires this)
RUN useradd -m runner

# Set up the runner directory
WORKDIR /home/runner/actions-runner

# Download the latest GitHub Actions Runner
# Check latest version: curl -s https://api.github.com/repos/actions/runner/releases/latest | jq -r '.tag_name'
ARG RUNNER_VERSION=2.334.0
RUN curl -L -o actions-runner.tar.gz \
    "https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" \
    &amp;amp;&amp;amp; tar xzf actions-runner.tar.gz \
    &amp;amp;&amp;amp; rm actions-runner.tar.gz

# Install runner dependencies
RUN ./bin/installdependencies.sh

# Copy the startup script
COPY start.sh .
RUN chmod +x start.sh

# Set ownership to the runner user
RUN chown -R runner:runner /home/runner

# Switch to non-root user
USER runner

ENTRYPOINT ["./start.sh"]&lt;/LI-CODE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="467"&gt;💡&amp;nbsp;&lt;STRONG&gt;Tip:&lt;/STRONG&gt;&amp;nbsp;Check the latest runner version by running:&lt;/P&gt;
&lt;P&gt;curl -s https://api.github.com/repos/actions/runner/releases/latest | jq -r '.tag_name'&lt;/P&gt;
&lt;P data-line="471"&gt;At the time of writing,&amp;nbsp;2.334.0&amp;nbsp;is the latest. Update the&amp;nbsp;ARG RUNNER_VERSION&amp;nbsp;value if a newer version is available.&lt;/P&gt;
&lt;P data-line="473"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;Using a deprecated runner version will cause runners to connect but refuse to pick up jobs.&lt;/STRONG&gt;&amp;nbsp;You'll see the error:&amp;nbsp;&lt;EM&gt;"Runner version vX.X.X is deprecated and cannot receive messages."&lt;/EM&gt; Always use a recent version.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="477"&gt;Step 4: Build and Push the Docker Image&lt;/H2&gt;
&lt;P data-line="479"&gt;Now we need to build this image and push it to your Azure Container Registry (ACR).&lt;/P&gt;
&lt;H3 data-line="481"&gt;Option A: Build Locally with Docker (Development)&lt;/H3&gt;
&lt;P data-line="483"&gt;Use this if you have&amp;nbsp;&lt;STRONG&gt;Docker Desktop&lt;/STRONG&gt;&amp;nbsp;installed on your machine.&lt;/P&gt;
&lt;P data-line="485"&gt;&lt;STRONG&gt;Where to run:&lt;/STRONG&gt;&amp;nbsp;In the&amp;nbsp;&lt;STRONG&gt;VS Code terminal&lt;/STRONG&gt;&amp;nbsp;(or any terminal), make sure you're inside the&amp;nbsp;github-runner-image&amp;nbsp;folder where your&amp;nbsp;Dockerfile&amp;nbsp;and&amp;nbsp;start.sh&amp;nbsp;are located.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;# 0. First, log in to Azure (this opens a browser window for authentication)
az login

# 1. Log in to your ACR (replace yourregistryname with your actual ACR name)
az acr login --name yourregistryname

# 2. Build the image
docker build -t yourregistryname.azurecr.io/github-runner:v1 .

# 3. Push the image to ACR
docker push yourregistryname.azurecr.io/github-runner:v1&lt;/LI-CODE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="501"&gt;📌&amp;nbsp;&lt;STRONG&gt;Make sure Docker Desktop is running&lt;/STRONG&gt;&amp;nbsp;before you execute these commands. If you see "Cannot connect to the Docker daemon", start Docker Desktop first.&lt;/P&gt;
&lt;P data-line="503"&gt;🔒&amp;nbsp;&lt;STRONG&gt;Don't have&amp;nbsp;az login&amp;nbsp;or Docker on your machine?&lt;/STRONG&gt;&amp;nbsp;Use&amp;nbsp;&lt;STRONG&gt;Azure Cloud Shell&lt;/STRONG&gt;&amp;nbsp;instead — it's a browser-based terminal at&amp;nbsp;&lt;A href="https://shell.azure.com/" target="_blank" rel="noopener" data-href="https://shell.azure.com"&gt;shell.azure.com&lt;/A&gt;&amp;nbsp;that comes pre-authenticated with Azure CLI (no&amp;nbsp;az login&amp;nbsp;needed) and has Docker available. See&amp;nbsp;&lt;STRONG&gt;Option B&lt;/STRONG&gt;&amp;nbsp;below if you can't use Docker at all.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3 data-line="505"&gt;Option B: Build Remotely with ACR Tasks (Production — No Docker Needed) ⭐&lt;/H3&gt;
&lt;P data-line="507"&gt;&lt;STRONG&gt;This is the recommended approach for production environments&lt;/STRONG&gt;&amp;nbsp;where:&lt;/P&gt;
&lt;UL data-line="508"&gt;
&lt;LI data-line="508"&gt;You don't have Docker installed&lt;/LI&gt;
&lt;LI data-line="509"&gt;Your production environment is fully private / locked down&lt;/LI&gt;
&lt;LI data-line="510"&gt;You want to build images directly in Azure without any local tooling&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="512"&gt;&lt;STRONG&gt;Where to run:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL data-line="513"&gt;
&lt;LI data-line="513"&gt;&lt;STRONG&gt;VS Code terminal&lt;/STRONG&gt;&amp;nbsp;→ Run&amp;nbsp;az login&amp;nbsp;first, then the build command&lt;/LI&gt;
&lt;LI data-line="514"&gt;&lt;STRONG&gt;Azure Cloud Shell&lt;/STRONG&gt;&amp;nbsp;(&lt;A href="https://shell.azure.com/" target="_blank" rel="noopener" data-href="https://shell.azure.com"&gt;shell.azure.com&lt;/A&gt;) → No&amp;nbsp;az login&amp;nbsp;needed, you're already authenticated. Upload your&amp;nbsp;Dockerfile&amp;nbsp;and&amp;nbsp;start.sh&amp;nbsp;files using the&amp;nbsp;&lt;STRONG&gt;Upload&lt;/STRONG&gt;&amp;nbsp;button in Cloud Shell, then run the build command&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="516"&gt;You must be inside the folder where your&amp;nbsp;Dockerfile&amp;nbsp;and&amp;nbsp;start.sh&amp;nbsp;are located.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;# If running from VS Code terminal (skip this line if using Azure Cloud Shell)
az login

# Build directly in ACR — no Docker required!
az acr build --registry yourregistryname --image github-runner:v1 --file Dockerfile .&lt;/LI-CODE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="526"&gt;☝️&amp;nbsp;&lt;STRONG&gt;That's it — one single command.&lt;/STRONG&gt;&amp;nbsp;No Docker install, no Docker daemon, nothing.&lt;/P&gt;
&lt;P data-line="528"&gt;&lt;STRONG&gt;Using Azure Cloud Shell?&lt;/STRONG&gt;&amp;nbsp;To upload files:&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="529"&gt;
&lt;LI data-line="529"&gt;
&lt;BLOCKQUOTE&gt;Open&amp;nbsp;&lt;A href="https://shell.azure.com/" target="_blank" rel="noopener" data-href="https://shell.azure.com"&gt;shell.azure.com&lt;/A&gt;&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="530"&gt;
&lt;BLOCKQUOTE&gt;Click the&amp;nbsp;&lt;STRONG&gt;Upload/Download&lt;/STRONG&gt;&amp;nbsp;button (📁 icon) in the toolbar&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="531"&gt;
&lt;BLOCKQUOTE&gt;Upload&amp;nbsp;Dockerfile&amp;nbsp;and&amp;nbsp;start.sh&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="532"&gt;
&lt;BLOCKQUOTE&gt;They'll land in your home directory (~/). Run az acr build from there.&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;P data-line="534"&gt;This command:&lt;/P&gt;
&lt;UL data-line="535"&gt;
&lt;LI data-line="535"&gt;Uploads your source code to ACR&lt;/LI&gt;
&lt;LI data-line="536"&gt;Builds the Docker image&amp;nbsp;&lt;STRONG&gt;in Azure&lt;/STRONG&gt;&amp;nbsp;(not on your machine)&lt;/LI&gt;
&lt;LI data-line="537"&gt;Tags and stores it in your registry&lt;/LI&gt;
&lt;LI data-line="538"&gt;No Docker daemon needed at all!&lt;/LI&gt;
&lt;/UL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="540"&gt;🔒&amp;nbsp;&lt;STRONG&gt;Production Note:&lt;/STRONG&gt;&amp;nbsp;In locked-down environments where even&amp;nbsp;az acr build&amp;nbsp;isn't possible from your machine, you can:&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="541"&gt;
&lt;LI data-line="541"&gt;
&lt;BLOCKQUOTE&gt;Use&amp;nbsp;&lt;STRONG&gt;Azure Cloud Shell&lt;/STRONG&gt;&amp;nbsp;(browser-based, always has Azure CLI)&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="542"&gt;
&lt;BLOCKQUOTE&gt;Set up an&amp;nbsp;&lt;STRONG&gt;ACR Task&lt;/STRONG&gt;&amp;nbsp;with a&amp;nbsp;&lt;STRONG&gt;Git trigger&lt;/STRONG&gt;&amp;nbsp;— ACR automatically builds when you push to a repo&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;LI data-line="543"&gt;
&lt;BLOCKQUOTE&gt;Use&amp;nbsp;&lt;STRONG&gt;Azure DevOps / GitHub Actions pipeline&lt;/STRONG&gt;&amp;nbsp;to build and push the image&lt;/BLOCKQUOTE&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&lt;U&gt;&lt;EM&gt;&lt;STRONG&gt;Example&lt;/STRONG&gt;&lt;/EM&gt;&lt;/U&gt;: Auto-build from a GitHub repo (single line for Cloud Shell)&lt;/P&gt;
&lt;LI-CODE lang=""&gt;az acr task create --registry yourregistryname --name build-runner-image --image "github-runner:{{.Run.ID}}" --context https://github.com/your-org/your-runner-repo.git --file Dockerfile --git-access-token YOUR_GITHUB_PAT&lt;/LI-CODE&gt;
&lt;H3 data-line="550"&gt;Verify the Image&lt;/H3&gt;
&lt;P data-line="552"&gt;After building, confirm the image exists in your registry:&lt;/P&gt;
&lt;P data-line="554"&gt;&lt;STRONG&gt;Portal:&lt;/STRONG&gt;&amp;nbsp;Go to your ACR →&amp;nbsp;&lt;STRONG&gt;Repositories&lt;/STRONG&gt;&amp;nbsp;→ you should see&amp;nbsp;github-runner&amp;nbsp;listed&lt;/P&gt;
&lt;P data-line="556"&gt;&lt;STRONG&gt;CLI:&lt;/STRONG&gt;&lt;/P&gt;
&lt;LI-CODE lang=""&gt;az acr repository list --name yourregistryname --output table&lt;/LI-CODE&gt;
&lt;H2 data-line="563"&gt;Step 5: Create the Container Apps Environment&lt;/H2&gt;
&lt;P data-line="565"&gt;The Container Apps Environment is the hosting platform for your container jobs. Think of it as the "cluster" where your runners will live.&lt;/P&gt;
&lt;H3 data-line="567"&gt;Steps (Azure Portal):&lt;/H3&gt;
&lt;OL data-line="569"&gt;
&lt;LI data-line="569"&gt;Search for&amp;nbsp;&lt;STRONG&gt;"Container Apps Environment"&lt;/STRONG&gt;&amp;nbsp;in the Azure Portal&lt;/LI&gt;
&lt;LI data-line="570"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="571"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tab&lt;/th&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Basics&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Subscription&lt;/td&gt;&lt;td&gt;Your subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;Resource group&lt;/td&gt;&lt;td&gt;rg-github-runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;Environment name&lt;/td&gt;&lt;td&gt;cae-github-runners&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;Region&lt;/td&gt;&lt;td&gt;West US 2&amp;nbsp;(same as other resources)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;Environment type&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Consumption only&lt;/STRONG&gt;&amp;nbsp;(or Consumption + Dedicated if you need workload profiles)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Monitoring&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Log Analytics workspace&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Create new&lt;/STRONG&gt;&amp;nbsp;or select existing&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="582"&gt;
&lt;LI data-line="582"&gt;Leave&amp;nbsp;&lt;STRONG&gt;Networking&lt;/STRONG&gt;&amp;nbsp;as defaults for now (we'll discuss production networking later)&lt;/LI&gt;
&lt;LI data-line="583"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + create&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="585"&gt;⏳ This takes 1-2 minutes to create.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="589"&gt;Step 6: Create the Container App Job&lt;/H2&gt;
&lt;P data-line="591"&gt;This is the core resource — the Container App Job that will run your GitHub runners.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="593"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;IMPORTANT: Complete Step 4 (Build &amp;amp; Push Image) BEFORE this step.&lt;/STRONG&gt;&amp;nbsp;The Container App Job creation form requires you to select a container image from your ACR. If your ACR is empty (no images pushed), the portal will show an error:&amp;nbsp;&lt;EM&gt;"The ACR does not have any images. Please push an image to the ACR and try again."&lt;/EM&gt;&amp;nbsp;So make sure your image is pushed first!&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H3 data-line="595"&gt;Steps (Azure Portal):&lt;/H3&gt;
&lt;OL data-line="597"&gt;
&lt;LI data-line="597"&gt;Search for&amp;nbsp;&lt;STRONG&gt;"Container App Jobs"&lt;/STRONG&gt;&amp;nbsp;in the Azure Portal search bar&lt;/LI&gt;
&lt;LI data-line="598"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Create Container App Job&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="600"&gt;Tab 1: Basics&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Subscription&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Your subscription&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Resource group&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;rg-github-runners&lt;/td&gt;&lt;td&gt;Same RG as other resources&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Container app job name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner-job&lt;/td&gt;&lt;td&gt;Lowercase, letters, numbers, hyphens&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Region&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;West US 2&lt;/td&gt;&lt;td&gt;Must match your CAE region&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Container Apps Environment&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;cae-github-runners&lt;/td&gt;&lt;td&gt;Select the environment created in Step 5&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="610"&gt;Click&amp;nbsp;&lt;STRONG&gt;Next: Container &amp;gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;H3 data-line="612"&gt;Tab 2: Container&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner&lt;/td&gt;&lt;td&gt;Name of the container within the job&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Image source&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Azure Container Registry&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Select this radio button&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Registry&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;yourregistryname.azurecr.io&lt;/td&gt;&lt;td&gt;Select your ACR from the dropdown&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Image&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner&lt;/td&gt;&lt;td&gt;Select the image you pushed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Image tag&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;v1&lt;/td&gt;&lt;td&gt;The tag you used during build&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Registry authentication&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Managed identity&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Leave as default&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Managed identity&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;System assigned Identity (environment)&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Leave as default — Azure will auto-assign ACR Pull role&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Command override&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;EM&gt;(Leave empty)&lt;/EM&gt;&lt;/td&gt;&lt;td&gt;Our Dockerfile already has an ENTRYPOINT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Arguments override&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;EM&gt;(Leave empty)&lt;/EM&gt;&lt;/td&gt;&lt;td&gt;Not needed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Workload profile&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Consumption&lt;/td&gt;&lt;td&gt;Default is fine&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;CPU and memory&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;0.5 CPU cores, 1 Gi memory&lt;/td&gt;&lt;td&gt;Increase if your jobs need more resources&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="628"&gt;💡&amp;nbsp;&lt;STRONG&gt;CPU/Memory guidance:&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL data-line="629"&gt;
&lt;LI data-line="629"&gt;0.5 CPU / 1 Gi&amp;nbsp;— Light jobs (linting, simple tests)&lt;/LI&gt;
&lt;LI data-line="630"&gt;1 CPU / 2 Gi&amp;nbsp;— Medium jobs (building apps, running test suites)&lt;/LI&gt;
&lt;LI data-line="631"&gt;2 CPU / 4 Gi&amp;nbsp;— Heavy jobs (compiling large projects, ML workloads)&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4 data-line="633"&gt;Environment Variables&lt;/H4&gt;
&lt;P data-line="635"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Add&lt;/STRONG&gt;&amp;nbsp;for each variable:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Source&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GITHUB_OWNER&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;Your GitHub org name (e.g.,&amp;nbsp;Quality-Framework)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RUNNER_SCOPE&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;org&amp;nbsp;(or&amp;nbsp;repo&amp;nbsp;for repo-level runners)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RUNNER_LABELS&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;container-app&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GITHUB_REPO&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;Comma-separated repo names that this runner will serve (e.g.,&amp;nbsp;my-app,my-api,my-infra). These should match the repos selected in your PAT (Step 1).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RUNNER_GROUP&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;The GitHub runner group name (e.g.,&amp;nbsp;container-app-runners). Must match the group created in Step 1. If not set, defaults to&amp;nbsp;Default.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GITHUB_PAT&lt;/td&gt;&lt;td&gt;&lt;EM&gt;(We'll configure this as a secret reference in Step 7)&lt;/EM&gt;&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="646"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;Do NOT put the PAT directly as an environment variable value.&lt;/STRONG&gt;&amp;nbsp;We will securely reference it from Key Vault in Step 7.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-line="648"&gt;For now, add only&amp;nbsp;GITHUB_OWNER,&amp;nbsp;RUNNER_SCOPE,&amp;nbsp;RUNNER_LABELS,&amp;nbsp;GITHUB_REPO, and&amp;nbsp;RUNNER_GROUP. We'll add&amp;nbsp;GITHUB_PAT&amp;nbsp;after setting up the identity and secret.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="650"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;Make sure&amp;nbsp;RUNNER_SCOPE&amp;nbsp;matches&amp;nbsp;runnerScope&amp;nbsp;in the scale rule below.&lt;/STRONG&gt;&amp;nbsp;If you're using org-level runners, both should be&amp;nbsp;org.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H4 data-line="652"&gt;Scale Rule Settings (same page, scroll down)&lt;/H4&gt;
&lt;P data-line="654"&gt;Below the environment variables, you'll see&amp;nbsp;&lt;STRONG&gt;Scale rule settings&lt;/STRONG&gt;:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Min executions&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;Scale to zero when no jobs are pending&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Max executions&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Maximum parallel runners (adjust as needed).&amp;nbsp;&lt;STRONG&gt;Do NOT set to 0&lt;/STRONG&gt;&amp;nbsp;— this means unlimited and can cause hundreds of runner containers to spawn!&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Polling interval&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;How often (in seconds) KEDA checks for pending jobs&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H4 data-line="662"&gt;Scale Rules — Click&amp;nbsp;&lt;STRONG&gt;+ Add&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P data-line="664"&gt;A side panel opens with the&amp;nbsp;&lt;STRONG&gt;"Add scale rule"&lt;/STRONG&gt;&amp;nbsp;form. Fill in:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Rule name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner-rule&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Custom rule type&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="671"&gt;&lt;STRONG&gt;Scale parameters&lt;/STRONG&gt;&amp;nbsp;(key-value pairs — click + Add for each):&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;githubAPIURL&lt;/td&gt;&lt;td&gt;https://api.github.com&lt;/td&gt;&lt;td&gt;Pre-filled by the portal, leave as-is&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;owner&lt;/td&gt;&lt;td&gt;your-github-org&lt;/td&gt;&lt;td&gt;Your GitHub org or username (e.g.,&amp;nbsp;Quality-Framework)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;runnerScope&lt;/td&gt;&lt;td&gt;org&lt;/td&gt;&lt;td&gt;org&amp;nbsp;for org-level,&amp;nbsp;repo&amp;nbsp;for repo-level&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;repos&lt;/td&gt;&lt;td&gt;your-repo-name&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Must match the repos you selected in your PAT (Step 1).&lt;/STRONG&gt;&amp;nbsp;Comma-separated, no spaces.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;targetWorkflowQueueLength&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Number of pending jobs needed to trigger one runner&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;labels&lt;/td&gt;&lt;td&gt;container-app&lt;/td&gt;&lt;td&gt;Must match&amp;nbsp;RUNNER_LABELS&amp;nbsp;env var and&amp;nbsp;runs-on&amp;nbsp;in your workflow&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="682"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;CRITICAL: Do NOT skip the&amp;nbsp;labels&amp;nbsp;parameter!&lt;/STRONG&gt;&amp;nbsp;Without it, KEDA cannot match pending jobs to your runner and will always show&amp;nbsp;MetricValue: 0.00&amp;nbsp;— meaning no containers will ever start. This is the most common setup mistake.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-line="684"&gt;&lt;STRONG&gt;Authentication:&lt;/STRONG&gt;&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Secret reference&lt;/th&gt;&lt;th&gt;Trigger parameter&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;EM&gt;(Leave empty for now — we'll configure this after creating the job and setting up Key Vault secrets in Step 7)&lt;/EM&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;personalAccessToken&lt;/STRONG&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="690"&gt;💡&amp;nbsp;&lt;STRONG&gt;The portal may let you save the scale rule without a secret reference.&lt;/STRONG&gt;&amp;nbsp;If it blocks you, delete the Authentication row entirely, click&amp;nbsp;&lt;STRONG&gt;Add scale rule&lt;/STRONG&gt;, and we'll add the authentication after the job is created.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P data-line="692"&gt;Click&amp;nbsp;&lt;STRONG&gt;Add scale rule&lt;/STRONG&gt;&amp;nbsp;→ Then click&amp;nbsp;&lt;STRONG&gt;Review + create&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Create&lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-line="694"&gt;⏳ Creation takes about 1 minute.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="696"&gt;⚠️&amp;nbsp;&lt;STRONG&gt;First-time creation may fail with an image pull error&lt;/STRONG&gt;&amp;nbsp;if you're creating a new Container Apps Environment at the same time. This happens because the environment's managed identity gets the AcrPull role during deployment, but the image pull happens before the role propagates. If this occurs, simply&amp;nbsp;&lt;STRONG&gt;Redeploy&lt;/STRONG&gt;&amp;nbsp;or create the Container App Job again — the role is already assigned and the second attempt will succeed.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="700"&gt;Step 7: Configure Managed Identity and Secrets&lt;/H2&gt;
&lt;P data-line="702"&gt;Now we need to:&lt;/P&gt;
&lt;OL data-line="703"&gt;
&lt;LI data-line="703"&gt;Enable Managed Identity on the Container App Job&lt;/LI&gt;
&lt;LI data-line="704"&gt;Grant it access to Key Vault and ACR&lt;/LI&gt;
&lt;LI data-line="705"&gt;Reference the GitHub PAT as a secret&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="707"&gt;7.1: Enable System-Assigned Managed Identity&lt;/H3&gt;
&lt;OL data-line="709"&gt;
&lt;LI data-line="709"&gt;Open your Container App Job (github-runner-job)&lt;/LI&gt;
&lt;LI data-line="710"&gt;In the left menu, go to&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Identity&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="711"&gt;Under&amp;nbsp;&lt;STRONG&gt;System assigned&lt;/STRONG&gt;, toggle&amp;nbsp;&lt;STRONG&gt;Status&lt;/STRONG&gt;&amp;nbsp;to&amp;nbsp;&lt;STRONG&gt;On&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="712"&gt;Click&amp;nbsp;&lt;STRONG&gt;Save&lt;/STRONG&gt;&amp;nbsp;→ Click&amp;nbsp;&lt;STRONG&gt;Yes&lt;/STRONG&gt;&amp;nbsp;to confirm&lt;/LI&gt;
&lt;LI data-line="713"&gt;Note the&amp;nbsp;&lt;STRONG&gt;Object ID&lt;/STRONG&gt;&amp;nbsp;that appears — you'll need this&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="715"&gt;7.2: Grant Key Vault Access&lt;/H3&gt;
&lt;OL data-line="717"&gt;
&lt;LI data-line="717"&gt;Go to your Key Vault (kv-github-runners)&lt;/LI&gt;
&lt;LI data-line="718"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Access Control (IAM)&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;+ Add role assignment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="719"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Role&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Key Vault Secrets User&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Assign access to&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Managed identity&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Members&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Search for&amp;nbsp;github-runner-job&amp;nbsp;and select it&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="727"&gt;
&lt;LI data-line="727"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + assign&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="729"&gt;7.3: Grant ACR Pull Access&lt;/H3&gt;
&lt;OL data-line="731"&gt;
&lt;LI data-line="731"&gt;Go to your Container Registry (yourregistryname)&lt;/LI&gt;
&lt;LI data-line="732"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Access Control (IAM)&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;+ Add role assignment&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="733"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Role&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;AcrPull&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Assign access to&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Managed identity&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Members&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Search for&amp;nbsp;github-runner-job&amp;nbsp;and select it&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="741"&gt;
&lt;LI data-line="741"&gt;Click&amp;nbsp;&lt;STRONG&gt;Review + assign&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="743"&gt;7.4: Add GitHub PAT as a Secret Reference&lt;/H3&gt;
&lt;OL data-line="745"&gt;
&lt;LI data-line="745"&gt;Go back to your Container App Job (github-runner-job)&lt;/LI&gt;
&lt;LI data-line="746"&gt;In the left menu, go to&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Secrets&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="747"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Add&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="748"&gt;Fill in:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Type&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Key Vault reference&lt;/STRONG&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Key&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-pat&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Key Vault secret URL&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Select your Key Vault and the&amp;nbsp;github-pat&amp;nbsp;secret&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Managed Identity&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;System assigned&lt;/STRONG&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="757"&gt;
&lt;LI data-line="757"&gt;Click&amp;nbsp;&lt;STRONG&gt;Add&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="759"&gt;7.5: Map the Secret to an Environment Variable&lt;/H3&gt;
&lt;OL data-line="761"&gt;
&lt;LI data-line="761"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Containers&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="762"&gt;Click on your container →&amp;nbsp;&lt;STRONG&gt;Edit&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="763"&gt;Go to the&amp;nbsp;&lt;STRONG&gt;Environment variables&lt;/STRONG&gt;&amp;nbsp;tab&lt;/LI&gt;
&lt;LI data-line="764"&gt;Click&amp;nbsp;&lt;STRONG&gt;+ Add&lt;/STRONG&gt;:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Source&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GITHUB_PAT&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Reference a secret&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-pat&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="770"&gt;
&lt;LI data-line="770"&gt;Click&amp;nbsp;&lt;STRONG&gt;Save&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P data-line="772"&gt;💡&amp;nbsp;&lt;STRONG&gt;If the Save button is greyed out&lt;/STRONG&gt;, try making a small edit to another field first (e.g., click into a value and click out) to trigger the save state. Alternatively, re-create the container with the correct env vars.&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;H2 data-line="776"&gt;Step 8: Configure KEDA Scale Rule (GitHub Runner Scaler)&lt;/H2&gt;
&lt;P data-line="778"&gt;This is where the magic happens. KEDA's GitHub Runner scaler monitors the GitHub Actions API for pending workflow jobs and scales your Container App Job accordingly.&lt;/P&gt;
&lt;H3 data-line="780"&gt;Steps:&lt;/H3&gt;
&lt;OL data-line="782"&gt;
&lt;LI data-line="782"&gt;Open your Container App Job (github-runner-job)&lt;/LI&gt;
&lt;LI data-line="783"&gt;Go to&amp;nbsp;&lt;STRONG&gt;Settings&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Scale&lt;/STRONG&gt;&amp;nbsp;(or&amp;nbsp;&lt;STRONG&gt;Scale and replicas&lt;/STRONG&gt;)&lt;/LI&gt;
&lt;LI data-line="784"&gt;Under&amp;nbsp;&lt;STRONG&gt;Scale rule&lt;/STRONG&gt;, click&amp;nbsp;&lt;STRONG&gt;+ Add&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="785"&gt;Fill in the scale rule:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Name&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner-rule&lt;/td&gt;&lt;td&gt;Any descriptive name&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Type&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Custom&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Select Custom&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Custom rule type&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-runner&lt;/td&gt;&lt;td&gt;This is the KEDA scaler type&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="793"&gt;
&lt;LI data-line="793"&gt;Under&amp;nbsp;&lt;STRONG&gt;Metadata&lt;/STRONG&gt;, add these key-value pairs:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;owner&lt;/td&gt;&lt;td&gt;your-github-org&lt;/td&gt;&lt;td&gt;Your GitHub org or username (e.g.,&amp;nbsp;Quality-Framework)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;repos&lt;/td&gt;&lt;td&gt;repo1,repo2&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Must match the repos you selected in your PAT token (Step 1).&lt;/STRONG&gt;&amp;nbsp;Comma-separated, no spaces. E.g.,&amp;nbsp;qualityframework-demo,qualityframework-bicep. Do NOT leave empty — if left empty, KEDA scans ALL org repos and you'll hit GitHub API rate limits.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;runnerScope&lt;/td&gt;&lt;td&gt;org&lt;/td&gt;&lt;td&gt;org&amp;nbsp;for org-level runners,&amp;nbsp;repo&amp;nbsp;for repo-level&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;labels&lt;/td&gt;&lt;td&gt;container-app&lt;/td&gt;&lt;td&gt;Must match the&amp;nbsp;RUNNER_LABELS&amp;nbsp;env var and the&amp;nbsp;runs-on&amp;nbsp;labels in your workflow YAML&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;targetWorkflowQueueLength&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Number of pending jobs needed to trigger one new runner instance&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="803"&gt;
&lt;LI data-line="803"&gt;Under&amp;nbsp;&lt;STRONG&gt;Authentication&lt;/STRONG&gt;, add:&lt;/LI&gt;
&lt;/OL&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Secret reference&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;github-pat&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Trigger parameter&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;personalAccessToken&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;OL data-line="810"&gt;
&lt;LI data-line="810"&gt;Click&amp;nbsp;&lt;STRONG&gt;Add&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Save&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="812"&gt;Understanding the Scale Rule&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;KEDA Action&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0 pending jobs with&amp;nbsp;container-app&amp;nbsp;label&lt;/td&gt;&lt;td&gt;0 runners (scale to zero)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 pending job&lt;/td&gt;&lt;td&gt;Starts 1 container&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3 pending jobs&lt;/td&gt;&lt;td&gt;Starts 3 containers (up to max)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Jobs complete&lt;/td&gt;&lt;td&gt;Containers stop, scale back to zero&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-line="823"&gt;Step 9: Test the Setup&lt;/H2&gt;
&lt;H3 data-line="825"&gt;9.1: Create a Test Workflow&lt;/H3&gt;
&lt;P data-line="827"&gt;In any repository within your GitHub organization, create a workflow file:&lt;/P&gt;
&lt;P data-line="829"&gt;&lt;STRONG&gt;File:&lt;/STRONG&gt;&amp;nbsp;.github/workflows/test-container-runner.yml&lt;/P&gt;
&lt;LI-CODE lang=""&gt;name: Test Container App Runner

on:
  workflow_dispatch:    # Allows manual trigger from GitHub UI
  push:
    branches: [main]

jobs:
  test-runner:
    runs-on: [self-hosted, container-app]   # Must match your RUNNER_LABELS
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Print runner info
        run: |
          echo "✅ Hello from Azure Container App Runner!"
          echo "Runner Name: $RUNNER_NAME"
          echo "Runner OS: $RUNNER_OS"
          echo "Workspace: $GITHUB_WORKSPACE"

      - name: Run a simple test
        run: |
          echo "Current directory: $(pwd)"
          echo "Files in repo:"
          ls -la
          echo "System info:"
          uname -a
          echo "Memory:"
          free -h&lt;/LI-CODE&gt;
&lt;H3 data-line="864"&gt;9.2: Trigger the Workflow&lt;/H3&gt;
&lt;OL data-line="866"&gt;
&lt;LI data-line="866"&gt;Go to your repository on GitHub&lt;/LI&gt;
&lt;LI data-line="867"&gt;Click&amp;nbsp;&lt;STRONG&gt;Actions&lt;/STRONG&gt;&amp;nbsp;tab&lt;/LI&gt;
&lt;LI data-line="868"&gt;Select&amp;nbsp;&lt;STRONG&gt;"Test Container App Runner"&lt;/STRONG&gt;&amp;nbsp;from the left sidebar&lt;/LI&gt;
&lt;LI data-line="869"&gt;Click&amp;nbsp;&lt;STRONG&gt;Run workflow&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Run workflow&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="871"&gt;9.3: Watch It Work&lt;/H3&gt;
&lt;OL data-line="873"&gt;
&lt;LI data-line="873"&gt;In the GitHub Actions tab, you'll see the job show as&amp;nbsp;&lt;STRONG&gt;"Queued"&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="874"&gt;In Azure Portal, go to your Container App Job →&amp;nbsp;&lt;STRONG&gt;Execution history&lt;/STRONG&gt;&lt;/LI&gt;
&lt;LI data-line="875"&gt;Within ~30 seconds (your polling interval), you should see a new execution start&lt;/LI&gt;
&lt;LI data-line="876"&gt;The job will:
&lt;UL data-line="877"&gt;
&lt;LI data-line="877"&gt;Container starts → Runner registers → Job executes → Container stops&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI data-line="878"&gt;Back in GitHub, the workflow run should show as ✅&amp;nbsp;&lt;STRONG&gt;completed&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;H3 data-line="880"&gt;Troubleshooting&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Problem&lt;/th&gt;&lt;th&gt;Likely Cause&lt;/th&gt;&lt;th&gt;Fix&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Job stays "Queued" forever&lt;/td&gt;&lt;td&gt;KEDA not detecting jobs&lt;/td&gt;&lt;td&gt;Check scale rule metadata — ensure&amp;nbsp;labels,&amp;nbsp;owner,&amp;nbsp;repos,&amp;nbsp;runnerScope&amp;nbsp;are all filled correctly&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Container starts but workflow doesn't complete&lt;/td&gt;&lt;td&gt;Wrong secret reference or empty env vars&lt;/td&gt;&lt;td&gt;Verify&amp;nbsp;GITHUB_PAT&amp;nbsp;env var points to correct secret, and all env vars have values&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;"Permission denied" errors&lt;/td&gt;&lt;td&gt;PAT missing required scopes&lt;/td&gt;&lt;td&gt;Edit PAT and add missing permissions (Step 1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Image pull errors on first deploy&lt;/td&gt;&lt;td&gt;ACR access timing issue&lt;/td&gt;&lt;td&gt;Redeploy — the AcrPull role was assigned but hadn't propagated yet&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Runner registers but job doesn't run&lt;/td&gt;&lt;td&gt;Label mismatch&lt;/td&gt;&lt;td&gt;Ensure&amp;nbsp;runs-on&amp;nbsp;labels in workflow match&amp;nbsp;RUNNER_LABELS&amp;nbsp;env var AND&amp;nbsp;labels&amp;nbsp;in KEDA scale rule&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Runner shows "Idle" but job stays queued&lt;/td&gt;&lt;td&gt;--disableupdate&amp;nbsp;flag or wrong runner group&lt;/td&gt;&lt;td&gt;Remove&amp;nbsp;--disableupdate&amp;nbsp;from&amp;nbsp;start.sh&amp;nbsp;and rebuild the image. Also verify&amp;nbsp;RUNNER_GROUP&amp;nbsp;env var matches the runner group name on GitHub, and the group has the correct repos assigned&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Runner version deprecated error&lt;/td&gt;&lt;td&gt;Outdated runner binary&lt;/td&gt;&lt;td&gt;Update&amp;nbsp;RUNNER_VERSION&amp;nbsp;in&amp;nbsp;Dockerfile&amp;nbsp;to the latest version and rebuild. Run&amp;nbsp;curl -s https://api.github.com/repos/actions/runner/releases/latest | jq -r '.tag_name'&amp;nbsp;to check&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hundreds of offline runners spawning&lt;/td&gt;&lt;td&gt;maxExecutions&amp;nbsp;set to 0 (unlimited)&lt;/td&gt;&lt;td&gt;Set&amp;nbsp;maxExecutions&amp;nbsp;to a reasonable limit (e.g., 5 or 10) in the scale rule settings&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Runner idle + job queued forever (public repo)&lt;/td&gt;&lt;td&gt;Runner group blocks public repos&lt;/td&gt;&lt;td&gt;Go to&amp;nbsp;&lt;STRONG&gt;Org Settings → Actions → Runner groups → your group&lt;/STRONG&gt;&amp;nbsp;and check&amp;nbsp;&lt;STRONG&gt;"Allow public repositories"&lt;/STRONG&gt;. Without this, GitHub silently refuses to dispatch jobs from public repos to runners in the group&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P data-line="894"&gt;&lt;STRONG&gt;To check container logs:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-line="896"&gt;Go to your Container App Job →&amp;nbsp;&lt;STRONG&gt;Monitoring&lt;/STRONG&gt;&amp;nbsp;→&amp;nbsp;&lt;STRONG&gt;Logs&lt;/STRONG&gt;&amp;nbsp;and run:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;ContainerAppConsoleLogs_CL | where ContainerGroupName_s startswith "github-runner-job" | where TimeGenerated &amp;gt; ago(30m) | order by TimeGenerated desc | take 20&lt;/LI-CODE&gt;
&lt;H2 data-line="945"&gt;Production Considerations&lt;/H2&gt;
&lt;H3 data-line="947"&gt;🔒 Networking: Private Environments&lt;/H3&gt;
&lt;P data-line="949"&gt;In production, your Container Apps Environment may be deployed inside a&amp;nbsp;&lt;STRONG&gt;VNet&lt;/STRONG&gt;&amp;nbsp;with no public internet access. Here's how to handle that:&lt;/P&gt;
&lt;H4 data-line="951"&gt;Private ACR Access&lt;/H4&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Container App Job ──(private endpoint)──► ACR&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;OL data-line="957"&gt;
&lt;LI data-line="957"&gt;Create a&amp;nbsp;&lt;STRONG&gt;Private Endpoint&lt;/STRONG&gt;&amp;nbsp;for your ACR&lt;/LI&gt;
&lt;LI data-line="958"&gt;Disable public access on ACR&lt;/LI&gt;
&lt;LI data-line="959"&gt;Ensure your Container Apps Environment is in the same (or peered) VNet&lt;/LI&gt;
&lt;/OL&gt;
&lt;H4 data-line="961"&gt;Private Key Vault Access&lt;/H4&gt;
&lt;P data-line="963"&gt;Same pattern — create a Private Endpoint for Key Vault and disable public access.&lt;/P&gt;
&lt;H4 data-line="965"&gt;GitHub API Access&lt;/H4&gt;
&lt;P data-line="967"&gt;Your runner containers need outbound access to:&lt;/P&gt;
&lt;UL data-line="968"&gt;
&lt;LI data-line="968"&gt;github.com&amp;nbsp;(runner registration)&lt;/LI&gt;
&lt;LI data-line="969"&gt;api.github.com&amp;nbsp;(KEDA polling)&lt;/LI&gt;
&lt;LI data-line="970"&gt;*.actions.githubusercontent.com&amp;nbsp;(downloading actions)&lt;/LI&gt;
&lt;/UL&gt;
&lt;P data-line="972"&gt;If using a firewall or NSG, ensure these are allowed.&lt;/P&gt;
&lt;H3 data-line="974"&gt;🔐 Using GitHub App Instead of PAT (Recommended for Production)&lt;/H3&gt;
&lt;P data-line="976"&gt;PATs are tied to individual users and have broad scopes. For production, consider using a&amp;nbsp;&lt;STRONG&gt;GitHub App&lt;/STRONG&gt;:&lt;/P&gt;
&lt;OL data-line="978"&gt;
&lt;LI data-line="978"&gt;Create a GitHub App in your organization&lt;/LI&gt;
&lt;LI data-line="979"&gt;Grant it&amp;nbsp;Organization Self-hosted runners: Read &amp;amp; Write&amp;nbsp;permissions&lt;/LI&gt;
&lt;LI data-line="980"&gt;Install the app in your organization&lt;/LI&gt;
&lt;LI data-line="981"&gt;Use the App ID and Private Key instead of PAT&lt;/LI&gt;
&lt;/OL&gt;
&lt;P data-line="983"&gt;The KEDA GitHub Runner scaler supports GitHub App authentication natively.&lt;/P&gt;
&lt;H3 data-line="985"&gt;📊 Monitoring and Alerting&lt;/H3&gt;
&lt;P data-line="987"&gt;Set up monitoring for your runners:&lt;/P&gt;
&lt;OL data-line="989"&gt;
&lt;LI data-line="989"&gt;&lt;STRONG&gt;Container App Job Metrics&lt;/STRONG&gt;&amp;nbsp;(Azure Monitor):
&lt;UL data-line="990"&gt;
&lt;LI data-line="990"&gt;Execution count&lt;/LI&gt;
&lt;LI data-line="991"&gt;Execution duration&lt;/LI&gt;
&lt;LI data-line="992"&gt;Failed executions&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI data-line="994"&gt;&lt;STRONG&gt;Alerts&lt;/STRONG&gt;&amp;nbsp;to set up:
&lt;UL data-line="995"&gt;
&lt;LI data-line="995"&gt;Alert when executions fail repeatedly&lt;/LI&gt;
&lt;LI data-line="996"&gt;Alert when execution queue is growing (KEDA can't keep up)&lt;/LI&gt;
&lt;LI data-line="997"&gt;Alert when runner registration fails (PAT expired?)&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI data-line="999"&gt;&lt;STRONG&gt;Log Analytics queries:&lt;/STRONG&gt;&lt;/LI&gt;
&lt;/OL&gt;
&lt;LI-CODE lang=""&gt;// Find failed executions
ContainerAppConsoleLogs_CL
| where ContainerGroupName_s startswith "github-runner-job"
| where Log_s contains "error" or Log_s contains "failed"
| order by TimeGenerated desc&lt;/LI-CODE&gt;
&lt;H3 data-line="1009"&gt;💰 Cost Optimization&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Strategy&lt;/th&gt;&lt;th&gt;Impact&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Scale to zero (min: 0)&lt;/td&gt;&lt;td&gt;No cost when idle&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Right-size CPU/memory&lt;/td&gt;&lt;td&gt;Don't over-provision&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Set reasonable max executions&lt;/td&gt;&lt;td&gt;Prevent runaway costs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Use Consumption plan&lt;/td&gt;&lt;td&gt;Pay per-second billing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Set replica timeout&lt;/td&gt;&lt;td&gt;Kill stuck jobs&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3 data-line="1019"&gt;🔄 Keeping the Runner Image Updated&lt;/H3&gt;
&lt;P data-line="1021"&gt;Runner versions get outdated. Set up automated rebuilds:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;# Create a scheduled ACR Task to rebuild weekly (single line for Cloud Shell)
az acr task create --registry yourregistryname --name rebuild-runner-weekly --image github-runner:latest --context https://github.com/your-org/runner-image-repo.git --file Dockerfile --schedule "0 0 * * 0" --git-access-token YOUR_PAT&lt;/LI-CODE&gt;
&lt;H2 data-line="1030"&gt;Appendix A: CLI Commands for All Steps&lt;/H2&gt;
&lt;P data-line="1032"&gt;If you prefer CLI over Portal, here are all the commands.&amp;nbsp;&lt;STRONG&gt;Run these in Azure Cloud Shell or any terminal with Azure CLI.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-line="1034"&gt;All commands are written as&amp;nbsp;&lt;STRONG&gt;single lines&lt;/STRONG&gt;&amp;nbsp;so they work directly in Azure Cloud Shell without formatting issues.&lt;/P&gt;
&lt;LI-CODE lang=""&gt;# ─── Set your variables (update these values) ───
RESOURCE_GROUP="rg-github-runners"
LOCATION="westus2"
ACR_NAME="yourregistryname"
KV_NAME="kvgithubrunners"
CAE_NAME="cae-github-runners"
JOB_NAME="github-runner-job"
IMAGE_NAME="github-runner"
IMAGE_TAG="v1"
GITHUB_ORG="your-github-org"

# ─── Step 1: Create Resource Group ───
az group create --name $RESOURCE_GROUP --location $LOCATION

# ─── Step 2: Create ACR ───
az acr create --name $ACR_NAME --resource-group $RESOURCE_GROUP --sku Basic

# ─── Step 3: Create Key Vault ───
az keyvault create --name $KV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION --enable-rbac-authorization

# ─── Step 4: Store PAT in Key Vault ───
az keyvault secret set --vault-name $KV_NAME --name "github-pat" --value "YOUR_PAT_HERE"

# ─── Step 5: Build Image with ACR Tasks (run from the folder with Dockerfile) ───
az acr build --registry $ACR_NAME --image $IMAGE_NAME:$IMAGE_TAG .

# ─── Step 6: Create Container Apps Environment ───
az containerapp env create --name $CAE_NAME --resource-group $RESOURCE_GROUP --location $LOCATION

# ─── Step 7: Create Container App Job (single command) ───
az containerapp job create --name $JOB_NAME --resource-group $RESOURCE_GROUP --environment $CAE_NAME --trigger-type Event --replica-timeout 1800 --replica-retry-limit 1 --replica-completion-count 1 --parallelism 1 --image "$ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG" --cpu "0.5" --memory "1Gi" --min-executions 0 --max-executions 5 --polling-interval 30 --scale-rule-name "github-runner-rule" --scale-rule-type "github-runner" --scale-rule-metadata "owner=$GITHUB_ORG" "runnerScope=org" "labels=container-app" "targetWorkflowQueueLength=1" --scale-rule-auth "personalAccessToken=github-pat" --secrets "github-pat=keyvaultref:https://$KV_NAME.vault.azure.net/secrets/github-pat,identityref:system" --env-vars "GITHUB_PAT=secretref:github-pat" "GITHUB_OWNER=$GITHUB_ORG" "RUNNER_SCOPE=org" "RUNNER_LABELS=container-app" "RUNNER_GROUP=container-app-runners" --registry-server "$ACR_NAME.azurecr.io" --registry-identity "system"&lt;/LI-CODE&gt;
&lt;H2 data-line="1072"&gt;Appendix B: Repo-Level Runner Changes&lt;/H2&gt;
&lt;P data-line="1074"&gt;If you want runners at the&amp;nbsp;&lt;STRONG&gt;repository level&lt;/STRONG&gt;&amp;nbsp;instead of organization level:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Setting&lt;/th&gt;&lt;th&gt;Org-Level&lt;/th&gt;&lt;th&gt;Repo-Level&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;PAT scope&lt;/td&gt;&lt;td&gt;admin:org&lt;/td&gt;&lt;td&gt;repo&amp;nbsp;only&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RUNNER_SCOPE&amp;nbsp;env var&lt;/td&gt;&lt;td&gt;org&lt;/td&gt;&lt;td&gt;repo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GITHUB_REPO&amp;nbsp;env var&lt;/td&gt;&lt;td&gt;Not needed&lt;/td&gt;&lt;td&gt;Required (e.g.,&amp;nbsp;my-repo)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KEDA&amp;nbsp;runnerScope&lt;/td&gt;&lt;td&gt;org&lt;/td&gt;&lt;td&gt;repo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KEDA&amp;nbsp;repos&lt;/td&gt;&lt;td&gt;Optional&lt;/td&gt;&lt;td&gt;Required&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H2 data-line="1086"&gt;Summary&lt;/H2&gt;
&lt;P data-line="1088"&gt;Here's what we built:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;What It Does&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Dockerfile + start.sh&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Creates an ephemeral GitHub Actions runner image&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;ACR&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Stores the runner image securely&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Key Vault&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Stores the GitHub PAT securely&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Container Apps Environment&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Provides the hosting platform&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Container App Job&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Runs the runner containers on demand&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;KEDA Scale Rule&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Automatically scales runners based on pending GitHub jobs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;STRONG&gt;Managed Identity&lt;/STRONG&gt;&lt;/td&gt;&lt;td&gt;Connects everything securely without passwords&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3 data-line="1100"&gt;The Result:&lt;/H3&gt;
&lt;P data-line="1102"&gt;✅&amp;nbsp;&lt;STRONG&gt;Zero cost when idle&lt;/STRONG&gt;&amp;nbsp;— no VMs running 24/7 ✅&amp;nbsp;&lt;STRONG&gt;Automatic scaling&lt;/STRONG&gt;&amp;nbsp;— KEDA handles it ✅&amp;nbsp;&lt;STRONG&gt;Ephemeral runners&lt;/STRONG&gt;&amp;nbsp;— clean environment every time ✅&amp;nbsp;&lt;STRONG&gt;Secure&lt;/STRONG&gt;&amp;nbsp;— secrets in Key Vault, Managed Identity for auth ✅&amp;nbsp;&lt;STRONG&gt;No Docker required&lt;/STRONG&gt;&amp;nbsp;— ACR Tasks builds images in the cloud ✅&amp;nbsp;&lt;STRONG&gt;Production ready&lt;/STRONG&gt;&amp;nbsp;— private networking, monitoring, automated image updates&lt;/P&gt;
&lt;P data-line="1102"&gt;-------------------------------------------------------------------------------------------&lt;/P&gt;
&lt;P data-line="1111"&gt;&lt;STRONG&gt;&lt;EM&gt;Have questions or feedback? Drop a comment below!&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P data-line="1113"&gt;&lt;EM&gt;Tags: Azure, Container Apps, GitHub Actions, KEDA, Self-hosted Runners, DevOps, Serverless&lt;/EM&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 04 May 2026 13:03:30 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/running-github-actions-runners-on-azure-container-apps-with-keda/ba-p/4512980</guid>
      <dc:creator>shubhijain</dc:creator>
      <dc:date>2026-05-04T13:03:30Z</dc:date>
    </item>
    <item>
      <title>Modernizing Terraform Pipelines on Azure: OIDC Federation for GitHub Actions and Azure DevOps</title>
      <link>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/modernizing-terraform-pipelines-on-azure-oidc-federation-for/ba-p/4516620</link>
      <description>&lt;H3&gt;The secret nobody wants to rotate&lt;/H3&gt;
&lt;P&gt;Most Terraform-on-Azure pipelines we see still authenticate the same way they did three years ago. A long-lived ARM_CLIENT_SECRET sitting in GitHub Actions or Azure DevOps, set once, copied around, and rotated only when something breaks.&lt;/P&gt;
&lt;P&gt;It's the most ignored credential in the cloud, and statistically the most likely one to leak. A developer screenshots a variable group. A pipeline log echoes a value. A fork inherits a secret. Or the secret simply expires on a Friday evening and takes production deployments with it.&lt;/P&gt;
&lt;P&gt;Workload Identity Federation (WIF) makes this whole class of problem go away. The pipeline mints a short-lived token at runtime, exchanges it for an Azure access token via Microsoft Entra, and never touches a secret. GitHub Actions has supported it since 2021. Azure DevOps service connections went GA with WIF in February 2024. The azurerm Terraform provider has supported it since v3.7.&lt;/P&gt;
&lt;P&gt;This post walks through the pattern end-to-end, for both GitHub Actions and Azure DevOps, the way I've rolled it out across multiple customer estates.&lt;/P&gt;
&lt;H3&gt;How the exchange actually works&lt;/H3&gt;
&lt;P&gt;Before any YAML, it helps to picture what's happening:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The CI system (GitHub or ADO) signs a short-lived JWT describing&amp;nbsp;&lt;EM&gt;exactly&lt;/EM&gt; what's running- which repo, which branch, which environment, which service connection.&lt;/LI&gt;
&lt;LI&gt;The pipeline sends that JWT to Microsoft Entra ID.&lt;/LI&gt;
&lt;LI&gt;Entra checks it against a&amp;nbsp;&lt;STRONG&gt;federated identity credential&lt;/STRONG&gt; you've configured on a managed identity or app registration. The iss, sub, and aud claims must match case-sensitively.&lt;/LI&gt;
&lt;LI&gt;If it matches, Entra returns an Azure access token valid for the duration of the job.&lt;/LI&gt;
&lt;LI&gt;Terraform uses it. The job ends. The token expires. Nothing persists.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The token is bound to a specific subject like repo:contoso/platform:environment:prod or sc://contoso/platform/azure-prod. It can't be reused from another repo, branch, or pipeline.&lt;/P&gt;
&lt;img /&gt;
&lt;H3&gt;Recommended Architecture&lt;/H3&gt;
&lt;P&gt;A few choices that usually hold up in production:&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Decision&lt;/th&gt;&lt;th&gt;Choice&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Identity type&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;User-assigned managed identity (UAMI)&lt;/STRONG&gt;, not app registration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Identity granularity&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;One UAMI per environment&lt;/STRONG&gt;&amp;nbsp;(not per pipeline)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Trust scope&lt;/td&gt;&lt;td&gt;Pinned to the&amp;nbsp;&lt;STRONG&gt;environment&lt;/STRONG&gt;&amp;nbsp;claim, not the branch&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RBAC scope&lt;/td&gt;&lt;td&gt;&lt;STRONG&gt;Resource group&lt;/STRONG&gt;, not subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Remote state&lt;/td&gt;&lt;td&gt;OIDC +&amp;nbsp;use_azuread_auth = true, shared key access disabled&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;Why UAMIs? They live in your subscription, don't need Application Administrator rights to manage, and follow the lifecycle of the resource group they belong to. Why one per environment? Pipeline-per-identity explodes into hundreds of identities. Environment-per-identity maps cleanly to deployment scopes.&lt;/P&gt;
&lt;H3&gt;Part 1 - GitHub Actions&lt;/H3&gt;
&lt;H4&gt;Step 1: Create the identity and federate it&lt;/H4&gt;
&lt;P&gt;Two commands &lt;STRONG&gt;per environment&lt;/STRONG&gt;. That's it.&lt;/P&gt;
&lt;LI-CODE lang="markdown"&gt;az identity create -g rg-platform-identity -n id-tf-prod -l eastus

az identity federated-credential create \
  --name github-prod \
  --identity-name id-tf-prod \
  --resource-group rg-platform-identity \
  --issuer https://token.actions.githubusercontent.com \
  --subject repo:contoso/platform:environment:prod \
  --audiences api://AzureADTokenExchange&lt;/LI-CODE&gt;
&lt;P&gt;Repeat for nonprod. No secret is created anywhere.&lt;/P&gt;
&lt;H4&gt;Step 2: Wire it up in GitHub&lt;/H4&gt;
&lt;P&gt;In repo&amp;nbsp;&lt;STRONG&gt;Settings → Environments&lt;/STRONG&gt;, create&amp;nbsp;nonprod&amp;nbsp;and&amp;nbsp;prod. On&amp;nbsp;prod, add required reviewers and a branch rule restricting deployments to&amp;nbsp;main. Then add three&amp;nbsp;&lt;STRONG&gt;environment variables&lt;/STRONG&gt; (not secrets - these aren't sensitive): AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID.&lt;/P&gt;
&lt;P&gt;The workflow itself stays small:&lt;/P&gt;
&lt;LI-CODE lang="yaml"&gt;permissions:
  id-token: write
  contents: read

jobs:
  apply:
    runs-on: ubuntu-latest
    environment: prod
    env:
      ARM_USE_OIDC: "true"
      ARM_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
      ARM_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
      ARM_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init &amp;amp;&amp;amp; terraform apply -auto-approve&lt;/LI-CODE&gt;
&lt;P&gt;Three things make this secure:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;id-token: write&amp;nbsp;is the only elevated permission, and it doesn't grant write access to anything&amp;nbsp;&lt;EM&gt;in GitHub,&lt;/EM&gt;&amp;nbsp;it just lets the runner mint a JWT.&lt;/LI&gt;
&lt;LI&gt;The&amp;nbsp;environment:&amp;nbsp;line picks the right&amp;nbsp;AZURE_CLIENT_ID&amp;nbsp;&lt;EM&gt;and&lt;/EM&gt;&amp;nbsp;drives the&amp;nbsp;sub&amp;nbsp;claim. The federation refuses anything else.&lt;/LI&gt;
&lt;LI&gt;No azure/login step is needed for Terraform. The azurerm provider reads GitHub's OIDC environment variables automatically.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Part 2 - Azure DevOps&lt;/H3&gt;
&lt;P&gt;The model is identical. The mechanics are different.&lt;/P&gt;
&lt;P&gt;ADO offers two creation paths for a WIF service connection:&amp;nbsp;&lt;STRONG&gt;automatic&lt;/STRONG&gt;&amp;nbsp;(it creates an app registration for you) and&amp;nbsp;&lt;STRONG&gt;manual&lt;/STRONG&gt; (you bring your own UAMI). For platform teams, manual + UAMI is almost always the better choice to ensure identity lives where governance lives.&lt;/P&gt;
&lt;P&gt;The flow is a small dance between the two portals:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In Azure DevOps, create a new ARM service connection → choose&amp;nbsp;&lt;STRONG&gt;Workload Identity Federation (manual)&lt;/STRONG&gt;&amp;nbsp;→ fill in your UAMI's client ID, tenant ID, and subscription. Save&amp;nbsp;&lt;STRONG&gt;as draft&lt;/STRONG&gt;. ADO shows you an issuer URL and a subject identifier.&lt;/LI&gt;
&lt;LI&gt;In Azure, on the UAMI, add a federated credential using the values ADO showed you. The subject looks like&amp;nbsp;sc://contoso/platform/azure-prod.&lt;/LI&gt;
&lt;LI&gt;Back in ADO, click&amp;nbsp;&lt;STRONG&gt;Verify and save&lt;/STRONG&gt;.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;In the pipeline, the service connection only "activates" if a task in the job loads it. The simplest way is the AzureCLI@2 task:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;- task: AzureCLI@2
  inputs:
    azureSubscription: azure-prod   # the WIF service connection
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      terraform init &amp;amp;&amp;amp; terraform apply -auto-approve
  env:
    ARM_USE_OIDC: "true"
    ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
    ARM_TENANT_ID: $(AZURE_TENANT_ID)
    ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
    ARM_ADO_PIPELINE_SERVICE_CONNECTION_ID: $(SERVICE_CONNECTION_ID)
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)
    SYSTEM_OIDCREQUESTURI: $(System.OidcRequestUri)&lt;/LI-CODE&gt;
&lt;P&gt;For teams converting dozens of legacy connections, the Azure DevOps team published a&amp;nbsp;&lt;A class="lia-external-url" href="https://devblogs.microsoft.com/devops/workload-identity-federation-for-azure-deployments-is-now-generally-available/" target="_blank" rel="noopener" data-href="https://devblogs.microsoft.com/devops/workload-identity-federation-for-azure-deployments-is-now-generally-available/"&gt;PowerShell helper&lt;/A&gt;&amp;nbsp;that walks every ARM service connection in a project and converts them in place. There's a 7-day rollback window on each connection, which makes the migration genuinely low-risk.&lt;/P&gt;
&lt;img /&gt;
&lt;H3&gt;Don't forget the state file&lt;/H3&gt;
&lt;P&gt;The Terraform state is your real blast radius. With OIDC, it's almost free to lock it down too. The same UAMI can read and write blob data without the storage account key:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;backend "azurerm" {
  resource_group_name  = "rg-tfstate"
  storage_account_name = "sttfstateprodeastus"
  container_name       = "platform-prod"
  key                  = "platform.tfstate"
  use_oidc             = true
  use_azuread_auth     = true
}&lt;/LI-CODE&gt;
&lt;P&gt;Grant the UAMI&amp;nbsp;Storage Blob Data Contributor&amp;nbsp;on the&amp;nbsp;&lt;STRONG&gt;container&lt;/STRONG&gt;&amp;nbsp;(not the account), disable shared key access on the storage account, and you've removed the last secret in the pipeline.&lt;/P&gt;
&lt;H3&gt;RBAC and break-glass&lt;/H3&gt;
&lt;P&gt;Federation removes a credential, not a privilege. A few habits worth keeping:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;Scope role assignments to resource groups&lt;/STRONG&gt;, not subscriptions. The whole point of federation is that scoping is now trivially easy.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Use&amp;nbsp;Role Based Access Control Administrator&lt;/STRONG&gt;&amp;nbsp;instead of&amp;nbsp;User Access Administrator&amp;nbsp;if your Terraform creates role assignments. It's a more recent, narrower role.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Have a documented break-glass.&lt;/STRONG&gt; If GitHub or ADO has a token-service incident, you still need a path to ship a hotfix. A single hardware-key-protected emergency app registration in a separate identity boundary works well, audited monthly.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Monitor sign-ins.&lt;/STRONG&gt; Every federated exchange shows up in Entra sign-in logs as a service principal sign-in. Pipe these to Sentinel and alert on anomalies like sign-ins outside expected hours, or from IPs outside GitHub's published ranges.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;The errors you will hit (and what they really mean)&lt;/H3&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Symptom&lt;/th&gt;&lt;th&gt;What it actually is&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;AADSTS70021: No matching federated identity record found&lt;/td&gt;&lt;td&gt;Case-sensitive mismatch in&amp;nbsp;iss,&amp;nbsp;sub, or&amp;nbsp;aud. Almost always a trailing slash or a capitalised character&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AADSTS700016: Application not found in directory&lt;/td&gt;&lt;td&gt;Wrong client ID or tenant. Not a federation problem&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;403 on a resource even though token exchange worked&lt;/td&gt;&lt;td&gt;Federation is fine. Your RBAC isn't. Check the exact scope&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Unable to determine OIDC token&amp;nbsp;(ADO)&lt;/td&gt;&lt;td&gt;No task in the job loaded the service connection. Add an&amp;nbsp;AzureCLI@2&amp;nbsp;step&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Works on&amp;nbsp;main, fails on tags&lt;/td&gt;&lt;td&gt;You pinned&amp;nbsp;sub&amp;nbsp;to a branch ref. Add a second federated credential for tags, or move to environment-based scoping&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H3&gt;Migrating without a maintenance window&lt;/H3&gt;
&lt;P&gt;You almost never get to do this on a greenfield repo. The order that has worked for me on legacy estates:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Create the new UAMI alongside the old service principal, with the same role assignments.&lt;/LI&gt;
&lt;LI&gt;Federate one canary pipeline. Verify it deploys equivalently.&lt;/LI&gt;
&lt;LI&gt;Cut over pipelines in waves, lowest-risk environment first.&lt;/LI&gt;
&lt;LI&gt;Once a full release cycle passes cleanly, disable the old SP's secret.&lt;/LI&gt;
&lt;LI&gt;Wait another cycle. Then delete the SP entirely.&lt;/LI&gt;
&lt;LI&gt;Add a CI gate that fails any new pipeline introducing ARM_CLIENT_SECRET.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;The old and new auth methods coexist on the same subscription throughout. There's no hard cutover and no maintenance window, just a steady drift toward zero secrets.&lt;/P&gt;
&lt;H3&gt;Wrapping up&lt;/H3&gt;
&lt;P&gt;If you do nothing else after reading this, do one thing: search your CI variable groups for ARM_CLIENT_SECRET. Every result is an outage or a breach waiting to happen.&lt;/P&gt;
&lt;P&gt;Federation is one of those rare changes that's both more secure&amp;nbsp;&lt;EM&gt;and&lt;/EM&gt;&amp;nbsp;less work to operate. Once you've set it up, you stop thinking about credential rotation, secret expiry, and quarterly access reviews for service principals. The pipeline simply runs, and the audit trail is in Entra where it belongs.&lt;/P&gt;
&lt;P&gt;That's a good trade.&lt;/P&gt;</description>
      <pubDate>Sat, 02 May 2026 20:34:19 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/azure-infrastructure-blog/modernizing-terraform-pipelines-on-azure-oidc-federation-for/ba-p/4516620</guid>
      <dc:creator>ssinghkalra</dc:creator>
      <dc:date>2026-05-02T20:34:19Z</dc:date>
    </item>
  </channel>
</rss>

