<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Working with Azure Logic Apps on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/series/working-with-azure-logic-apps/</link><description>Recent content in Working with Azure Logic Apps on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 03 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/series/working-with-azure-logic-apps/index.xml" rel="self" type="application/rss+xml"/><item><title>Azure Logic Apps Standard | Send Custom Events to Application Insights</title><link>https://andrewilson.co.uk/post/2026/02/logic-app-standard-send-custom-events-application-insights/</link><pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2026/02/logic-app-standard-send-custom-events-application-insights/</guid><description>Introduction When building integration workflows with Azure Logic Apps Standard, there&amp;rsquo;s often a need to track custom business events that sit between pure technical telemetry and business process monitoring. Recently, while authoring a Logic App Standard workflow, I needed to track the total number of items processed along with a breakdown of successful versus failed processing attempts.
While Logic Apps provides excellent run history and built-in diagnostics, custom events allow you to capture specific business actions and metrics that align with your reporting requirements.</description><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>When building integration workflows with Azure Logic Apps Standard, there&rsquo;s often a need to track custom business events that sit between pure technical telemetry and business process monitoring. Recently, while authoring a Logic App Standard workflow, I needed to track the total number of items processed along with a breakdown of successful versus failed processing attempts.</p>
<p>While Logic Apps provides excellent run history and built-in diagnostics, custom events allow you to capture specific business actions and metrics that align with your reporting requirements. In this post, I&rsquo;ll show you how to send custom events directly to Azure Application Insights using the ingestion endpoint from the Application Insights connection string.</p>
<h2 id="the-use-case">The Use Case</h2>
<p>I needed to answer questions like:</p>
<ul>
<li>How many items were processed in total for a workflow run?</li>
<li>What&rsquo;s the success vs. failure rate for different item types?</li>
<li>Can I correlate these metrics with other application telemetry?</li>
</ul>
<p>Standard Logic Apps diagnostics don&rsquo;t easily provide this level of custom business metric tracking, making Application Insights custom events the perfect solution.</p>
<h2 id="understanding-the-application-insights-ingestion-endpoint">Understanding the Application Insights Ingestion Endpoint</h2>
<p>The Application Insights connection string contains several components, including the ingestion endpoint. It looks something like this:</p>
<pre tabindex="0"><code>InstrumentationKey=&lt;key&gt;;IngestionEndpoint=https://&lt;region&gt;.in.applicationinsights.azure.com/;LiveEndpoint=https://&lt;region&gt;.livediagnostics.monitor.azure.com/;ApplicationId=&lt;ID&gt;

// Broken Down
//------------
InstrumentationKey=&lt;key&gt;

IngestionEndpoint=https://&lt;region&gt;.in.applicationinsights.azure.com/

LiveEndpoint=https://&lt;region&gt;.livediagnostics.monitor.azure.com/

ApplicationId=&lt;ID&gt;
</code></pre><p>The Ingestion Endpoint component as the name suggests is used for the ingest of telemetry/metrics/events/etc. The component points to a regional Application Insights endpoint with the Instrumentation key supplied later in in the ingestion request for targeting your specific Application Insights instance.</p>
<p>The missing part to this endpoint that allows you to post your telemetry is a trailing <code>v2/track</code>. Combined this appears as follows:
<code>https://&lt;region&gt;.in.applicationinsights.azure.com/v2/track</code></p>
<p>We&rsquo;ll use the <code>IngestionEndpoint</code> combined with the <code>InstrumentationKey</code> to send custom events via HTTP requests.</p>
<h2 id="implementation">Implementation</h2>
<h3 id="step-1-configure-application-insights-connection-in-bicep">Step 1: Configure Application Insights Connection in Bicep</h3>
<p>First, we need to extract the ingestion endpoint and instrumentation key from Application Insights and make them available to our Logic App as application settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationInsights</span> <span style="color:#f1fa8c">&#39;Microsoft.Insights/components@2020-02-02&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">applicationInsightsName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppDeployment</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2025-03-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">Location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">kind</span>: <span style="color:#f1fa8c">&#39;functionapp,workflowapp&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">siteConfig</span>: {
</span></span><span style="display:flex;"><span>      ...
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">appSettings</span>: [
</span></span><span style="display:flex;"><span>        ...
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;appInsightsIngestUrl&#39;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#50fa7b">split</span>(<span style="color:#50fa7b">filter</span>(<span style="color:#50fa7b">split</span>(<span style="color:#8be9fd;font-style:italic">applicationInsights</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">ConnectionString</span>, <span style="color:#f1fa8c">&#39;;&#39;</span>), <span style="color:#8be9fd;font-style:italic">val</span> =&gt; <span style="color:#50fa7b">contains</span>(<span style="color:#8be9fd;font-style:italic">val</span>, <span style="color:#f1fa8c">&#39;IngestionEndpoint=&#39;</span>))[<span style="color:#8be9fd;font-style:italic">0</span>], <span style="color:#f1fa8c">&#39;=&#39;</span>)[<span style="color:#8be9fd;font-style:italic">1</span>]<span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">v2/track&#39;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;appInsightsKey&#39;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">applicationInsights</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">InstrumentationKey</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      ]
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Bicep code above parses the connection string to extract the ingestion endpoint and appends the required <code>v2/track</code> path. It also captures the instrumentation key needed to point to your instance.</p>
<h3 id="step-2-create-logic-app-parameters">Step 2: Create Logic App Parameters</h3>
<p>Add parameters to your Logic App Workflow&rsquo;s <code>parameters.json</code> file to reference these application settings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;AppInsightsIngestionUrl&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;value&#34;</span>: <span style="color:#f1fa8c">&#34;@appsetting(&#39;appInsightsIngestUrl&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;AppInsightsKey&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;value&#34;</span>: <span style="color:#f1fa8c">&#34;@appsetting(&#39;appInsightsKey&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>These parameters allow your workflow to access the ingestion URL and key at runtime.</p>
<h3 id="step-3-add-the-workflow-actions-and-event-payload">Step 3: Add the Workflow Actions and Event Payload</h3>
<p>In your Logic App workflow, use a <strong>Compose</strong> action to build the Application Insights event payload. The payload follows the Application Insights telemetry schema:</p>
<p>
  <img src="/images/posts/2026/02/CustomEventsLGActions.png" alt="CustomEventsLGActions">

</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;Microsoft.ApplicationInsights.@{parameters(&#39;AppInsightsKey&#39;)}.Event&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;time&#34;</span>: <span style="color:#f1fa8c">&#34;@{utcNow()}&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;iKey&#34;</span>: <span style="color:#f1fa8c">&#34;@{parameters(&#39;AppInsightsKey&#39;)}&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;data&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;baseType&#34;</span>: <span style="color:#f1fa8c">&#34;EventData&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;baseData&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;ver&#34;</span>: <span style="color:#f1fa8c">&#34;2&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;LogicAppWorkflowName&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;properties&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;workflowRunId&#34;</span>: <span style="color:#f1fa8c">&#34;@{workflow().run.name}&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;ItemsProcessed&#34;</span>: <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type1Count&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type1CountFailures&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type2Count&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type2CountFailures&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type3Count&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;Type3CountFailures&#34;</span>:  <span style="color:#f1fa8c">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Key components of the payload:</p>
<ul>
<li><strong>name</strong>: Event identifier following Application Insights naming convention</li>
<li><strong>time</strong>: Timestamp in UTC format</li>
<li><strong>iKey</strong>: Your instrumentation key</li>
<li><strong>data.baseData.name</strong>: The custom event name that will appear in Application Insights</li>
<li><strong>data.baseData.properties</strong>: Your custom properties containing business metrics</li>
</ul>
<h3 id="step-4-send-the-event-via-http">Step 4: Send the Event via HTTP</h3>
<p>Add an <strong>HTTP</strong> action to send the composed payload to Application Insights:</p>
<p>
  <img src="/images/posts/2026/02/CustomEventsLGHTTP.png" alt="CustomEventsLGHTTPAction">

</p>
<p>Configure the HTTP action with:</p>
<ul>
<li><strong>Method</strong>: POST</li>
<li><strong>URI</strong>: <code>@{parameters('AppInsightsIngestionUrl')}</code></li>
<li><strong>Headers</strong>: <code>Content-Type: application/json</code></li>
<li><strong>Body</strong>: Output from the Compose action</li>
</ul>
<p>The HTTP action will receive a 200 OK response when the event is successfully ingested.</p>
<p>The response body should indicate a successful ingestion as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;itemsReceived&#34;</span>: <span style="color:#bd93f9">1</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;itemsAccepted&#34;</span>: <span style="color:#bd93f9">1</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;errors&#34;</span>: []
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="step-5-query-your-events">Step 5: Query Your Events</h3>
<p>After your workflow runs, navigate to Application Insights and use the following KQL query to view your custom events:</p>
<pre tabindex="0"><code class="language-kusto" data-lang="kusto">customEvents
| where name == &#34;LogicAppWorkflowName&#34;
| project timestamp, 
          workflowRunId = tostring(customDimensions.workflowRunId),
          itemsProcessed = toint(customDimensions.ItemsProcessed),
          type1Success = toint(customDimensions.Type1Count),
          type1Failures = toint(customDimensions.Type1CountFailures)
| order by timestamp desc
</code></pre><p>You can create custom dashboards, alerts, and reports based on these events.</p>
<h2 id="summary">Summary</h2>
<p>By leveraging the Application Insights ingestion endpoint directly via HTTP actions, you can easily track custom business metrics from your Logic Apps Standard workflows without external dependencies. This approach lets you correlate workflow execution with wider integration components/applications and build comprehensive dashboards based on your specific use case.</p>
<p>Hope this helps, and keep Workflow-ing!</p>
]]></content:encoded></item><item><title>Agent Loop | Azure Logic Apps Just Got Smarter</title><link>https://andrewilson.co.uk/post/2025/05/agent-loop-announcement-microsoft-logic-apps/</link><pubDate>Wed, 21 May 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/05/agent-loop-announcement-microsoft-logic-apps/</guid><description>Microsoft Announcement Microsoft has just introduced something quite revolutionary into the world of integration: Agent Loop, a new capability in Azure Logic Apps that lets you build AI-powered agents directly into your workflows. On the surface, it might seem like another incremental feature. But dig a little deeper, and the implications are huge!
Let’s break it down.
What Is Agent Loop? Agent Loop is Microsoft’s way of embedding advanced AI decision-making into Logic Apps workflows.</description><content:encoded><![CDATA[<h2 id="microsoft-announcement">Microsoft Announcement</h2>
<p>Microsoft has just introduced something quite revolutionary into the world of integration: <strong>Agent Loop</strong>, a new capability in Azure Logic Apps that lets you build AI-powered agents directly into your workflows. On the surface, it might seem like another incremental feature. But dig a little deeper, and the implications are huge!</p>
<p>Let’s break it down.</p>
<h2 id="what-is-agent-loop">What Is Agent Loop?</h2>
<p>Agent Loop is Microsoft’s way of embedding <strong>advanced AI decision-making</strong> into Logic Apps workflows. Think of it like adding a smart co-pilot into your integration flows, an agent that can <strong>retain context, reason over time, and take meaningful actions</strong>. It uses an LLM like Azure OpenAI under the hood, paired with a memory store that persists throughout the workflow, allowing the agent to understand, adapt, and make decisions across multiple steps.</p>
<p>This isn’t just a chat feature bolted onto Logic Apps. This is <strong>a new integration pattern</strong>.</p>
<h2 id="why-this-matters">Why This Matters</h2>
<h3 id="1-from-orchestrators-to-orchestrators-with-brains">1. From Orchestrators to Orchestrators-With-Brains</h3>
<p>Traditionally, Logic Apps has been a powerful tool for orchestrating workflows, but each step is stateless and reactive. With Agent Loop, Microsoft is blurring the lines between <strong>workflow automation and autonomous decision-making</strong>. Your integration logic can now evolve based on prior inputs, contextual signals, or even unstructured content.</p>
<p>Imagine an agent that:</p>
<ul>
<li>Detects anomalies in data feeds and adjusts routing accordingly</li>
<li>Analyses unstructured text (emails, tickets, PDFs) and initiates remediation</li>
<li>Talks to legacy systems, interprets responses, and adapts its logic in real time</li>
</ul>
<p>This isn’t just modernisation, it’s <strong>next-gen augmentation</strong>.</p>
<h3 id="2-for-biztalk-migrations-this-changes-the-equation">2. For BizTalk Migrations, This Changes the Equation</h3>
<p>Many of the workflows built in BizTalk were complex not just because of their integration points, but because of the <strong>decision logic</strong> baked into orchestration layers. Until now, moving those workflows into Azure meant carefully untangling rulesets, mappings, and dependencies.</p>
<p>Agent Loop gives you a new option, <strong>wrap legacy logic in an AI reasoning layer</strong>, preserve existing behaviour where needed, and <strong>inject flexibility</strong> where it&rsquo;s long overdue. That’s a big deal for organisations plotting their <strong>BizTalk to Azure Integration Services (AIS)</strong> migration.</p>
<h3 id="3-bridging-structured-and-unstructured-worlds">3. Bridging Structured and Unstructured Worlds</h3>
<p>In most enterprises, structured data lives in databases, but the real mess, the emails, PDFs, meeting notes, customer queries, is where value is trapped. Agent Loop lets you embed GPT-style agents that can process unstructured inputs, make sense of them, and act accordingly.</p>
<p>In effect, it bridges the gap between <strong>API-driven systems and human language interactions</strong>, a holy grail for integration architecture.</p>
<h2 id="what-could-this-enable">What Could This Enable?</h2>
<p>Some early scenarios come to mind:</p>
<ul>
<li><strong>Intelligent triage</strong>: Auto-routing support tickets based on nuanced analysis, not just keywords</li>
<li><strong>Contract processing</strong>: Reading legal documents and extracting obligations for ERP updates</li>
<li><strong>Integration self-healing</strong>: Agents that spot failed API calls and retry or switch endpoints contextually</li>
<li><strong>Customer 360 augmentation</strong>: Combining CRM data with email sentiment to tailor outreach strategies</li>
</ul>
<p>What’s powerful here is not just the AI, it’s that the AI lives inside your <strong>governed, observable, enterprise-ready integration fabric</strong>. That’s the kind of maturity architects have been waiting for.</p>
<h2 id="the-bigger-picture">The Bigger Picture</h2>
<p>This move by Microsoft is a signal, <strong>AI isn’t a separate strategy anymore, it’s becoming part of the plumbing</strong>. And for IT leaders, that means a shift in how we think about capability building.</p>
<p>Where before we asked, “What can be automated?”, now we ask, “What can be <strong>intelligently</strong> automated?”
Where we once feared black-box AI, now we can build AI agents that live inside controlled workflows.</p>
<h2 id="a-word-of-caution">A Word of Caution</h2>
<p>This is still early days. Agent Loop is in public preview, and like all AI features, there are concerns around predictability, testing, and operational risk. Governance, testing harnesses, and monitoring patterns will also need to be matured alongside adoption.</p>
<p>But make no mistake, this is a foundational shift.</p>
<h2 id="getting-started">Getting Started</h2>
<p>Agent Loop is already available in Logic Apps Standard! Here are some Microsoft resources to help you begin:</p>
<ul>
<li><strong>Documentation</strong>: Explore the <a href="https://aka.ms/agentloopconcepts">agent loop concepts</a> and <a href="https://aka.ms/AgentLoopHowTo">detailed guide with step-by-step instructions</a> on how to configure and use Agent Loop.</li>
<li><strong>Samples &amp; Demos</strong>: Watch<a href="https://aka.ms/agentloopdemos"> pre-recorded demos</a> showcasing both conversational and autonomous agent scenarios built with Agent Loop. You&rsquo;ll also get a preview of exciting features coming soon.</li>
</ul>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>If you’re leading a modernisation initiative, working through a BizTalk migration, or trying to unify integration and automation under a future-proof architecture, Agent Loop deserves your attention.</p>
<p>It’s one of those moments where <strong>what looks like a feature is actually a new paradigm</strong>. The integration space just got a whole lot smarter,and that changes everything.</p>
<h2 id="further-reading">Further Reading:</h2>
<p><a href="https://techcommunity.microsoft.com/blog/integrationsonazureblog/%F0%9F%93%A2announcing-agent-loop-build-ai-agents-in-azure-logic-apps-%F0%9F%A4%96/4415052">Official Announcement – Microsoft Tech Community</a></p>
]]></content:encoded></item><item><title>Logic App | Access Key Revocation and Regeneration</title><link>https://andrewilson.co.uk/post/2025/02/logic-app-standard-sas-revocation-and-regeneration/</link><pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/02/logic-app-standard-sas-revocation-and-regeneration/</guid><description>Overview In previous articles I have subtly referenced risks and best practices regarding HTTP triggered workflows and their use of Access Keys for security, such as:
Some Potential Risks:
If a Key is leaked, it can be used by anyone who obtains it to call your Logic App Workflow. If a Key has expired or been invalidated then services, applications, and or users who have not been provided a new key will cease to be able to invoke your workflow.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>In previous articles I have subtly referenced risks and best practices regarding HTTP triggered workflows and their use of Access Keys for security, such as:</p>
<ul>
<li>
<p>Some Potential Risks:</p>
<ul>
<li>If a <strong>Key is leaked</strong>, it can be used by anyone who obtains it to call your Logic App Workflow.</li>
<li>If a <strong>Key has expired or been invalidated</strong> then services, applications, and or users who have not been provided a new key will cease to be able to invoke your workflow.</li>
</ul>
</li>
<li>
<p>Some Access Key Best Practices to mitigate risks:</p>
<ul>
<li><strong>Have a revocation plan</strong> - Make sure that you are prepared to respond if a Key is compromised.</li>
<li><strong>Have a rotation plan</strong> - Look to replace the Key with new ones at regular intervals.</li>
</ul>
</li>
</ul>
<p>Given the risks and best practices described, I wanted to put together a solution whereby the regeneration and issue of the access keys could be automated. This allows for keys to be regenerated on a regular schedule provided they might need to comply with security policies. Further to this, regenerating the access keys means old ones are invalidated and thus protects you in the incident were a key is compromised.</p>
<h2 id="solution">Solution</h2>
<p>
  <img src="/images/posts/2025/02/accesskeyrevocationandregeneration.png" alt="Access Key Revocation and Regeneration">

</p>
<p>To automate the regeneration of the access keys, I am going to make use of the <a href="https://learn.microsoft.com/en-us/rest/api/appservice/workflows/regenerate-access-key?view=rest-appservice-2024-04-01&amp;tabs=HTTP">Azure Rest API</a>
and the following components:</p>
<ul>
<li><strong>Azure Key Vault</strong> - Used as secure storage for the workflow access keys.</li>
<li><strong>Identity and Access Management</strong> - Services, applications, and users will gain access to the access key secrets in Key Vault through Identity and role assignment at the secret level (Principal of Least Privilege).</li>
<li><strong>PowerShell Script</strong> - A script developed to invoke the Regenerate Access Key Azure Rest API.</li>
<li><strong>Bicep Template</strong> - A template developed to obtain and re-issue the workflow access keys to Key Vault.</li>
<li><strong>DevOps Pipeline</strong> - Using an automated pipeline to manually or on schedule invoke the PowerShell script and redeploy the Bicep template.</li>
</ul>
<blockquote>
<p>⚠️ <strong>Note</strong></p>
<ul>
<li>
<p>For automated roll out of access keys to services, applications, or users, their reference of the key vault secrets must not be directly tied to a version of the secret, rather always point to current.</p>
</li>
<li>
<p>Key vault reference values are cached in App Services and refetched every 24 hours.</p>
<ul>
<li>To refetch values immediately, the following options are available:
<ul>
<li>
<p>Manually through the Portal by using the &ldquo;Pull Reference Values&rdquo; under &ldquo;Environment Variables&rdquo;.</p>
</li>
<li>
<p>Update the App Config. Any configuration change to the app causes an app restart and an immediate refetch of all referenced secrets.</p>
</li>
<li>
<p><strong>Preferred</strong> - Pipeline powershell task after roll out that invokes a refetch.</p>
<p><code>az rest --method post --url https://management.azure.com/[Resurce ID]/config/configreferences/appsettings/refresh?api-version=2022-03-01 </code></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
<p><strong>Script to Regenerate a Workflow Access Key</strong></p>
<p>The following PowerShell script is used to Regenerate a specific Logic App Workflow Access Key. By regenerating a new key, the previous will also be invalidated.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-PowerShell" data-lang="PowerShell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$SubscriptionId</span> = <span style="color:#f1fa8c">&#39;{SubscriptionID}&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$ResourceGroupName</span> = <span style="color:#f1fa8c">&#39;{ResourceGroupName}&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$LogicAppName</span> = <span style="color:#f1fa8c">&#39;{Standard Logic App Name}&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$WorkflowName</span> = <span style="color:#f1fa8c">&#39;{Workflow Name}&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># Not required if automated and using as part of a DevOps pipeline.</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Connect-AzAccount</span> -Subscription <span style="color:#8be9fd;font-style:italic">$SubscriptionId</span> 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$accessToken</span> = <span style="color:#8be9fd;font-style:italic">Get-AzAccessToken</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$request</span> = @{
</span></span><span style="display:flex;"><span>    Method = <span style="color:#f1fa8c">&#39;POST&#39;</span>
</span></span><span style="display:flex;"><span>    Uri = <span style="color:#f1fa8c">&#34;https://management.azure.com/subscriptions/</span>$(<span style="color:#8be9fd;font-style:italic">$SubscriptionId</span>)<span style="color:#f1fa8c">/resourceGroups/</span>$(<span style="color:#8be9fd;font-style:italic">$ResourceGroupName</span>)<span style="color:#f1fa8c">/providers/Microsoft.Web/sites/</span>$(<span style="color:#8be9fd;font-style:italic">$LogicAppName</span>)<span style="color:#f1fa8c">/hostruntime/runtime/webhooks/workflow/api/management/workflows/</span>$(<span style="color:#8be9fd;font-style:italic">$WorkflowName</span>)<span style="color:#f1fa8c">/regenerateAccessKey?api-version=2024-04-01&#34;</span>
</span></span><span style="display:flex;"><span>    Body = @{
</span></span><span style="display:flex;"><span>        keyType = <span style="color:#f1fa8c">&#39;Primary&#39;</span>
</span></span><span style="display:flex;"><span>    } | <span style="color:#8be9fd;font-style:italic">ConvertTo-Json</span>
</span></span><span style="display:flex;"><span>    Headers = @{
</span></span><span style="display:flex;"><span>        Authorization = <span style="color:#f1fa8c">&#34;Bearer </span>$(<span style="color:#8be9fd;font-style:italic">$accessToken</span>.Token)<span style="color:#f1fa8c">&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f1fa8c">&#34;Content-Type&#34;</span> = <span style="color:#f1fa8c">&#34;application/json&#34;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Invoke-RestMethod</span> <span style="color:#8be9fd;font-style:italic">@request</span>
</span></span></code></pre></div><p><strong>Bicep Template to Obtain and Surface Workflow Access Keys to Key Vault</strong></p>
<p>The following Bicep template is used to obtain the workflow access key and create the secret in key vault (if already deployed, then a new version).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/********************************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">Workflow</span> <span style="color:#8be9fd;font-style:italic">Access</span> <span style="color:#8be9fd;font-style:italic">Keys</span> <span style="color:#8be9fd;font-style:italic">Role</span> <span style="color:#8be9fd;font-style:italic">Out</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">Author</span>: <span style="color:#8be9fd;font-style:italic">Andrew</span> <span style="color:#8be9fd;font-style:italic">Wilson</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">*********************************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** User Defined Types **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ************************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Object type used to identify a Workflow and Trigger&#39;</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">metadata</span>({
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">workflowName</span>: <span style="color:#f1fa8c">&#39;The name of the workflow within your Standard Logic App.&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">workflowTrigger</span>: <span style="color:#f1fa8c">&#39;The HTTP trigger name within the workflow&#39;</span>
</span></span><span style="display:flex;"><span>})
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">sealed</span>()
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">workflow</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">workflowName</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">workflowTrigger</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Array of Standard Logic App Workflows&#39;</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">minLength</span>(<span style="color:#8be9fd;font-style:italic">1</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">workflowArray</span> = <span style="color:#8be9fd;font-style:italic">workflow</span>[]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Logic App to place workflow(s) sig into KeyVault&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">LogicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Key Vault to place secrets into&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">keyVaultName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Array of Workflows to obtain sigs from.&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">workflows</span> <span style="color:#8be9fd;font-style:italic">workflowArray</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing Logic App&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicApp</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2024-04-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">LogicAppName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing Key Vault instance to store secrets&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">keyVault</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2023-07-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">keyVaultName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the Logic App workflow access key as a secret - Deployment principle requires RBAC permissions to do this&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">vaultLogicAppKey</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults/secrets@2023-07-01&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">workflow</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">workflows</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">keyVault</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceType</span>: <span style="color:#f1fa8c">&#39;LogicAppStandard&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">contentType</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowName</span>, <span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">queries</span>.<span style="color:#8be9fd;font-style:italic">sig</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span></code></pre></div><p>In the instance that the access key is compromised due to a user/component/service being compromised, then the action would be two fold:</p>
<ol>
<li>Revoke the user/component/service access to the secret in key vault.</li>
<li>Regenerate and issue a new access key.</li>
</ol>
<p>Hope this helps and have fun.</p>
]]></content:encoded></item><item><title>Logic App | Try-Catch Pattern, Nested Scopes, And Compensating Transaction Pattern</title><link>https://andrewilson.co.uk/post/2025/01/logic-app-nested-scopes-and-compensating-transaction-pattern/</link><pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/01/logic-app-nested-scopes-and-compensating-transaction-pattern/</guid><description>The Try-Catch Pattern Following the idea of defensive programming or as I like to call it for Logic Apps (being low code): defensive processing, it is considered good practice to wrap your workflows in a try-catch pattern to handle the unexpected. The pattern makes use of a mixture of Run After conditions and the Scope block.
Run After Conditions | used to define the execution order based on the state of the previous action or scope Scope Block | provides the ability to group a series of actions.</description><content:encoded><![CDATA[<h2 id="the-try-catch-pattern">The Try-Catch Pattern</h2>
<p>Following the idea of defensive programming or as I like to call it for Logic Apps (<em>being low code</em>): <em>defensive processing</em>, it is considered good practice to wrap your workflows in a try-catch pattern to handle the unexpected. The pattern makes use of a mixture of Run After conditions and the Scope block.</p>
<ul>
<li><strong>Run After Conditions</strong> | <em>used to define the execution order based on the state of the previous action or scope</em></li>
<li><strong>Scope Block</strong> | <em>provides the ability to group a series of actions. If any action within the scope fails, the whole scope will fail (unless handled via other means)</em></li>
</ul>
<p>By placing your actions within a &ldquo;try&rdquo; scope with the assumption that each action will run after the success of the previous, if there is an action failure, the scope will fail also.</p>
<p>Using the Run After conditions on either a proceeding action or scope, you can &ldquo;catch&rdquo; any <code>has failed, is skipped, or has timed out</code> states from the &ldquo;try&rdquo; scope. In effect this makes up your simple try-catch block.</p>
<p><strong>Example</strong></p>
<p>
  <img src="/images/posts/2025/01/trycatch.png" alt="Simple Try-Catch">

</p>
<p>It is possible once you have entered into the catch scope to retrieve details of the resulting try scope by using the expression <code>@result('Scope-Try')</code>. The expression will provide an array of all the actions and their details including if they were successful or failed with a given exception message.</p>
<p>This is really useful but how does it hold up when nested you may ask&hellip;</p>
<h2 id="nested-try-catch-scopes">Nested Try-Catch Scopes</h2>
<p>Nested try-catch scopes can be handy when you have smaller segments of the larger workflow that can be tried as a group; preventing unnecessary complexity in handling issues and failures later in the workflow or as a whole.</p>
<p><strong>Example</strong>

  <img src="/images/posts/2025/01/nestedtrycatch.png" alt="Nested Try-Catch">

</p>
<p>This example still has its overarching try-catch due to the possibility of either sub catches containing actions that can fail, be skipped, or time out.</p>
<p>Nesting try-catch scopes offers the same capabilities as un-nested. However, there are caveats to remember when nesting in this way:</p>
<ul>
<li><strong>Complexity</strong> | readability and maintainability is always paramount when designing workflows.
<ul>
<li>Make sure to appropriately and consistently title actions and scopes.</li>
<li><a href="https://blog.sandro-pereira.com/2022/02/28/logic-app-best-practices-tips-and-tricks-3-add-comments/">Add comments</a>, especially on scopes as this can aid in describing the processing and functionality that sits within.</li>
</ul>
</li>
<li><strong>Intentional flow review</strong> | given the added complexity through nesting and run after configurations, thorough review and testing of processing flow should be conducted.
<ul>
<li>A method of doing this is to <a href="https://learn.microsoft.com/en-us/azure/logic-apps/test-logic-apps-mock-data-static-results?tabs=standard">test/mock outputs on actions</a>.</li>
</ul>
</li>
<li><strong>Handles the unexpected</strong> | as with the single try-catch, this is not a method in handling non-&ldquo;happy path&rdquo; results from processing, rather the unexpected failures, skips, or timeouts.</li>
</ul>
<p>As referred to in the last point in the caveats, if the try-catch both singular and nested aids in the unexpected, how can I add to this pattern to help with handling &ldquo;un-happy&rdquo; paths. This cues the Compensating Transaction pattern&hellip;</p>
<h2 id="compensating-transaction-pattern">Compensating Transaction Pattern</h2>
<p>The <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction">Compensating Transaction pattern</a> is useful when you are trying to attain an eventually consistent operation that consists of multiple steps. If one or more of the steps fail, this pattern can be used to undo the steps performed.</p>
<p>One of the most basic forms of compensation or undo is to notify for manual remediation. This is the scenario that I will use as an example.</p>
<p><strong>Scenario</strong></p>
<p>Let&rsquo;s assume that a taxi booking process needs to be automated as a logic app workflow. There are four steps involved in this process:</p>
<ol>
<li>Check to see if the customer is an existing customer, and if so obtain an enriched form of their details from our system.</li>
<li>Check if the time slot is available with a local driver.</li>
<li>If the time slot is available, book the time slot with the local driver.</li>
<li>Send a notification to the customer regarding details of the booked time slot and their driver.</li>
</ol>
<p>If there are any problems with processing these four steps, a notification will need to be sent for manual remediation. This must include:</p>
<ul>
<li>The steps that were successful</li>
<li>The step that was not able to be performed</li>
<li>The steps that were skipped after the one that failed to be processed</li>
</ul>
<p>In this scenario and example, the use of the try-catch pattern (nested) is used to catch the unexpected problems in processing. The addition of the Condition action allows us to perform process validation (<em>the action may have succeeded, but did it return the result we desired?</em>). The example further uses the Condition action to validate if the workflow should continue onto the next processing step given the previous may have failed.</p>
<p><strong>Example</strong>

  <img src="/images/posts/2025/01/CompensatingTransactionPattern.png" alt="Compensating Transaction pattern">

</p>
<blockquote>
<p>The example shows a subset of the steps implemented as the rest are a repeat demonstration.</p>
</blockquote>
<p>Given this workflow design, we can process faults in a controlled manner both expected and unexpected. We can control which processing steps should be performed given an error may have occurred, and we can through our transaction log give a full account allowing for full remediation.</p>
<p>There are caveats to remember when implementing this pattern and example:</p>
<ul>
<li><strong>Complexity</strong> | readability and maintainability is always paramount when designing workflows.
<ul>
<li>Make sure to appropriately and consistently title actions and scopes.</li>
<li><a href="https://blog.sandro-pereira.com/2022/02/28/logic-app-best-practices-tips-and-tricks-3-add-comments/">Add comments</a>, especially on scopes as this can aid in describing the processing and functionality that sits within.</li>
</ul>
</li>
<li><strong>Intentional flow review</strong> | given the added complexity through nesting, conditions, and run after configurations, thorough review and testing of processing flow should be conducted.
<ul>
<li>A method of doing this is to <a href="https://learn.microsoft.com/en-us/azure/logic-apps/test-logic-apps-mock-data-static-results?tabs=standard">test/mock outputs on actions</a>.</li>
</ul>
</li>
</ul>
<p>Hope this helps and have fun.</p>
]]></content:encoded></item><item><title>Key Vault Reference | Logic and Function Apps using User-Assigned Managed Identity</title><link>https://andrewilson.co.uk/post/2025/01/logic-and-function-app-keyvault-access-with-user-assigned-identity/</link><pubDate>Mon, 06 Jan 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/01/logic-and-function-app-keyvault-access-with-user-assigned-identity/</guid><description>Overview Prior to the Christmas break I was involved in writing some integrations that used a mixture of Logic Apps Standard and Function Apps. It was agreed as part of the architecture that user-assigned identities would be the best fit. As part of the implementation, I observed that the differences in configuration setup between system-assigned and user-assigned wasn&amp;rsquo;t widely understood. This article aims to show a brief run through of both.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>Prior to the Christmas break I was involved in writing some integrations that used a mixture of Logic Apps Standard and Function Apps. It was agreed as part of the architecture that user-assigned identities would be the best fit. As part of the implementation, I observed that the differences in configuration setup between system-assigned and user-assigned wasn&rsquo;t widely understood. This article aims to show a brief run through of both.</p>
<h2 id="setup-and-difference-with-system-assigned">Setup and Difference with System-Assigned</h2>
<p><strong>System-Assigned</strong></p>
<p>The general process when using a <em>System-Assigned identity</em> is as follows:</p>
<ol>
<li>
<p>Create a Key Vault Instance.</p>
</li>
<li>
<p>Create secrets required by the application.</p>
</li>
<li>
<p>Create the app resource (Logic App / Function App)</p>
<ul>
<li>
<p>As part of the configuration, specify the identity as System Assigned.</p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli#source-app-settings-from-key-vault">Reference the key vault secret(s)</a> in your App Settings.</p>
</li>
</ul>
</li>
<li>
<p>Authorise the applications identity read access to key vault or <a href="/post/2023/11/rbac-key-vault-specific-secret/">specifically the key vaults secret</a>.</p>
</li>
</ol>
<p>The main points with System-Assigned setup is:</p>
<ul>
<li>The identity is tied to the created app resource and its life-cycle</li>
<li>The resource cannot reference key vault secrets at the point of creation
<ul>
<li>Authorisation to read the key vault secrets has not occurred at this point</li>
</ul>
</li>
<li>The identity cannot be associated with other resources</li>
</ul>
<p><strong>User-Assigned</strong></p>
<p>The general process when using a <em>User-Assigned identity</em> is as follows:</p>
<ol>
<li>
<p>Create a Key Vault instance</p>
</li>
<li>
<p>Create secrets required by the application(s)</p>
</li>
<li>
<p>Create the user-assigned identity</p>
</li>
<li>
<p>Authorise the user-assigned identity read access to key vault or <a href="/post/2023/11/rbac-key-vault-specific-secret/">specifically the key vaults secret</a>.</p>
</li>
<li>
<p>Create the app resource (Logic App / Function App)</p>
<p>As part of the resource configuration</p>
<ul>
<li>
<p>Specify the identity as user-assigned and reference the created identity in step 3</p>
</li>
<li>
<p>Specify the identity to be used for key vault reference operations by setting the <code>keyVaultReferenceIdentity</code> property to the resource ID of the user-assigned identity</p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli#source-app-settings-from-key-vault">Reference the key vault secret(s)</a> in your App Settings.</p>
</li>
</ul>
</li>
</ol>
<p>The main points with User-Assigned setup is:</p>
<ul>
<li>The identity is managed outside the context of a resource and its life-cycle</li>
<li>A resource that uses the identity can read secrets from keyvault at the point of creation
<ul>
<li>Given that the authorisation has occurred prior to the resource creation.</li>
</ul>
</li>
<li>The identity can be associated with on or more resources</li>
</ul>
<p>⚠️ <strong>Note</strong> One of the most common gotchas [user-assigned] is missing or forgetting to specify the identity to be used for key vault reference operations (<code>keyVaultReferenceIdentity</code> property - Step 5).</p>
<p>Hope this helps and have fun.</p>
]]></content:encoded></item><item><title>Easy Auth | Standard Logic App with Azure API Management</title><link>https://andrewilson.co.uk/post/2024/02/standard-logic-app-easy-auth-apim/</link><pubDate>Tue, 26 Nov 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/02/standard-logic-app-easy-auth-apim/</guid><description>Overview The recent work that I have been doing with Standard Logic Apps and linking them as backends to Azure API Management has relied on the use of the Logic App Workflow SAS key for security. This is a valid authentication approach, but there are risks that you need to be aware of as well as best practices that you need to be abiding by. Such as:
Some Potential Risks:</description><content:encoded><![CDATA[<p><a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend">
  <img src="https://img.shields.io/badge/Repo-Easy%20Auth%20With%20Standard%20Logic%20App%20And%20APIM-blue?logo=github&amp;style=for-the-badge" alt="GitHub Repository">

</a></p>
<h2 id="overview">Overview</h2>
<p>The recent work that I have been doing with Standard Logic Apps and linking them as backends to Azure API Management has relied on the use of the Logic App Workflow SAS key for security. This is a valid authentication approach, but there are risks that you need to be aware of as well as <a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview#best-practices-when-using-sas">best practices</a> that you need to be abiding by. Such as:</p>
<ul>
<li>
<p>Some Potential Risks:</p>
<ul>
<li>If a <strong>SAS is leaked</strong>, it can be used by anyone who obtains it to call your Logic App Workflow.</li>
<li>If a <strong>SAS expires</strong> and the API Management API has not been updated to make use of the updated SAS, then the integration functionality will be hindered.</li>
</ul>
</li>
<li>
<p>Some SAS Best Practices to mitigate risks:</p>
<ul>
<li><strong>Always use HTTPS</strong> - If a SAS is passed over HTTP and intercepted, an attacker can perform a man-in-the-middle attack and read the SAS.</li>
<li><strong>Have a revocation plan</strong> - Make sure that you are prepared to respond if a SAS is compromised.</li>
<li><strong>Have a rotation plan</strong> - Look to replace the SAS with new ones at regular intervals and include shorter time intervals for the expiration period.</li>
</ul>
</li>
</ul>
<p>There are other features that can be used to further restrict access to your Logic App, for instance adding <a href="https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-securing-a-logic-app?tabs=azure-portal#standard-workflows-1">IP Address Restrictions</a> to limit traffic to only your API Management Instance.</p>
<p>But what if you require further governance whereby the Logic App requires a valid Entra ID bearer token in order to be invoked. To implement this we are going to make use of Easy Auth.</p>
<h2 id="easy-auth">Easy Auth</h2>
<p><a href="https://learn.microsoft.com/en-us/azure/app-service/overview-authentication-authorization">Easy Auth</a> is a built-in authentication and authorisation capability provided by Azure App Services and Azure Functions. Easy Auth makes use of federated identity whereby a third-party identity provider manages the user identities and authentication flow for you. Fortunately for us, Standard Logic Apps have the same foundations as Azure Functions and therefore Easy Auth is also extended to Logic Apps Standard.</p>
<p>
  <img src="/images/posts/2024/02/EasyAuth.png" alt="Eay Auth">

</p>
<p>Easy Auth is a platform feature running on the same virtual machine as your application. Once enabled, any incoming HTTP requests will pass through this feature prior to being handled by your application. Easy Auth runs separately from your application code and can be configured using ARM settings or using a configuration file.</p>
<h2 id="using-easy-auth-and-linking-to-api-management">Using Easy Auth and Linking to API Management</h2>
<p>As mentioned above, I would like to use Easy Auth to protect my HTTP Triggered Azure Logic App (Standard) workflows, but more importantly, I would like Azure API Management to be the only identity that can be used to make requests to my workflows as shown in the diagram below:</p>
<p>
  <img src="/images/posts/2024/02/EasyAuthAPIM.png" alt="Eay Auth">

</p>
<blockquote>
<p><strong>Note:</strong></p>
<p>As we will be invoking the Logic App HTTP triggered workflows with Easy Auth, we no longer need to specify the following parameters in the request:</p>
<ul>
<li>sp: The permissions; generally &lsquo;read&rsquo; or &lsquo;write&rsquo;</li>
<li>sv: The version number of the query parameters</li>
<li>sig: Shared-Access-Signature</li>
</ul>
<p>Furthermore, I have opted for Infrastructure as Code (IaC) as my method of implementation, specifically Bicep.</p>
</blockquote>
<p>For setup, we will need to conduct the following four steps:</p>
<ol>
<li>
<p>Configure the Logic App to <a href="https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad?tabs=workforce-configuration">Use Microsoft Entra sign-in</a>.</p>
<p>Working through the Microsoft instructions in the link above, you will require as minimum the following when setting up the Logic App Application Registration:</p>
<ul>
<li>
<p>Select the supported account type. (<em>I&rsquo;m using Current tenant - single tenant</em>)</p>
</li>
<li>
<p>Setup a Redirect URI for your Logic App:</p>
<p>Select Web for platform and set the URI to <code>&lt;app-url&gt;/.auth/login/aad/callback</code>. For example, <a href="https://contoso.azurewebsites.net/.auth/login/aad/callback">https://contoso.azurewebsites.net/.auth/login/aad/callback</a>.</p>
</li>
<li>
<p>Make not of the Application (client) ID.</p>
</li>
<li>
<p>Create a Client Secret and store this securely (<em>I&rsquo;m using Azure  DevOps Secure Library Variables as part of a deployment</em>).</p>
<p><em>This is a secret value that the application uses to prove its identity when requesting a token. This value is saved in your app&rsquo;s configuration as a slot-sticky application setting named <code>MICROSOFT_PROVIDER_AUTHENTICATION_SECRET</code>. If the client secret isn&rsquo;t set, sign-in operations from the service use the OAuth 2.0 implicit grant flow, which isn&rsquo;t recommended.</em></p>
</li>
<li>
<p>Expose an API &gt; Add &gt; Save. This value uniquely identifies the application when it&rsquo;s used as a resource, allowing tokens to be requested that grant access. It&rsquo;s used as a prefix for scopes you create.</p>
<p>I am using a single-tenant app and therefore using the default value. Appears as such <code>api://&lt;application-client-id&gt;</code></p>
</li>
<li>
<p>Add the <code>user_impersonation</code> scope to your App Registration allowing <code>Admins and users</code> to consent.</p>
</li>
</ul>
</li>
<li>
<p>Make sure that API Management has been setup with Managed Identity. I am using System Assigned.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deployment of the APIM instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">apimInstanceDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">identity</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;SystemAssigned&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></li>
<li>
<p>Store the App Registration Secret in KeyVault and Reference in your Logic App Settings to allow the Logic App to prove its identity.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">secure</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The client secret for the Easy Auth App Registration&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">applicationEasyAuthClientSecret</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Role Definition Id for the Key Vault Secrets User role&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefId</span> = <span style="color:#f1fa8c">&#39;4633458b-17de-408a-b874-0445c86b69e6&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the Application Easy Auth App Registration Secret to Keyvault&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">vaultLogicAppRegSecret</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults/secrets@2023-07-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-EasyAuth-Secret&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">applicationKeyVaultDeploy</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">contentType</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">applicationEasyAuthClientSecret</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the Application Standard Logic App&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppStandardDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2024-04-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">identity</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;SystemAssigned&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">config</span> <span style="color:#f1fa8c">&#39;config@2024-04-01&#39;</span> = {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;appsettings&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>      ...
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">MICROSOFT_PROVIDER_AUTHENTICATION_SECRET</span>: <span style="color:#f1fa8c">&#39;@Microsoft.KeyVault(VaultName=</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationKeyVaultDeploy</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">;SecretName=</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">vaultLogicAppRegSecret</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">)&#39;</span>
</span></span><span style="display:flex;"><span>      ...
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the RBAC for the Logic App to Read the Secret from Key Vault&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppRBACWithKV</span> <span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleAssignments@2022-04-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#50fa7b">guid</span>(<span style="color:#8be9fd;font-style:italic">applicationKeyVaultDeploy</span>.<span style="color:#8be9fd;font-style:italic">id</span>, <span style="color:#8be9fd;font-style:italic">applicationLogicAppStandardDeploy</span>.<span style="color:#8be9fd;font-style:italic">id</span>, <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefId</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">scope</span>: <span style="color:#8be9fd;font-style:italic">vaultLogicAppRegSecret</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalId</span>: <span style="color:#8be9fd;font-style:italic">applicationLogicAppStandardDeploy</span>.<span style="color:#8be9fd;font-style:italic">identity</span>.<span style="color:#8be9fd;font-style:italic">principalId</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">roleDefinitionId</span>: <span style="color:#50fa7b">subscriptionResourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleDefinitions&#39;</span>, <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefId</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalType</span>: <span style="color:#f1fa8c">&#39;ServicePrincipal&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></li>
<li>
<p>Enable Easy Auth on the Standard Logic App using <a href="https://learn.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-authsettingsv2?pivots=deployment-language-bicep#siteauthsettingsv2properties">ARM/Bicep Template AuthSettingsV2</a> or <a href="https://github.com/Azure/azure-rest-api-specs/blob/main/specification/web/resource-manager/Microsoft.Web/stable/2021-02-01/WebApps.json#L1197">ARM REST API</a>. I am using a Bicep Template.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Setup the Easy Auth config settings for the Standard Logic App&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationAuthSettings</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites/config@2023-01-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;authsettingsV2&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">applicationLogicAppStandardDeploy</span> <span style="color:#6272a4">// Existing Standard Logic App for Easy Auth to be enabled</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">globalValidation</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">requireAuthentication</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">unauthenticatedClientAction</span>: <span style="color:#f1fa8c">&#39;AllowAnonymous&#39;</span> <span style="color:#6272a4">// Do not change: See note below.</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">httpSettings</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">requireHttps</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">routes</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">apiPrefix</span>: <span style="color:#f1fa8c">&#39;/.auth&#39;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">forwardProxy</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">convention</span>: <span style="color:#f1fa8c">&#39;NoProxy&#39;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">identityProviders</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">azureActiveDirectory</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">enabled</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">registration</span>: {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">openIdIssuer</span>: <span style="color:#50fa7b">uri</span>(<span style="color:#f1fa8c">&#39;https://sts.windows.net/&#39;</span>, <span style="color:#50fa7b">tenant</span>().<span style="color:#8be9fd;font-style:italic">tenantId</span>)
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">clientId</span>: <span style="color:#8be9fd;font-style:italic">logicAppEasyAuthClientId</span>
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">clientSecretSettingName</span>: <span style="color:#f1fa8c">&#39;MICROSOFT_PROVIDER_AUTHENTICATION_SECRET&#39;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">validation</span>: {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">allowedAudiences</span>: <span style="color:#50fa7b">environment</span>().<span style="color:#8be9fd;font-style:italic">authentication</span>.<span style="color:#8be9fd;font-style:italic">audiences</span> <span style="color:#6272a4">// Azure Management Plane [management.core.windows.net and management.azure.com]</span>
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">defaultAuthorizationPolicy</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd;font-style:italic">allowedPrincipals</span>: {
</span></span><span style="display:flex;"><span>              <span style="color:#8be9fd;font-style:italic">identities</span>: [
</span></span><span style="display:flex;"><span>                <span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">identity</span>.<span style="color:#8be9fd;font-style:italic">principalId</span> <span style="color:#6272a4">// APIM System Assigned Principal Id</span>
</span></span><span style="display:flex;"><span>              ]
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>          }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">platform</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">enabled</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">runtimeVersion</span>: <span style="color:#f1fa8c">&#39;~1&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>Note:</p>
<p><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>EasyAuth is managed by AppService, and for an incoming request, it is a hop that comes before LA Runtime. When EasyAuth is enabled for a Logicapp standard, all incoming requests are validated against the policies in your V2 Auth settings.</p>
<p>If you have “unauthenticatedClientAction”: “Return401” and when the request fails with EasyAuth, those requests are not routed to LA runtime and will fail with 401 from AppService. Therefore, you will also observe broken portal experience with Return401. When you set it to “AllowAnonymous”, all calls (failed and successful) will be routed to the LA runtime. The LA runtime will know if the request failed with EasyAuth or was successful and will process the request accordingly. For example, to get run histories, we authenticate it on SAS specific to that run generated based on the Logic Apps access keys. LA runtime will know that this request failed with EasyAuth but it will be processed successfully as it has valid SAS. The underlying AppService platform will have no knowledge of validating other auth like SAS.</p>
</blockquote>
</li>
<li>
<p>Configure API Management to obtain a valid Bearer token and add it to the request Authorization Header. Implemented through <a href="https://learn.microsoft.com/en-us/azure/api-management/authentication-managed-identity-policy">APIM Policy</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-XML" data-lang="XML"><span style="display:flex;"><span><span style="color:#6272a4">&lt;!-- API ALL OPERATIONS SCOPE --&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;policies&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;inbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6272a4">&lt;!-- Uses System Assigned Managed Identity of the APIM Instance --&gt;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#ff79c6">&lt;authentication-managed-identity</span> <span style="color:#50fa7b">resource=</span><span style="color:#f1fa8c">&#34;https://management.azure.com/&#34;</span> <span style="color:#50fa7b">output-token-variable-name=</span><span style="color:#f1fa8c">&#34;msi-access-token&#34;</span> <span style="color:#50fa7b">ignore-error=</span><span style="color:#f1fa8c">&#34;false&#34;</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#ff79c6">&lt;set-header</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;Authorization&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;override&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span> 	         <span style="color:#ff79c6">&lt;value&gt;</span>@(&#34;Bearer &#34; + (string)context.Variables[&#34;msi-access-token&#34;])<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#ff79c6">&lt;/set-header&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/inbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;outbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/outbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;on-error&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/on-error&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;/policies&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>Configure API Management to Append the Logic App Workflow api-version query parameter to the request. Implemented through <a href="https://learn.microsoft.com/en-us/azure/api-management/set-query-parameter-policy">APIM Policy</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-XML" data-lang="XML"><span style="display:flex;"><span><span style="color:#6272a4">&lt;!-- API OPERATION SCOPE --&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;policies&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;inbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;rewrite-uri</span> <span style="color:#50fa7b">template=</span><span style="color:#f1fa8c">&#34;__uri__&#34;</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-query-parameter</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;api-version&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;append&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&lt;value&gt;</span>__api-version__<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;/set-query-parameter&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/inbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;outbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/outbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;on-error&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/on-error&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;/policies&gt;</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="summary">Summary</h2>
<p>In short, we have defined our three A&rsquo;s (Access, Authentication, Authorisation) providing further governance on our Standard Logic App and API Management through the use of Easy Auth. To see my worked example, have a look at my <a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend">GitHub repository</a> along with a README that explains how to get started.</p>
<p>Hope this helps and have fun.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Trigger workflows in Standard logic apps with Easy Auth | <a href="https://techcommunity.microsoft.com/t5/azure-integration-services-blog/trigger-workflows-in-standard-logic-apps-with-easy-auth/ba-p/3207378">https://techcommunity.microsoft.com/t5/azure-integration-services-blog/trigger-workflows-in-standard-logic-apps-with-easy-auth/ba-p/3207378</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Microsoft.Web/Connections | Access Policies</title><link>https://andrewilson.co.uk/post/2024/04/api-connection-access-policies/</link><pubDate>Wed, 10 Apr 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/04/api-connection-access-policies/</guid><description>Problem Space I have recently been adding email alerting to some Logic App Standard workflows as part of the error handling flow. In doing so I made use of an existing Office 365 Outlook Connector in the Azure Subscription; the connector is not built in for Standard Logic Apps but is rather part of the Managed Api Connections.
Managed Api Connectors require more than just the connection details to be detailed in the Logic Apps connections.</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>I have recently been adding email alerting to some Logic App Standard workflows as part of the error handling flow. In doing so I made use of an existing Office 365 Outlook Connector in the Azure Subscription; the connector is not built in for Standard Logic Apps but is rather part of the Managed Api Connections.</p>
<p>Managed Api Connectors require more than just the connection details to be detailed in the Logic Apps connections.json configuration as shown below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;managedApiConnections&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;office365&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;api&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;id&#34;</span>: <span style="color:#f1fa8c">&#34;@appsetting(&#39;office365_apiId&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>      },
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;authentication&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;ManagedServiceIdentity&#34;</span>
</span></span><span style="display:flex;"><span>      },
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;connection&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;id&#34;</span>: <span style="color:#f1fa8c">&#34;@appsetting(&#39;office365_connectionId&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>      },
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;connectionRuntimeUrl&#34;</span>: <span style="color:#f1fa8c">&#34;@appsetting(&#39;office365_connectionRuntimeUrl&#39;)&#34;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The Managed API Connector also requires that the Logic App has been granted access to the Connector through the use of Access Policies. This can be configured through the Azure Portal or through infrastructure deployments, in my case I have opted for infrastructure deployments with the use of Bicep templates.</p>
<p>It was at this point that I realised that the Access Policy resource which is a child resource to <code>Microsoft.Web/connections</code> has not been <a href="https://learn.microsoft.com/en-us/azure/templates/microsoft.web/connections?tabs=json&amp;pivots=deployment-language-bicep">documented</a>, obtainable through an Azure Portal template export, or through the Resource Explorer.</p>
<h2 id="solution">Solution</h2>
<p>From digging around the <a href="https://learn.microsoft.com/en-us/azure/logic-apps/azure-arc-enabled-logic-apps-create-deploy-workflows?tabs=azure-cli#arm-template">Access Policy resource</a> has the following ARM Template Schema:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Microsoft.Web/connections/accessPolicies&#34;</span>,
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;apiVersion&#34;</span>: <span style="color:#f1fa8c">&#34;2016-06-01&#34;</span>,
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;[concat(&#39;&lt;connection-name&gt;&#39;),&#39;/&#39;,&#39;&lt;object-ID&gt;&#39;)]&#34;</span>,
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;location&#34;</span>: <span style="color:#f1fa8c">&#34;&lt;location&gt;&#34;</span>,
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;dependsOn&#34;</span>: [
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#34;[resourceId(&#39;Microsoft.Web/connections&#39;, parameters(&#39;connection_name&#39;))]&#34;</span>
</span></span><span style="display:flex;"><span>   ],
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&#34;properties&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;principal&#34;</span>: {
</span></span><span style="display:flex;"><span>         <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;ActiveDirectory&#34;</span>,
</span></span><span style="display:flex;"><span>         <span style="color:#ff79c6">&#34;identity&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;objectId&#34;</span>: <span style="color:#f1fa8c">&#34;&lt;object-ID&gt;&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;tenantId&#34;</span>: <span style="color:#f1fa8c">&#34;&lt;tenant-ID&gt;&#34;</span>
</span></span><span style="display:flex;"><span>         }
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>   }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p><strong>Resource Properties</strong></p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&lt;connection-name&gt;</code></td>
<td>The name for your managed API connection, for example office365</td>
</tr>
<tr>
<td><code>&lt;object-ID&gt;</code></td>
<td>The object ID for your Microsoft Entra identity, for example the system assigned managed identity of the logic app</td>
</tr>
<tr>
<td><code>&lt;tenant-ID&gt;</code></td>
<td>The tenant ID for your Microsoft Entra identity</td>
</tr>
</tbody>
</table>
</blockquote>
<p>In Bicep this takes on the following form:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the access policy for the Logic App to access the managed Api Connection &#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">managedAPIConnectionAccessPolicy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/connections/accessPolicies@2016-06-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span> <span style="color:#6272a4">// Using the Logic App Name for readability</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">managedAPIConnector</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">Location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principal</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;ActiveDirectory&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">identity</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">tenantId</span>: <span style="color:#50fa7b">subscription</span>().<span style="color:#8be9fd;font-style:italic">tenantId</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">objectId</span>: <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">identity</span>.<span style="color:#8be9fd;font-style:italic">principalId</span> <span style="color:#6272a4">// Using the System Assigned Managed Identity of the Logic App</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p><strong>Note</strong></p>
<p>The Bicep tooling will give you the following warning but will not hinder in both the transpilation into ARM or in the deployment of the resource:</p>
<p><code>Resource type &quot;Microsoft.Web/connections/accessPolicies@2016-06-01&quot; does not have types available.</code></p>
</blockquote>
]]></content:encoded></item><item><title>Azure API Management | Logic App (Standard) Backend Using a Swagger Definition</title><link>https://andrewilson.co.uk/post/2024/02/standard-logic-app-apim-backend-swagger/</link><pubDate>Thu, 01 Feb 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/02/standard-logic-app-apim-backend-swagger/</guid><description>Overview After setting up a Logic App (Standard) Backend in Azure API Management (APIM) in my last post, I wanted to try and see if I could create a Swagger definition from a Standard Logic App which could then be used to simplify the API authoring process in APIM. This post shows my methods of doing so.
If you haven&amp;rsquo;t already I would recommend reading my previous post as this one will be working off of the building blocks of the last.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p><a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend">
  <img src="https://img.shields.io/badge/Repo-Standard--Logic--App--APIM--Backend-blue?logo=github&amp;style=for-the-badge" alt="GitHub Repository">

</a></p>
<p>After setting up a <a href="/post/2024/01/standard-logic-app-apim-backend/">Logic App (Standard) Backend in Azure API Management (APIM)</a> in my last post, I wanted to try and see if I could create a Swagger definition from a Standard Logic App which could then be used to simplify the API authoring process in APIM. This post shows my methods of doing so.</p>
<blockquote>
<p>If you haven&rsquo;t already I would recommend reading my previous <a href="/post/2024/01/standard-logic-app-apim-backend/"><strong>post</strong></a> as this one will be working off of the building blocks of the last.</p>
</blockquote>
<p>As with my previous post, the high-level architecture has not changed and neither has the overall aim as shown below.

  <img src="/images/posts/2024/01/Overview.png" alt="Overview">

</p>
<p>The design aims to abstract the backend from the api operations, i.e. the backend points to the Logic App and the individual operations point to the respective workflows. The design also specifies granular access to the workflow Shared-Access-Signature (sig) held in the applications specific KeyVault (<em>to see further details on this, see <a href="/post/2023/11/rbac-key-vault-specific-secret/">Azure RBAC Key Vault | Role Assignment for Specific Secret</a></em>). Furthermore, the additional required parameters that are necessary to call a workflow have been implemented through APIM policies to remove the need for callers to understand backend implementation.</p>
<p>I have opted for Infrastructure as Code (IaC) as my method of implementation, specifically Bicep. I have broken down the implementation of the diagram above into two parts, Application Deployment, and API Deployment.</p>
<h3 id="problem-space">Problem Space</h3>
<p>Having come across the ARM REST API to generate a Swagger definition for a <a href="https://learn.microsoft.com/en-us/rest/api/logic/workflows/list-swagger?view=rest-logic-2016-06-01&amp;tabs=HTTP">consumption Logic App</a>, I went searching for the same functionality for Standard Logic Apps. Given a short time searching, I found the <a href="https://learn.microsoft.com/en-us/rest/api/appservice/workflows?view=rest-appservice-2022-03-01">REST APIs</a> situated under App Services with the Swagger generation API no where to be seen.</p>
<p>But would this stop me&hellip; No.</p>
<p>Knowing that I can retrieve a detailed definition of a Standard Logic App through the Azure Resource Manager, I started looking at methods of stripping out the detail that I would need to construct a Swagger Definition.</p>
<p>My chosen method to do this is through a PowerShell script using both ARM REST APIs and the az cli. This choice will allow me to run the script as non-interactive in future DevOps CI/CD pipelines.</p>
<h2 id="application-deployment">Application Deployment</h2>
<p>Our first step toward generating the Swagger definition for our Logic App is to deploy an instance of our Logic App to Azure. The process has not changed from the last post apart from the addition of step 4. As shown in the diagram below, step 4 is where we will use the PowerShell script that I have written to extract the core details of our Logic App and workflows to construct a Swagger Definition.</p>
<p>
  <img src="/images/posts/2024/01/Application-Deployment-Swagger.png" alt="Application Deployment">

</p>
<p>The script has been designed to take a ControlFile.json that you update with one or more HTTP triggered workflows and API details to assist in the retrieval and generation of the definition. There is an example control file in my <a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend/blob/main/SwaggerGenerator/ControlFile.json">GitHub repository</a>.</p>
<p>The <a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend/blob/main/SwaggerGenerator/SpecCreator.ps1">SpecCreator.ps1</a> takes the following parameters:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-PowerShell" data-lang="PowerShell"><span style="display:flex;"><span><span style="color:#6272a4">&lt;#
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .</span><span style="color:#f1fa8c">SYNOPSIS</span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">	Creates a Swagger definition for a select Standard Logic App and its specified Workflows.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .</span><span style="color:#f1fa8c">DESCRIPTION</span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">	Uses a series of parameters to derive the Standard Logic App and the Workflows to include in the base Swagger definition template. 
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER SubscriptionId
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    The ID of the Subscription that the Standard Logic App is Hosted in.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER ResourceGroupName
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    The Resource Group Name that the Standard Logic App is Hosted in.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER LogicAppName
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    The Name of the Standard Logic App to use for the Swagger Definition.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER APITitle
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    API Name used to define the set of operations.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER APIDescription
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    Description of the API and its set of operations.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER APIVersion
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    None-Mandatory - Specified version of the API. Default is 1.0.0.0
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER SpecTemplatePath
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    None-Mandatory - Base path to the swagger definition template, doesn&#39;t include the name of the file.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    .PARAMETER ControlFile
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    None-Mandatory - Base path to the json control file used to identify the set of Workflows to extract as operations for the swagger definition, doesn&#39;t include the name of the file.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">	.PARAMETER InteractiveMode
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">	If specified will request the user to interactively login into Azure for az tooling.
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4">    #&gt;</span>
</span></span></code></pre></div><p>The script then uses a series of ARM REST API calls to obtain the following detail:</p>
<ul>
<li>Request Schema (if one is provided).</li>
<li>Workflow Definition.</li>
</ul>
<p>Using the Workflow Definition, we can interrogate the Workflow Trigger for details such as:</p>
<ul>
<li>HTTP Method.</li>
<li>Relative Paths.
<ul>
<li><strong>Note:</strong> Path Parameters are expected to be wrapped with curly braces, for example:
<ul>
<li>/users/{id}</li>
<li>/cars/{carId}/drivers/{driverId}</li>
<li>cars/{carId}/drivers/{driverId}</li>
<li>/{carId}/{driverId}</li>
<li>{carId}</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Once all the Workflow details have been obtained, the script uses an imported tokenised Swagger Definition to generate the respective Definition for your Standard Logic App and Workflows.</p>
<h2 id="api-deployment">API Deployment</h2>
<p>For the most part, the API Deployment has not changed. We are using the same Bicep to create the APIM Instance, APIM Backends/Named Values, and Policies. The main change to our Bicep Deployment occurs in step 2.1 as shown in the diagram below.</p>
<p>
  <img src="/images/posts/2024/01/API-Deployment-with-Swagger.png" alt="API Deployment">

</p>
<p>Rather than constructing the API and API Operations individually through Bicep Resources as done in the previous post, we are going to define the APIM API along with the generated Swagger Definition from earlier steps. APIM validates the Swagger Definition and uses it to construct the API and Operations on our behalf.</p>
<p>The three main differences to our API deployment are:</p>
<ol>
<li>We need to make use of the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-files#loadtextcontent">loadTextContent</a> Bicep function to load the generated Swagger Definition into our Bicep Template.
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">swaggerDefinition</span> = <span style="color:#50fa7b">loadTextContent</span>(<span style="color:#f1fa8c">&#39;../../SwaggerGenerator/GeneratedSpec.json&#39;</span>)
</span></span></code></pre></div></li>
<li>We need to change the <code>Microsoft.ApiManagement/service/apis</code> resource to accept our generated Swagger Definition:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the Logic App API in APIM - Loading in Swagger Definition&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppAPI</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apiName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#8be9fd;font-style:italic">apimAPIDisplayName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">subscriptionRequired</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">path</span>: <span style="color:#8be9fd;font-style:italic">apimAPIPath</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">protocols</span>: [
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;https&#39;</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">format</span>: <span style="color:#f1fa8c">&#39;swagger-json&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">swaggerDefinition</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></li>
<li>We need to remove the following Bicep Module call to create the API Operations as this will now be done for us.
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy logic App API operation&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">module</span> <span style="color:#8be9fd;font-style:italic">logicAppAPIOperation</span> <span style="color:#f1fa8c">&#39;Modules/apimOperation.azuredeploy.bicep&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">operation</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span> :{
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-deploy&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">params</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parentName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicAppAPI</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicAppName</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationDisplayName</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">displayName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationMethod</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">method</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationName</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}]
</span></span></code></pre></div></li>
</ol>
<h2 id="summary">Summary</h2>
<p>The main benefit of using this method over constructing the API and Operations through Bicep is that we only need to define the backing API once.</p>
<p>If you would like to spin up a demo of this implementation or would like to use it as the basis of something you are working on, the source to all my work is in my <a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend">GitHub repository</a> along with a README that explains how to get started.</p>
<p>Have a go and see if this simplifies your Standard Logic App APIM Configurations.</p>
]]></content:encoded></item><item><title>Azure API Management | Logic App (Standard) Backend</title><link>https://andrewilson.co.uk/post/2024/01/standard-logic-app-apim-backend/</link><pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/01/standard-logic-app-apim-backend/</guid><description>Overview Updated [31/01/2024]: See New Post showing methods of linking a Logic App Standard as a Backend to APIM through a Swagger Definition.
I have recently been reviewing the method in which a Logic App (Standard) workflow would be setup as an API in API Management. My aim is to overcome and simplify the limitation whereby directly importing a Logic App (Standard) workflow is not available, only in consumption.
After some exploration I believe I have identified a configurable and secure method in setting up the front-to-backend routing as can be seen in the diagram below: The overall design aims to abstract the backend from the api operations, i.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p><a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend">
  <img src="https://img.shields.io/badge/Repo-Standard--Logic--App--APIM--Backend-blue?logo=github&amp;style=for-the-badge" alt="GitHub Repository">

</a></p>
<blockquote>
<p><code>Updated [31/01/2024]: See</code> <a href="/post/2024/02/standard-logic-app-apim-backend-swagger/">New Post</a> <code>showing methods of linking a Logic App Standard as a Backend to APIM through a Swagger Definition.</code></p>
</blockquote>
<p>I have recently been reviewing the method in which a Logic App (Standard) workflow would be setup as an API in API Management. My aim is to overcome and simplify the limitation whereby <a href="https://techcommunity.microsoft.com/t5/azure-paas-blog/import-logic-apps-standard-into-azure-api-management/ba-p/3055490#:~:text=As%20an%20alternative%2C%20to%20import,into%20the%20backend%20and%20frontend.">directly importing a Logic App (Standard) workflow is not available, only in consumption.</a></p>
<p>After some exploration I believe I have identified a configurable and secure method in setting up the front-to-backend routing as can be seen in the diagram below:

  <img src="/images/posts/2024/01/Overview.png" alt="Overview">

</p>
<p>The overall design aims to abstract the backend from the api operations, i.e. the backend points to the Logic App and the individual operations point to the respective workflows. The design also specifies granular access to the workflow Shared-Access-Signature (sig) held in the applications specific KeyVault (<em>to see further details on this, see <a href="/post/2023/11/rbac-key-vault-specific-secret/">Azure RBAC Key Vault | Role Assignment for Specific Secret</a></em>). Furthermore, the additional required parameters that are necessary to call a workflow have been implemented through APIM policies to remove the need for callers to understand backend implementation.</p>
<p>I have opted for Infrastructure as Code (IaC) as my method of implementation, specifically Bicep. I have broken down the implementation of the diagram above into two parts, Application Deployment, and API Deployment.</p>
<h2 id="application-deployment">Application Deployment</h2>
<p>The following diagram demonstrates how the application backend has been deployed.

  <img src="/images/posts/2024/01/Application-Deployment.png" alt="ApplicationDeployment">

</p>
<p>The deployment is split into three stages:</p>
<ol>
<li>Deploy the Core Application Components.</li>
<li>Deploy the Logic Workflows to the recently deployed Logic App.</li>
<li>Store the Workflow SAS keys in KeyVault for later secure use.</li>
</ol>
<p>In turn the Bicep for <strong>step 1</strong> is shown below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/***************************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">Application</span> <span style="color:#8be9fd;font-style:italic">Core</span> <span style="color:#8be9fd;font-style:italic">Deploy</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">***************************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;A prefix used to identify the application resources&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">applicationPrefixName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The name of the application used for tags&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">applicationName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The location that the resources will be deployed to - defaulting to the resource group location&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#50fa7b">resourceGroup</span>().<span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The environment that the resources are being deployed to&#39;</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">allowed</span>([
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;dev&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;test&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;prod&#39;</span>
</span></span><span style="display:flex;"><span>])
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">env</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;dev&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">applicationKeyVaultName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationPrefixName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">env</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">kv&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">lgApplicationAppServicePlanName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationPrefixName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">env</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">asp&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">lgStorageAccountName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationPrefixName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">env</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">st&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationPrefixName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">env</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">logic&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">isProduction</span> = <span style="color:#8be9fd;font-style:italic">env</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#39;prod&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the Application Specific Key Vault&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationKeyVaultDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2023-07-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">applicationKeyVaultName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Application</span>: <span style="color:#8be9fd;font-style:italic">applicationName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Version</span>: <span style="color:#50fa7b">deployment</span>().<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">template</span>.<span style="color:#8be9fd;font-style:italic">contentVersion</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">family</span>: <span style="color:#f1fa8c">&#39;A&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;standard&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tenantId</span>: <span style="color:#50fa7b">tenant</span>().<span style="color:#8be9fd;font-style:italic">tenantId</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">enableRbacAuthorization</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">enableSoftDelete</span>: <span style="color:#8be9fd;font-style:italic">isProduction</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the App Service Plan used for Logic App Standard&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">lgAppServicePlanDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/serverfarms@2022-09-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">lgApplicationAppServicePlanName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Application</span>: <span style="color:#8be9fd;font-style:italic">applicationName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Version</span>: <span style="color:#50fa7b">deployment</span>().<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">template</span>.<span style="color:#8be9fd;font-style:italic">contentVersion</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">kind</span>: <span style="color:#f1fa8c">&#39;elastic&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sku</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;WS1&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tier</span>: <span style="color:#f1fa8c">&#39;WorkflowStandard&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">size</span>: <span style="color:#f1fa8c">&#39;WS1&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">family</span>: <span style="color:#f1fa8c">&#39;WS&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">capacity</span>: <span style="color:#8be9fd;font-style:italic">1</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the Storage Account used for Logic App Standard&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Storage/storageAccounts@2023-01-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">lgStorageAccountName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Application</span>: <span style="color:#8be9fd;font-style:italic">applicationName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Version</span>: <span style="color:#50fa7b">deployment</span>().<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">template</span>.<span style="color:#8be9fd;font-style:italic">contentVersion</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sku</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;Standard_LRS&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">kind</span>: <span style="color:#f1fa8c">&#39;StorageV2&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">supportsHttpsTrafficOnly</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">minimumTlsVersion</span>: <span style="color:#f1fa8c">&#39;TLS1_2&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">defaultToOAuthAuthentication</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy the Application Standard Logic App&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppStandardDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2022-09-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Application</span>: <span style="color:#8be9fd;font-style:italic">applicationName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Version</span>: <span style="color:#50fa7b">deployment</span>().<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">template</span>.<span style="color:#8be9fd;font-style:italic">contentVersion</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">kind</span>: <span style="color:#f1fa8c">&#39;functionapp,workflowapp&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">serverFarmId</span>: <span style="color:#8be9fd;font-style:italic">lgAppServicePlanDeploy</span>.<span style="color:#8be9fd;font-style:italic">id</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">publicNetworkAccess</span>: <span style="color:#f1fa8c">&#39;Enabled&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">httpsOnly</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">config</span> <span style="color:#f1fa8c">&#39;config@2022-09-01&#39;</span> = {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;appsettings&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">FUNCTIONS_EXTENSION_VERSION</span>: <span style="color:#f1fa8c">&#39;~4&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">FUNCTIONS_WORKER_RUNTIME</span>: <span style="color:#f1fa8c">&#39;node&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">WEBSITE_NODE_DEFAULT_VERSION</span>: <span style="color:#f1fa8c">&#39;~18&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">AzureWebJobsStorage</span>: <span style="color:#f1fa8c">&#39;DefaultEndpointsProtocol=https;AccountName=</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">;AccountKey=</span><span style="color:#f1fa8c">${</span><span style="color:#50fa7b">listKeys</span>(<span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span>.<span style="color:#8be9fd;font-style:italic">id</span>, <span style="color:#f1fa8c">&#39;2019-06-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">keys</span>[<span style="color:#8be9fd;font-style:italic">0</span>].<span style="color:#8be9fd;font-style:italic">value</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">;EndpointSuffix=core.windows.net&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">WEBSITE_CONTENTAZUREFILECONNECTIONSTRING</span>: <span style="color:#f1fa8c">&#39;DefaultEndpointsProtocol=https;AccountName=</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">;AccountKey=</span><span style="color:#f1fa8c">${</span><span style="color:#50fa7b">listKeys</span>(<span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span>.<span style="color:#8be9fd;font-style:italic">id</span>, <span style="color:#f1fa8c">&#39;2019-06-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">keys</span>[<span style="color:#8be9fd;font-style:italic">0</span>].<span style="color:#8be9fd;font-style:italic">value</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">;EndpointSuffix=core.windows.net&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">WEBSITE_CONTENTSHARE</span>: <span style="color:#8be9fd;font-style:italic">lgStorageAccountDeploy</span>.<span style="color:#8be9fd;font-style:italic">name</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">AzureFunctionsJobHost__extensionBundle__id</span>: <span style="color:#f1fa8c">&#39;Microsoft.Azure.Functions.ExtensionBundle.Workflows&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">AzureFunctionsJobHost__extensionBundle__version</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#f1fa8c">&#39;[1.*,&#39;</span><span style="color:#f1fa8c">}${</span><span style="color:#f1fa8c">&#39; 2.0.0)&#39;</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">APP_KIND</span>: <span style="color:#f1fa8c">&#39;workflowApp&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">output</span> <span style="color:#8be9fd;font-style:italic">keyVaultName</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#8be9fd;font-style:italic">applicationKeyVaultName</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">output</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>  = <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span>
</span></span></code></pre></div><p><strong>Step 2</strong> is the deployment of the workflow definition such as this very simple request response:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;definition&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;Response&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Response&#34;</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;kind&#34;</span>: <span style="color:#f1fa8c">&#34;Http&#34;</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;statusCode&#34;</span>: <span style="color:#bd93f9">200</span>
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {}
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;outputs&#34;</span>: {},
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;triggers&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;When_a_HTTP_request_is_received&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Request&#34;</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;kind&#34;</span>: <span style="color:#f1fa8c">&#34;Http&#34;</span>
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;kind&#34;</span>: <span style="color:#f1fa8c">&#34;Stateless&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Step 3</strong> demonstrated below takes a number of workflows, retrieves their SAS keys and creates them as secrets in the Application KeyVault.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/*****************************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">Application</span> <span style="color:#8be9fd;font-style:italic">Secrets</span> <span style="color:#8be9fd;font-style:italic">Deploy</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">*****************************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Logic App to place workflow(s) sig into KeyVault&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Key Vault to place secrets into&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">keyVaultName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Array of Workflows to obtain sigs from.&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">workflows</span> <span style="color:#8be9fd;font-style:italic">array</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">workflowName</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">workflowTrigger</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing Logic App&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicApp</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2022-09-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">applicationLogicAppName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing Key Vault instance to store secrets&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">keyVault</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2023-07-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">keyVaultName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Vault the Logic App workflow sig as a secret - Deployment principle requires RBAC permissions to do this&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">vaultLogicAppKey</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults/secrets@2023-07-01&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">workflow</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">workflows</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">keyVault</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceType</span>: <span style="color:#f1fa8c">&#39;LogicAppStandard&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">contentType</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">name</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowName</span>, <span style="color:#8be9fd;font-style:italic">workflow</span>.<span style="color:#8be9fd;font-style:italic">workflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">queries</span>.<span style="color:#8be9fd;font-style:italic">sig</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span></code></pre></div><h2 id="api-deployment">API Deployment</h2>
<p>The following diagram demonstrates how API Management and the Logic App backend API have been deployed.</p>
<p>
  <img src="/images/posts/2024/01/API-Deployment.png" alt="ApplicationDeployment">

</p>
<p>The deployment is split into two stages:</p>
<ol>
<li>Deploy an API Management Service Instance.</li>
<li>Deploy respective Backend, API, API Operations, and Policies.</li>
</ol>
<p>Our deployment of the API and its operations pointing at the Standard Logic App requires the following components:</p>
<ol>
<li><strong>Azure Role Assignment</strong> - This is the authorisation system that we will use to assign APIMs <a href="https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview">System Assigned Managed Identity</a> access to the applications Key Vault, specifically the sig secret.</li>
<li><strong>APIM API and API Operations</strong> - Represents a set of available operations with each containing a reference to a backend service that implements the API.</li>
<li><strong>APIM Named Values</strong> - This is a global collection of name/value pairs within the APIM Instance. Using APIM Policies we can use Named Values to further API configuration. Named Values can store constant string values, secrets, or more importantly Key Vault references to secrets.</li>
<li><strong>APIM Backend</strong> - APIM Backend is an HTTP service that implements a front-end API. Normally with consumption Logic Apps when imported into APIM a Backend Service is automatically created for you. This is not currently possible with Standard Logic Apps. However, Standard Logic Apps have the same foundations as Azure Functions which means that we can set this up through custom backends (i.e. is treated as a Function Backend).
<ul>
<li>Setting up the Backend means that we can abstract backend service information, promoting reusability and improved governance.</li>
</ul>
</li>
<li><strong>APIM Policies</strong> - Policies are statements that are run sequentially on a given request or response for an API. These statements further our ability to configure the API and its abilities such as adding further parameters, setting a backend, making use of configured Named Values.</li>
</ol>
<p>The Bicep for <strong>step 1</strong> is shown below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/**********************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">APIM</span> <span style="color:#8be9fd;font-style:italic">Instance</span> <span style="color:#8be9fd;font-style:italic">Deploy</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">***********************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;A prefix used to identify the api resources&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apiPrefixName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The location that the resources will be deployed to - defaulting to the resource group location&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#50fa7b">resourceGroup</span>().<span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The environment that the resources are being deployed to&#39;</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">allowed</span>([
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;dev&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;test&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;prod&#39;</span>
</span></span><span style="display:flex;"><span>])
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">env</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;dev&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The apim publisher email&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimPublisherEmail</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The apim publisher name&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimPublisherName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimInstanceName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiPrefixName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">env</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">apim&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deployment of the APIM instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">apimInstanceDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apimInstanceName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">env</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Version</span>: <span style="color:#50fa7b">deployment</span>().<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">template</span>.<span style="color:#8be9fd;font-style:italic">contentVersion</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sku</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">capacity</span>: <span style="color:#8be9fd;font-style:italic">0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;Consumption&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">publisherEmail</span>: <span style="color:#8be9fd;font-style:italic">apimPublisherEmail</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">publisherName</span>: <span style="color:#8be9fd;font-style:italic">apimPublisherName</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">identity</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;SystemAssigned&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">output</span> <span style="color:#8be9fd;font-style:italic">apimInstanceName</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#8be9fd;font-style:italic">apimInstanceName</span>
</span></span></code></pre></div><p>The Bicep for <strong>step 2</strong> makes use of module deployments and policies loaded as text into variables.
The Main deployment template is shown below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/******************************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">Logic</span> <span style="color:#8be9fd;font-style:italic">App</span> <span style="color:#8be9fd;font-style:italic">Standard</span> <span style="color:#8be9fd;font-style:italic">APIM</span> <span style="color:#8be9fd;font-style:italic">API</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">*******************************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Logic App to add as a backend&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">logicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the APIM instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimInstanceName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the Key Vault instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">keyVaultName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the API to create in APIM&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apiName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;APIM API path&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimAPIPath</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;APIM API display name&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimAPIDisplayName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Array of API operations&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span> <span style="color:#8be9fd;font-style:italic">array</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">method</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Logic App Base URL</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">lgBaseUrl</span> = <span style="color:#f1fa8c">&#39;https://</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">defaultHostName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/api&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Key Vault Read Access</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefinitionId</span> = <span style="color:#f1fa8c">&#39;4633458b-17de-408a-b874-0445c86b69e6&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// All Operations Policy</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimAPIPolicyRaw</span> = <span style="color:#50fa7b">loadTextContent</span>(<span style="color:#f1fa8c">&#39;./APIM-Policies/APIMAllOperationsPolicy.xml&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimAPIPolicy</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">apimAPIPolicyRaw</span>, <span style="color:#f1fa8c">&#39;__apiName__&#39;</span>, <span style="color:#8be9fd;font-style:italic">apiName</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Operation Policy Template</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimOperationPolicyRaw</span> = <span style="color:#50fa7b">loadTextContent</span>(<span style="color:#f1fa8c">&#39;./APIM-Policies/APIMOperationPolicy.xml&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing APIM Instance, will add APIs and Policies to this resource&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">apimInstance</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service@2022-08-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apimInstanceName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the Logic App API in APIM&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppAPI</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apiName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#8be9fd;font-style:italic">apimAPIDisplayName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">subscriptionRequired</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">path</span>: <span style="color:#8be9fd;font-style:italic">apimAPIPath</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">protocols</span>: [
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;https&#39;</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing Logic App for linking as a backend&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicApp</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2022-09-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy logic App API operation&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">module</span> <span style="color:#8be9fd;font-style:italic">logicAppAPIOperation</span> <span style="color:#f1fa8c">&#39;Modules/apimOperation.azuredeploy.bicep&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">operation</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span> :{
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-deploy&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">params</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parentName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicAppAPI</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicAppName</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationDisplayName</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">displayName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationMethod</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">method</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">operationName</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing application Key Vault instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">keyVault</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2023-07-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">keyVaultName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the existing logicapp workflow sig secret&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">vaultLogicAppKey</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults/secrets@2023-07-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">operation</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicAppName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">keyVault</span>
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Grant APIM Key Vault Reader for the logic app API key secret&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">grantAPIMPermissionsToSecret</span> <span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleAssignments@2022-04-01&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> (<span style="color:#8be9fd;font-style:italic">operation</span>, <span style="color:#8be9fd;font-style:italic">index</span>) <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#50fa7b">guid</span>(<span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefinitionId</span>, <span style="color:#8be9fd;font-style:italic">keyVault</span>.<span style="color:#8be9fd;font-style:italic">id</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">scope</span>: <span style="color:#8be9fd;font-style:italic">vaultLogicAppKey</span>[<span style="color:#8be9fd;font-style:italic">index</span>]
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">roleDefinitionId</span>: <span style="color:#50fa7b">subscriptionResourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleDefinitions&#39;</span>, <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefinitionId</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalId</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">identity</span>.<span style="color:#8be9fd;font-style:italic">principalId</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalType</span>: <span style="color:#f1fa8c">&#39;ServicePrincipal&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the named values for the logic app API sigs&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppBackendNamedValues</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/namedValues@2022-08-01&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> (<span style="color:#8be9fd;font-style:italic">operation</span>, <span style="color:#8be9fd;font-style:italic">index</span>) <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tags</span>: [
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;sig&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;logicApp&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">secret</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">keyVault</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">identityClientId</span>: <span style="color:#ff79c6">null</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">secretIdentifier</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">keyVault</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">vaultUri</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">secrets/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">vaultLogicAppKey</span>[<span style="color:#8be9fd;font-style:italic">index</span>].<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dependsOn</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">grantAPIMPermissionsToSecret</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the backend for the Logic App API&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppBackend</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/backends@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apiName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">protocol</span>: <span style="color:#f1fa8c">&#39;http&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">url</span>: <span style="color:#8be9fd;font-style:italic">lgBaseUrl</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">resourceId</span>: <span style="color:#50fa7b">uri</span>(<span style="color:#50fa7b">environment</span>().<span style="color:#8be9fd;font-style:italic">resourceManager</span>, <span style="color:#8be9fd;font-style:italic">logicApp</span>.<span style="color:#8be9fd;font-style:italic">id</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tls</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">validateCertificateChain</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">validateCertificateName</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create a policy for the logic App API and all its operations - linking the logic app backend&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppAPIAllOperationsPolicy</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis/policies@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;policy&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">logicAppAPI</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">apimAPIPolicy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">format</span>: <span style="color:#f1fa8c">&#39;xml&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dependsOn</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">logicAppBackend</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Add query strings via policy&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">module</span> <span style="color:#8be9fd;font-style:italic">operationPolicy</span> <span style="color:#f1fa8c">&#39;./Modules/apimOperationPolicy.azuredeploy.bicep&#39;</span> = [<span style="color:#8be9fd;font-style:italic">for</span> (<span style="color:#8be9fd;font-style:italic">operation</span>, <span style="color:#8be9fd;font-style:italic">index</span>) <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">apimAPIOperations</span>: {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;operationPolicy-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">params</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parentStructureForName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">logicAppAPI</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">rawPolicy</span>: <span style="color:#8be9fd;font-style:italic">apimOperationPolicyRaw</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">apiVersion</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicAppName</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">queries</span>[<span style="color:#f1fa8c">&#39;api-version&#39;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sp</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicAppName</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">queries</span>.<span style="color:#8be9fd;font-style:italic">sp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sv</span>: <span style="color:#50fa7b">listCallbackUrl</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/hostruntime/webhooks/api/workflows/triggers&#39;</span>, <span style="color:#8be9fd;font-style:italic">logicAppName</span>, <span style="color:#f1fa8c">&#39;runtime&#39;</span>, <span style="color:#f1fa8c">&#39;workflow&#39;</span>, <span style="color:#f1fa8c">&#39;management&#39;</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowName</span>, <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">lgWorkflowTrigger</span>), <span style="color:#f1fa8c">&#39;2022-09-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">queries</span>.<span style="color:#8be9fd;font-style:italic">sv</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sig</span>: <span style="color:#f1fa8c">&#39;{{</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-sig}}&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dependsOn</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">logicAppAPIOperation</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span></code></pre></div><p>The APIM All Operations Policy template is as follows:</p>
<blockquote>
<p>The Deletion Set Header is used to remove subscription key headers from the forwarded request to the backend. For more information see <a href="/post/2023/11/apim-subscription-key-header/"><em>Azure API Management | Unintentional Pass through of Subscription Key Header</em></a>.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">&lt;!-- API ALL OPERATIONS SCOPE --&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;policies&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;inbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-backend-service</span> <span style="color:#50fa7b">id=</span><span style="color:#f1fa8c">&#34;logicapp-backend-policy&#34;</span> <span style="color:#50fa7b">backend-id=</span><span style="color:#f1fa8c">&#34;__apiName__&#34;</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-header</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;Ocp-Apim-Subscription-Key&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;delete&#34;</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/inbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;outbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/outbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;on-error&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/on-error&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;/policies&gt;</span>
</span></span></code></pre></div><p>The APIM Operation Policy template is as follows:</p>
<blockquote>
<p>By setting the parameters as policy means that those calling the API do not need to be aware of backend configuration. Thus allowing for complete separation of concerns.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#6272a4">&lt;!-- API OPERATION SCOPE --&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;policies&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;inbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-query-parameter</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;api-version&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;append&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&lt;value&gt;</span>__api-version__<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;/set-query-parameter&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-query-parameter</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;sp&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;append&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&lt;value&gt;</span>__sp__<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;/set-query-parameter&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-query-parameter</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;sv&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;append&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&lt;value&gt;</span>__sv__<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;/set-query-parameter&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;set-query-parameter</span> <span style="color:#50fa7b">name=</span><span style="color:#f1fa8c">&#34;sig&#34;</span> <span style="color:#50fa7b">exists-action=</span><span style="color:#f1fa8c">&#34;append&#34;</span><span style="color:#ff79c6">&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&lt;value&gt;</span>__sig__<span style="color:#ff79c6">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;/set-query-parameter&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/inbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;outbound&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/outbound&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;on-error&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&lt;base</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&lt;/on-error&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">&lt;/policies&gt;</span>
</span></span></code></pre></div><p>The API Operation Module deployment is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/**********************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">API</span> <span style="color:#8be9fd;font-style:italic">Operation</span> <span style="color:#8be9fd;font-style:italic">Deploy</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">***********************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;API Management Service API Name Path&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">parentName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the API Operation&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">operationName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Display name for the API operation&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">operationDisplayName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;API Operation Method e.g. GET&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">operationMethod</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Logic App Call Back object containing URL and other details&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">lgCallBackObject</span> <span style="color:#8be9fd;font-style:italic">object</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">operationUrlBase</span> = <span style="color:#50fa7b">split</span>(<span style="color:#50fa7b">split</span>(<span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.<span style="color:#8be9fd;font-style:italic">value</span>, <span style="color:#f1fa8c">&#39;?&#39;</span>)[<span style="color:#8be9fd;font-style:italic">0</span>], <span style="color:#f1fa8c">&#39;/api&#39;</span>)[<span style="color:#8be9fd;font-style:italic">1</span>]
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> = <span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.?<span style="color:#8be9fd;font-style:italic">relativePath</span> <span style="color:#ff79c6">!=</span> <span style="color:#ff79c6">null</span> ? <span style="color:#ff79c6">true</span> : <span style="color:#ff79c6">false</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">pathParametersList</span> = <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> ? <span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.<span style="color:#8be9fd;font-style:italic">relativePathParameters</span> : []
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">pathParameters</span> = [<span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">pathParameter</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">pathParametersList</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">pathParameter</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>}]
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">RelativePathHasBeginingSlash</span> = <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> ? <span style="color:#50fa7b">first</span>(<span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.<span style="color:#8be9fd;font-style:italic">relativePath</span>) <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#39;/&#39;</span> : <span style="color:#ff79c6">false</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">operationUrl</span> = <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> <span style="color:#ff79c6">&amp;&amp;</span> <span style="color:#8be9fd;font-style:italic">RelativePathHasBeginingSlash</span> ? <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operationUrlBase</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.<span style="color:#8be9fd;font-style:italic">relativePath</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span> : <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> <span style="color:#ff79c6">&amp;&amp;</span> <span style="color:#ff79c6">!</span><span style="color:#8be9fd;font-style:italic">RelativePathHasBeginingSlash</span> ? <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operationUrlBase</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">lgCallBackObject</span>.<span style="color:#8be9fd;font-style:italic">relativePath</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span> : <span style="color:#8be9fd;font-style:italic">operationUrlBase</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Deploy logic App API operation&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppAPIGetOperation</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis/operations@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">parentName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">operationName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#8be9fd;font-style:italic">operationDisplayName</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">method</span>: <span style="color:#8be9fd;font-style:italic">operationMethod</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">urlTemplate</span>: <span style="color:#8be9fd;font-style:italic">operationUrl</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">templateParameters</span>: <span style="color:#8be9fd;font-style:italic">hasRelativePath</span> ? <span style="color:#8be9fd;font-style:italic">pathParameters</span> : <span style="color:#ff79c6">null</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span></code></pre></div><p>The API Operation Policy Module Deployment is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/********************************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Bicep</span> <span style="color:#8be9fd;font-style:italic">Template</span>: <span style="color:#8be9fd;font-style:italic">APIM</span> <span style="color:#8be9fd;font-style:italic">LG</span> <span style="color:#8be9fd;font-style:italic">API</span> <span style="color:#8be9fd;font-style:italic">Operation</span> <span style="color:#8be9fd;font-style:italic">Policy</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">********************************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The Parent naming structure for the Policy&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">parentStructureForName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The raw policy document template&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">rawPolicy</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The Logic App service API version&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">apiVersion</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The Logic App workflow permissions&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">sp</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The Logic App workflow version number of the query parameters&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">sv</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The named value name for the workflow sig&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">sig</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">policyApiVersion</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">rawPolicy</span>, <span style="color:#f1fa8c">&#39;__api-version__&#39;</span>, <span style="color:#8be9fd;font-style:italic">apiVersion</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">policySP</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">policyApiVersion</span>, <span style="color:#f1fa8c">&#39;__sp__&#39;</span>, <span style="color:#8be9fd;font-style:italic">sp</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">policySV</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">policySP</span>, <span style="color:#f1fa8c">&#39;__sv__&#39;</span>, <span style="color:#8be9fd;font-style:italic">sv</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">policySIG</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">policySV</span>, <span style="color:#f1fa8c">&#39;__sig__&#39;</span>, <span style="color:#8be9fd;font-style:italic">sig</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Add query strings via policy&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">operationPolicy</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis/operations/policies@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">parentStructureForName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/policy&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">policySIG</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">format</span>: <span style="color:#f1fa8c">&#39;xml&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span></code></pre></div><p>Have a go and see if this simplifies your Standard Logic App APIM Configurations.</p>
]]></content:encoded></item><item><title>Automating Deployment of Azure Consumption Logic Apps | Bicep and ARM</title><link>https://andrewilson.co.uk/post/2023/02/automate-deployment-of-azure-consumption-logic-apps/</link><pubDate>Fri, 24 Feb 2023 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2023/02/automate-deployment-of-azure-consumption-logic-apps/</guid><description>Azure Logic Apps Azure Logic Apps is an Azure Integration Service (AIS) that provides you the ability to create and run automated workflows with little to no code. Consumption Logic Apps are developed using the visual designer within the Azure Portal.
If you are new to developing Azure Logic Apps, there is great Microsoft Learning material to get you started:
What are Azure Logic Apps | https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-overview Introduction to Azure Logic Apps | https://learn.</description><content:encoded><![CDATA[<h2 id="azure-logic-apps">Azure Logic Apps</h2>
<p>Azure Logic Apps is an Azure Integration Service (AIS) that provides you the ability to create and run automated workflows with little to no code. Consumption Logic Apps are developed using the visual designer within the Azure Portal.</p>
<p>If you are new to developing Azure Logic Apps, there is great Microsoft Learning material to get you started:</p>
<ul>
<li>What are Azure Logic Apps | <a href="https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-overview">https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-overview</a></li>
<li>Introduction to Azure Logic Apps | <a href="https://learn.microsoft.com/en-us/training/modules/intro-to-logic-apps/">https://learn.microsoft.com/en-us/training/modules/intro-to-logic-apps/</a></li>
<li>Quickstart: Create an integration workflow | <a href="https://learn.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">https://learn.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow</a></li>
</ul>
<h2 id="problem-space">Problem Space</h2>
<p>Once you have created your workflow in the Logic App designer, your next question may be:</p>
<blockquote>
<p>How do I consistently deploy the Logic App with my developed workflow?</p>
</blockquote>
<p>We are going to be looking at conducting our deployment with ARM and Bicep templates.</p>
<p>ARM templates are a declarative way of defining Azure service configurations in code. When deploying services to Azure using ARM templates that are under source control and therefore in step with product development, are by far the best approach. The Azure services can be defined in a single template and that template can be used to deploy multiple copies of the system, either for dev/test purposes or to provision live instances for multiple customers in a reliable and predictable manner.</p>
<p>Bicep<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> is a transparent abstraction over ARM template JSON and doesn&rsquo;t lose any of the JSON template capabilities. Bicep templates will be compiled into ARM templates.</p>
<h3 id="arm-template-deployments">ARM Template Deployments</h3>
<p>Following the Microsoft guide<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> for both building an Azure Logic App using ARM templates and including the Logic Apps definition, you will likely end up with the following development process:</p>
<ol>
<li>Develop and Deploy a Basic Logic App ARM template:</li>
</ol>
<p><code>Remember to add the template to your Source Control</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;parameters&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;logicAppName&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;location&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;variables&#34;</span>: {},
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;resources&#34;</span>: [
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Microsoft.Logic/workflows&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;apiVersion&#34;</span>: <span style="color:#f1fa8c">&#34;2019-05-01&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;[parameters(&#39;logicAppName&#39;)]&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;location&#34;</span>: <span style="color:#f1fa8c">&#34;[parameters(&#39;location&#39;)]&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;properties&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;definition&#34;</span>: {},
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;parameters&#34;</span>: {}
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="2">
<li>Develop a workflow in the deployed Logic App Portal Designer:

  <img src="/images/posts/2023/02/LogicAppPortalDesigner.png" alt="Logic App Portal Designer">

</li>
<li>Obtain the workflow definition from <code>Code view</code>:

  <img src="/images/posts/2023/02/LogicAppCodeView.png" alt="Logic App Portal Designer">

</li>
<li>Copy the workflow definition from the Portal into your Logic App ARM Template:</li>
</ol>
<p><code>Make sure to parametrise fields within your workflow using the ARM Parameter syntax</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Json" data-lang="Json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;parameters&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;logicAppName&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;location&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;String&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;interval&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;int&#34;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;variables&#34;</span>: {},
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;resources&#34;</span>: [
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Microsoft.Logic/workflows&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;apiVersion&#34;</span>: <span style="color:#f1fa8c">&#34;2019-05-01&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;[parameters(&#39;logicAppName&#39;)]&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;location&#34;</span>: <span style="color:#f1fa8c">&#34;[parameters(&#39;location&#39;)]&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;properties&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;definition&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;Condition_-_Morning_or_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;Terminate_-_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                                    <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                                        <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                                    },
</span></span><span style="display:flex;"><span>                                    <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                                    <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                                }
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;else&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                                    <span style="color:#ff79c6">&#34;Terminate_-_Morning&#34;</span>: {
</span></span><span style="display:flex;"><span>                                        <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                                            <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                                        },
</span></span><span style="display:flex;"><span>                                        <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                                        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                                    }
</span></span><span style="display:flex;"><span>                                }
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;expression&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;and&#34;</span>: [
</span></span><span style="display:flex;"><span>                                    {
</span></span><span style="display:flex;"><span>                                        <span style="color:#ff79c6">&#34;greaterOrEquals&#34;</span>: [
</span></span><span style="display:flex;"><span>                                            <span style="color:#f1fa8c">&#34;@utcNow(&#39;H:mm:ss&#39;)&#34;</span>,
</span></span><span style="display:flex;"><span>                                            <span style="color:#f1fa8c">&#34;12:00:00&#34;</span>
</span></span><span style="display:flex;"><span>                                        ]
</span></span><span style="display:flex;"><span>                                    }
</span></span><span style="display:flex;"><span>                                ]
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;If&#34;</span>
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    },
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;outputs&#34;</span>: {},
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;parameters&#34;</span>: {},
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;triggers&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;Recurrence_-_Start&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;evaluatedRecurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Day&#34;</span>,
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#bd93f9">1</span>,
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;schedule&#34;</span>: {
</span></span><span style="display:flex;"><span>                                    <span style="color:#ff79c6">&#34;hours&#34;</span>: [
</span></span><span style="display:flex;"><span>                                        <span style="color:#f1fa8c">&#34;11&#34;</span>
</span></span><span style="display:flex;"><span>                                    ]
</span></span><span style="display:flex;"><span>                                }
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;recurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Hour&#34;</span>,
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#f1fa8c">&#34;[parameters(&#39;interval&#39;)]&#34;</span>
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Recurrence&#34;</span>
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;parameters&#34;</span>: {}
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="5">
<li>Any changes to the workflow in the Azure Portal Designer are to be reflected in your ARM Template that is in Source Control. You can use source control change tooling to see the diff between current and latest, this can help you retain parameterized values that you have previously included.</li>
</ol>
<h3 id="bicep-template-deployment">Bicep Template Deployment</h3>
<p>Generating Logic App ARM Templates from Bicep is possible but has a different approach. Bicep is not written in Json as ARM is, and therefore you cannot simply copy the Json workflow definition into the Logic App deployment resource.</p>
<p>Following the example given by Microsoft<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, their method is to write out the definition using the Bicep syntax and replace property values with Bicep properties as you would with ARM. This approach however does not adapt well to change, nor is it an easy task to bring the workflow definition across from the portal. Having to convert the workflow to Bicep syntax every time is simply a pain.</p>
<p>That said, hope is not lost.</p>
<p>Bicep has some built in functions that will allow us to retain a similar development process, such that:</p>
<p>We will still run through <code>steps 1, 2, and 3</code> as we have done for ARM, but this time with Bicep.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Logic</span> <span style="color:#8be9fd;font-style:italic">App</span> <span style="color:#8be9fd;font-style:italic">Template</span> <span style="color:#8be9fd;font-style:italic">Bicep</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">**************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Logic App Name&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">logicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The location that the resource will be deployed to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppDeployment</span> <span style="color:#f1fa8c">&#39;Microsoft.Logic/workflows@2022-10-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">definition</span>: {}
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parameters</span>: {}
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">state</span>: <span style="color:#f1fa8c">&#39;Enabled&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">output</span> <span style="color:#8be9fd;font-style:italic">LogicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span></code></pre></div><ol start="4">
<li>
<p>Rather than copying the workflow definition into the Bicep template, copy the definition into a <code>new Json file</code> in your source control repository.</p>
</li>
<li>
<p>As you do not have access to your Bicep Parameters, any values that need parametrising will need to be replaced with tokens that will be replaced by the Bicep Template. For instance, **interval**.</p>
</li>
<li>
<p>Next we will load our workflow definition into the template, conduct token replacement with Parameter values, and then assign the definition and parameters to the Logic App Resource.</p>
<p>The Bicep Functions that we will be using to conduct these activities are:</p>
<ul>
<li><strong>loadTextContent</strong> | Loads the content of the specified file as a string. | <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-files#loadtextcontent">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-files#loadtextcontent</a></li>
<li><strong>replace</strong> | Returns a new string with all instances of one string replaced by another string. | <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-string#replace">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-string#replace</a></li>
<li><strong>json</strong> | Converts a valid JSON string into a JSON data type. | <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-object#json">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-object#json</a></li>
</ul>
<p>See the Example Below:</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#ff79c6">/************************</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Logic</span> <span style="color:#8be9fd;font-style:italic">App</span> <span style="color:#8be9fd;font-style:italic">Template</span> <span style="color:#8be9fd;font-style:italic">Bicep</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">**************************/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">targetScope</span> = <span style="color:#f1fa8c">&#39;resourceGroup&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ****************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Logic App Name&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">logicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The location that the resource will be deployed to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Trigger Interval&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">interval</span> <span style="color:#8be9fd;font-style:italic">int</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">logicAppDefinition</span> = <span style="color:#50fa7b">loadTextContent</span>(<span style="color:#f1fa8c">&#39;./Definition.json&#39;</span>) <span style="color:#6272a4">// Load our definition into a string variable</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">logicAppReplacementParameter</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">logicAppDefinition</span>, <span style="color:#f1fa8c">&#39;**interval**&#39;</span>, <span style="color:#8be9fd;font-style:italic">interval</span>) <span style="color:#6272a4">// Replace tokens with our parameters</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">logicAppDefinitionJson</span> = <span style="color:#50fa7b">json</span>(<span style="color:#8be9fd;font-style:italic">logicAppReplacementParameter</span>) <span style="color:#6272a4">// Retrieve the Json object from the Json String so we can access specific data when assigning</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicAppDeployment</span> <span style="color:#f1fa8c">&#39;Microsoft.Logic/workflows@2022-10-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">definition</span>: <span style="color:#8be9fd;font-style:italic">logicAppDefinitionJson</span>.<span style="color:#8be9fd;font-style:italic">definition</span> <span style="color:#6272a4">// Set the definition</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parameters</span>: <span style="color:#8be9fd;font-style:italic">logicAppDefinitionJson</span>.<span style="color:#8be9fd;font-style:italic">parameters</span> <span style="color:#6272a4">// Set any Properties that may be set</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Outputs **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">output</span> <span style="color:#8be9fd;font-style:italic">LogicAppName</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#8be9fd;font-style:italic">logicAppName</span>
</span></span></code></pre></div><ol start="7">
<li>As with the ARM templates, any changes to the workflow in the Azure Portal Designer are to be reflected in your Json Workflow file that is in Source Control. You can use source control change tooling to see the diff between current and latest, this can help you retain tokenised values that you have previously included.</li>
</ol>
<h2 id="take-note-when">Take Note When</h2>
<ul>
<li>Special point of care should be taken if your logic app is using xpath expressions, proper concatenation/interpolation of the quotes can be a nightmare.</li>
<li>Bicep loadTextContent has size limits: The maximum allowed size of the file is 96 Kb.
<ul>
<li>If you are meeting these size limits for your workflows, this may be an indication that you need to split your workflow up.</li>
</ul>
</li>
</ul>
<h2 id="summary">Summary</h2>
<p>Whether you choose to build your resource deployment templates with ARM or Bicep, both options as shown will provide you a development process where you can keep your low code consumption Logic App not only in source control, but have a reliable deployment template that will allow you to create your Logic App when and where ever you wish.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>What is Bicep | <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Automate deployment for Azure Logic Apps by using <strong>ARM Templates</strong> | <a href="https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-azure-resource-manager-templates-overview">https://learn.microsoft.com/en-us/azure/logic-apps/logic-apps-azure-resource-manager-templates-overview</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Automate deployment for Azure Logic Apps by using <strong>Bicep Templates</strong> | <a href="https://learn.microsoft.com/en-us/azure/logic-apps/quickstart-create-deploy-bicep?tabs=CLI">https://learn.microsoft.com/en-us/azure/logic-apps/quickstart-create-deploy-bicep?tabs=CLI</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Azure Logic App | Parallel Terminates &amp; Action State Checking</title><link>https://andrewilson.co.uk/post/2022/09/azure-logic-app-parallel-terminate/</link><pubDate>Sun, 04 Sep 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/09/azure-logic-app-parallel-terminate/</guid><description>Problem Space: I have recently encountered an interesting problem space with Azure logic app action run after logic. I ran into the problem whilst creating a logic app that will perform actions in parallel. The bulk of the actions are performed in scopes. If an action fails within the first set of scopes, the scope status is Failed. If the first scope fails, then the second scope full of actions are executed (this based on run after logic).</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space:</h2>
<p>I have recently encountered an interesting problem space with Azure logic app action <code>run after</code> logic. I ran into the problem whilst creating a logic app that will perform actions in parallel. The bulk of the actions are performed in scopes. If an action fails within the first set of scopes, the scope status is <code>Failed</code>. If the first scope fails, then the second scope full of actions are executed (<em>this based on run after logic</em>). The problem with this is that I still need the logic app to terminate as Failed so that an alert will be fired off.</p>
<h3 id="assumed-fix-one">Assumed fix one</h3>
<p>To fix this, I assumed that I could place a terminate action after the parallel actions conclude with run after logic <em>Succeeded</em>. Thus being, if the second scope on either branch has succeeded, then the terminate failed action runs.</p>
<p>This logic can be seen in the diagram shown below:</p>
<p>
  <img src="/images/posts/2022/09/LogicAppState%28Small%29.png" alt="Initial Design">

</p>
<p>How this actually turns out is that both parallel first scopes will have to have failed and the second scopes have run for the terminate condition to run.
Thus, if using run after logic to assess if an action after a parallel stream should run will only work in an <strong>AND</strong> logic case.</p>
<blockquote>
<p>i.e</p>
<p>Both second scopes have succeeded, or both second scopes have failed etc.</p>
<p>Not if scope 2.2 succeeded or if scope 3.2 succeeded.</p>
</blockquote>
<h3 id="assumed-fix-two">Assumed fix two</h3>
<p>After validating the run after logic of the first assumed fix, I then experimented with placing a terminate failed action at the end of each parallel stream with the same run after condition. As you would expect, the major problem with this is that if the one parallel stream fails first, the other stream will be skipped mid execution. Clearly not fixing the problem. This can be seen in the diagram below:</p>
<p>
  <img src="/images/posts/2022/09/LogicAppState2%28Small%29.png" alt="Assumed Fix Two">

</p>
<h3 id="actual-fix">Actual Fix</h3>
<p>The actual fix for this is not one you would naturally come to. Based on <a href="https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-control-flow-run-steps-group-scopes">Microsoft Documentation</a> we need to evaluate the scopes result status within a conditional action, then conduct the actions based on that result. Within the condition action, we can use either and/or logic as required. The expression to retrieve the scopes run status is as follows:</p>
<p><code>result('Scope')[0]['status']</code></p>
<p>This solution allows us to retrieve individual scope run status and evaluate at the end of the parallel stream. Based on either 2.1 or 3.1 scopes failing, we can then run our failed termination, else allow logic app to succeed.</p>
<p>Bear in mind that for this to work, the conditional after the parallel stream needs to have all run after types set so that the conditional runs regardless. This can be seen in the diagram below:</p>
<p>
  <img src="/images/posts/2022/09/LogicAppState3%28Small%29.png" alt="Actual Fix">

</p>
]]></content:encoded></item></channel></rss>