<?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>APIM on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/tags/apim/</link><description>Recent content in APIM on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 26 Nov 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/tags/apim/index.xml" rel="self" type="application/rss+xml"/><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>&lt;p&gt;&lt;a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend"&gt;
&lt;img src="https://img.shields.io/badge/Repo-Easy%20Auth%20With%20Standard%20Logic%20App%20And%20APIM-blue?logo=github&amp;amp;style=for-the-badge" alt="GitHub Repository"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;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 &lt;a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview#best-practices-when-using-sas"&gt;best practices&lt;/a&gt; that you need to be abiding by. Such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Some Potential Risks:&lt;/p&gt;</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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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>Easy Auth | Function App with Azure API Management</title><link>https://andrewilson.co.uk/post/2024/11/function-app-easy-auth-apim/</link><pubDate>Thu, 14 Nov 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/11/function-app-easy-auth-apim/</guid><description>&lt;p&gt;&lt;a href="https://github.com/Andrew-D-Wilson/Function-App-APIM-Backend/"&gt;
&lt;img src="https://img.shields.io/badge/Repo-Easy%20Auth%20With%20Function%20Apps%20And%20APIM-blue?logo=github&amp;amp;style=for-the-badge" alt="GitHub Repository"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://andrewilson.co.uk/post/2024/10/function-app-apim-backend/"&gt;recent work&lt;/a&gt; that I have been doing with Function Apps and linking them as backends to Azure API Management has relied on the use of the Function Apps Function SAS key for security. This is a valid authentication approach, but there are risks that you need to be aware of as well as &lt;a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview#best-practices-when-using-sas"&gt;best practices&lt;/a&gt; that you need to be abiding by. Such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Some Potential Risks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a &lt;strong&gt;SAS is leaked&lt;/strong&gt;, it can be used by anyone who obtains it to call your Function.&lt;/li&gt;
&lt;li&gt;If a &lt;strong&gt;SAS expires&lt;/strong&gt; and the API Management API has not been updated to make use of the updated SAS, then the integration functionality will be hindered.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some SAS Best Practices to mitigate risks:&lt;/p&gt;</description><content:encoded><![CDATA[<p><a href="https://github.com/Andrew-D-Wilson/Function-App-APIM-Backend/">
  <img src="https://img.shields.io/badge/Repo-Easy%20Auth%20With%20Function%20Apps%20And%20APIM-blue?logo=github&amp;style=for-the-badge" alt="GitHub Repository">

</a></p>
<h2 id="overview">Overview</h2>
<p>The <a href="/post/2024/10/function-app-apim-backend/">recent work</a> that I have been doing with Function Apps and linking them as backends to Azure API Management has relied on the use of the Function Apps Function 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 Function.</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>But what if you require further governance whereby the Function 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, Azure Functions, and <a href="/post/2024/02/standard-logic-app-easy-auth-apim/">Standard Logic Apps</a>. Easy Auth makes use of federated identity whereby a third-party identity provider manages the user identities and authentication flow for you.</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 functions, but more importantly, I would like Azure API Management to be the only identity that can be used to make requests to my functions as shown in the diagram below:</p>
<p>
  <img src="/images/posts/2024/11/EasyAuthAPIM.png" alt="Eay Auth">

</p>
<blockquote>
<p><strong>Note:</strong></p>
<p>As we will be invoking the Function App HTTP triggered Functions with Easy Auth, we no longer need to specify the following parameters or details:</p>
<ul>
<li>Parameter <strong>code</strong>: Shared-Access-Signature</li>
<li><strong>AuthorizationLevel</strong>: When Easy Auth is enabled, the HTTP triggered Functions no longer need to have the <code>AuthorizationLevel</code> set to Function but rather set to Anonymous. This is because Easy Auth will conduct the authorisation prior to reaching your code and no longer requires a SAS key to be provided of which the Function AuthorisationLevel requires.</li>
</ul>
</blockquote>
<p>For setup, we will need to conduct the following steps:</p>
<blockquote>
<p><em>I have opted for Infrastructure as Code (IaC) as my method of implementation, specifically Bicep. I have also opted for Microsoft Entra as my Identity Provider.</em></p>
</blockquote>
<ol>
<li>
<p>Configure the Function 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 Function 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 Function:</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;-webkit-text-size-adjust:none;"><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@2024-05-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 Function App Settings to allow the Function 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;-webkit-text-size-adjust:none;"><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">vaultFunctionAppRegSecret</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">applicationFunctionAppName</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 Function 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">applicationFunctionAppDeploy</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">applicationFunctionAppName</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">vaultFunctionAppRegSecret</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 Function 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">applicationFunctionAppRBACWithKV</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">applicationFunctionAppDeploy</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">vaultFunctionAppRegSecret</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">applicationFunctionAppDeploy</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 Function App using <a href="https://learn.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-authsettingsv2?pivots=deployment-language-bicep">ARM/Bicep Template AuthSettingsV2</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;-webkit-text-size-adjust:none;"><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 Function 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@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;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">applicationFunctionAppDeploy</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;Return401&#39;</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">functionAppEasyAuthClientId</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></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></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>EasyAuth is managed by the AppService, and for an incoming request, it is a hop that comes before FA Runtime. When EasyAuth is enabled for a Function App, all incoming requests are validated against the policies in your V2 Auth settings.</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;-webkit-text-size-adjust:none;"><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>
</ol>
<h2 id="summary">Summary</h2>
<p>In short, we have applied further governance on our Function 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/Function-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>
]]></content:encoded></item><item><title>Azure API Management | Function App Backend</title><link>https://andrewilson.co.uk/post/2024/10/function-app-apim-backend/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/10/function-app-apim-backend/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/Andrew-D-Wilson/Function-App-APIM-Backend"&gt;
&lt;img src="https://img.shields.io/badge/Repo-Function--App--APIM--Backend-blue?logo=github&amp;amp;style=for-the-badge" alt="GitHub Repository"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Following on from a previous set of posts from earlier this year where I detailed how to securely implement Logic App Standard backends in Azure API Management, there has been questions on how this would be achieved in a similar manner with Azure Function Apps.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;To read-up on how this was achieved with Standard Logic Apps have a look at the following:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://andrewilson.co.uk/post/2024/01/standard-logic-app-apim-backend/"&gt;Azure API Management | Logic App (Standard) Backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://andrewilson.co.uk/post/2024/02/standard-logic-app-apim-backend-swagger/"&gt;Azure API Management | Logic App (Standard) Backend Using a Swagger Definition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://andrewilson.co.uk/post/2024/02/standard-logic-app-easy-auth-apim/"&gt;Easy Auth | Standard Logic App with Azure API Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At a high level comparison with Azure Logic Apps, Azure Functions are a developer-centric serverless compute offering allowing authors to write code in languages such as C#, Java, Javascript, Python, and PowerShell. Azure Functions are best suited for stateless computation and application specific tasks.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p><a href="https://github.com/Andrew-D-Wilson/Function-App-APIM-Backend">
  <img src="https://img.shields.io/badge/Repo-Function--App--APIM--Backend-blue?logo=github&amp;style=for-the-badge" alt="GitHub Repository">

</a></p>
<p>Following on from a previous set of posts from earlier this year where I detailed how to securely implement Logic App Standard backends in Azure API Management, there has been questions on how this would be achieved in a similar manner with Azure Function Apps.</p>
<p><em>To read-up on how this was achieved with Standard Logic Apps have a look at the following:</em></p>
<ul>
<li><a href="/post/2024/01/standard-logic-app-apim-backend/">Azure API Management | Logic App (Standard) Backend</a></li>
<li><a href="/post/2024/02/standard-logic-app-apim-backend-swagger/">Azure API Management | Logic App (Standard) Backend Using a Swagger Definition</a></li>
<li><a href="/post/2024/02/standard-logic-app-easy-auth-apim/">Easy Auth | Standard Logic App with Azure API Management</a></li>
</ul>
<p>At a high level comparison with Azure Logic Apps, Azure Functions are a developer-centric serverless compute offering allowing authors to write code in languages such as C#, Java, Javascript, Python, and PowerShell. Azure Functions are best suited for stateless computation and application specific tasks.</p>
<p>Azure Logic Apps are similar in that they too are a serverless offering but more specifically built as a workflow integration platform. It&rsquo;s a low code/no code user-friendly development option for designing workflows, integrating different systems, and building business process automation.</p>
<p>Given that Standard Logic Apps share the same compute platform as Azure Function Apps, some of what this post will aim to achieve will be similar to that achieved with the posts highlighted above, but with enough differences that I would suggest reading on.</p>
<p>The method explored here (<em>Linking a Azure Function App as an APIM API Backend</em>) aims to be configurable (<em>Both in Deployment and API setup</em>), and secure; ensuring Principal of Least Privilege (PoLP). The diagram below provides an overview of what is to be achieved:</p>
<p>
  <img src="/images/posts/2024/10/AzureAPIManagement-FunctionAppOverview.png" alt="Overview">

</p>
<p>The overall design aims to abstract the backend from the API Operations, i.e. the backend points to the Azure Function App and the individual operations point to the respective HTTP triggered functions. The design also specifies granular access to the Function specific Shared-Access-Signature (SAS) key as opposed to the Function App SAS key. Providing access to the Function App Host or Admin key is simpler in deployment configuration but has a security concern in allowing access to any Function within the Function App. By utilising the specific Function host SAS key means that only specific access is granted; following in principal of least privilege and lessening the blast radius if a breach of security were to occur. Further to this, the Function SAS key will be held in the applications specific KeyVault where access to this secret will be conducted over Role Based Access Control (RBAC) restricted to the specific secret (again following PoLP). <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>.</p>
<p>As with my previous posts, 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/10/AzureAPIManagement-FunctionAppAppDeployment.png" alt="ApplicationDeployment">

</p>
<p>The deployment is split into three stages:</p>
<ol>
<li>Deploy the Core Application Components.</li>
<li>Deploy the Functions to the recently deployed Function App.</li>
<li>Store the Function specific SAS keys in KeyVault for later secure access.</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;-webkit-text-size-adjust:none;"><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">Deploy</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">// ** 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">funcApplicationAppServicePlanName</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">funcStorageAccountName</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">applicationFunctionAppName</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">func&#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 Function 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">funcAppServicePlanDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/serverfarms@2023-12-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">funcApplicationAppServicePlanName</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;Y1&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tier</span>: <span style="color:#f1fa8c">&#39;Dynamic&#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></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 Function 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">funcStorageAccountDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Storage/storageAccounts@2023-05-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">funcStorageAccountName</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 Function 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">applicationFunctionAppDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2023-12-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">applicationFunctionAppName</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&#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">funcAppServicePlanDeploy</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;dotnet&#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">funcStorageAccountDeploy</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">funcStorageAccountDeploy</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">funcStorageAccountDeploy</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">funcStorageAccountDeploy</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">funcStorageAccountDeploy</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:#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">applicationFunctionAppName</span> <span style="color:#8be9fd;font-style:italic">string</span>  = <span style="color:#8be9fd;font-style:italic">applicationFunctionAppName</span>
</span></span></code></pre></div><p><strong>Step 2</strong> is the deployment of the Functions such as this simple C# Hello World 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;-webkit-text-size-adjust:none;"><code class="language-C#" data-lang="C#"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">using</span> ...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">namespace</span> HelloWorldFunctions
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">public</span> <span style="color:#8be9fd;font-style:italic">static</span> <span style="color:#ff79c6">class</span> <span style="color:#50fa7b">HelloWorld</span>
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span><span style="color:#50fa7b">        [FunctionName(&#34;HelloWorld&#34;)]</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">public</span> <span style="color:#8be9fd;font-style:italic">static</span> <span style="color:#8be9fd;font-style:italic">async</span> Task&lt;IActionResult&gt; Run(
</span></span><span style="display:flex;"><span><span style="color:#50fa7b">            [HttpTrigger(AuthorizationLevel.Function, &#34;get&#34;, &#34;post&#34;, Route = null)]</span> HttpRequest req,
</span></span><span style="display:flex;"><span>            ILogger log)
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            log.LogInformation(<span style="color:#f1fa8c">&#34;C# HTTP trigger function processed a request.&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd">string</span> name = req.Query[<span style="color:#f1fa8c">&#34;name&#34;</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd">string</span> requestBody = <span style="color:#ff79c6">await</span> <span style="color:#ff79c6">new</span> StreamReader(req.Body).ReadToEndAsync();
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd">dynamic</span> data = JsonConvert.DeserializeObject(requestBody);
</span></span><span style="display:flex;"><span>            name = name ?? data?.name;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd">string</span> responseMessage = <span style="color:#8be9fd">string</span>.IsNullOrEmpty(name)
</span></span><span style="display:flex;"><span>                ? <span style="color:#f1fa8c">&#34;This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.&#34;</span>
</span></span><span style="display:flex;"><span>                : <span style="color:#f1fa8c">$&#34;Hello, {name}. This HTTP triggered function executed successfully.&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">return</span> <span style="color:#ff79c6">new</span> OkObjectResult(responseMessage);
</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><strong>Step 3</strong> demonstrated below takes a number of functions, retrieves their SAS keys and creates them as secrets in the Application KeyVault.</p>
<blockquote>
<p><strong>Note</strong>: To obtain the Function specific SAS key, the Function must have already been deployed to the Function App.</p>
</blockquote>
<p>The following Bicep is used to obtain the Function specific SAS key:
<code>listKeys(resourceId('Microsoft.Web/sites/functions', applicationFunctionAppName, function),'2023-12-01').default</code></p>
<blockquote>
<p>⚠️ <strong>Important</strong></p>
<p>This implementation utilises the default Function SAS key, so special consideration should be taken in your own implementation regarding SAS expiration, revocation, and rotation.</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;-webkit-text-size-adjust:none;"><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:#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">// ** 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 Function 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">applicationFunctionAppName</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 functions in the function app to add secrets for&#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">functions</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:#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 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 Functions 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">vaultFunctionsKey</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">function</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">functions</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">applicationFunctionAppName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">function</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#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;FunctionApp&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">applicationFunctionAppName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">function</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">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">listKeys</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Web/sites/functions&#39;</span>, <span style="color:#8be9fd;font-style:italic">applicationFunctionAppName</span>, <span style="color:#8be9fd;font-style:italic">function</span>),<span style="color:#f1fa8c">&#39;2023-12-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">default</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 Function App backend API have been deployed.</p>
<p>
  <img src="/images/posts/2024/10/AzureAPIManagement-FunctionAppAPIDeployment.png" alt="APIDeployment">

</p>
<p>The deployment is split into two stages:</p>
<ol>
<li>Deploy an API Management Service Instance.</li>
<li>Deploy respective Backend, Named Values, API, API Operations, and Policies.</li>
</ol>
<p>The deployment of the API and its operations pointing at the Azure Function 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 SAS Key secrets.</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. Setting up the Backend means that we can abstract backend service information, promoting reusability and improved governance.</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;-webkit-text-size-adjust:none;"><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:#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">// ** 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.
Further to this, the Function operations are defined within a JSON control file so that the Bicep templates can remain agnostic to operation implementation. The JSON control file also allows the definition of multiple API operations per Function due to a function allowing multiple HTTP Methods such as GET and POST.</p>
<p>The structure of the operations within the Control file allow for APIM to provide a different Operation name to that specified on the backend such as:</p>
<ul>
<li>APIM /HWGET &ndash;&gt; Function /HellowWorld</li>
</ul>
<p>Each Operation will also detail which Function it is associated with as to utilise the correct Named Value in APIM containing reference to KeyVault Function SaS Key.</p>
<p>The JSON Control file 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;-webkit-text-size-adjust:none;"><code class="language-JSON" data-lang="JSON"><span style="display:flex;"><span>[
</span></span><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;HelloWorldGet&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;backendFunctionName&#34;</span>: <span style="color:#f1fa8c">&#34;HelloWorld&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;rewriteUrl&#34;</span>: <span style="color:#f1fa8c">&#34;/HelloWorld&#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;displayName&#34;</span>: <span style="color:#f1fa8c">&#34;Hello World GET&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;method&#34;</span>: <span style="color:#f1fa8c">&#34;GET&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;urlTemplate&#34;</span>: <span style="color:#f1fa8c">&#34;/HWGET&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;description&#34;</span>: <span style="color:#f1fa8c">&#34;Hello World GET&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;templateParameters&#34;</span>: [],
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;request&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;queryParameters&#34;</span>: [
</span></span><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;name&#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;required&#34;</span>: <span style="color:#ff79c6">false</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;headers&#34;</span>: []
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;responses&#34;</span>: [
</span></span><span style="display:flex;"><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></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;name&#34;</span>: <span style="color:#f1fa8c">&#34;HelloWorldPost&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;backendFunctionName&#34;</span>: <span style="color:#f1fa8c">&#34;HelloWorld&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;rewriteUrl&#34;</span>: <span style="color:#f1fa8c">&#34;/HelloWorld&#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;displayName&#34;</span>: <span style="color:#f1fa8c">&#34;Hello World POST&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;method&#34;</span>: <span style="color:#f1fa8c">&#34;POST&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;urlTemplate&#34;</span>: <span style="color:#f1fa8c">&#34;/HWPOST&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;description&#34;</span>: <span style="color:#f1fa8c">&#34;Hello World POST&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;templateParameters&#34;</span>: [],
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;request&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;queryParameters&#34;</span>: [],
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;headers&#34;</span>: []
</span></span><span style="display:flex;"><span>            },
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;responses&#34;</span>: [
</span></span><span style="display:flex;"><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></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 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;-webkit-text-size-adjust:none;"><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">Function</span> <span style="color:#8be9fd;font-style:italic">App</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:#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">// ** 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 Function 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">functionAppName</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:#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">// Function 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">funcBaseUrl</span> = <span style="color:#f1fa8c">&#39;https://</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">functionApp</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">// Operation List and Details</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimApiOperations</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;apimApiConfigurations/helloWorldApiOperationsConfiguration.json&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Obtain single distinct list of functions used in operations </span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">allFunction</span> = <span style="color:#50fa7b">map</span>(<span style="color:#8be9fd;font-style:italic">apimApiOperations</span>, <span style="color:#8be9fd;font-style:italic">op</span> =&gt; <span style="color:#8be9fd;font-style:italic">op</span>.<span style="color:#8be9fd;font-style:italic">backendFunctionName</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">uniqueFunctions</span> = <span style="color:#50fa7b">union</span>(<span style="color:#8be9fd;font-style:italic">allFunction</span>, <span style="color:#8be9fd;font-style:italic">allFunction</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 Function 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">functionAppAPI</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 Function 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">functionApp</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">functionAppName</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 function App API operations&#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">functionAppAPIOperation</span> <span style="color:#f1fa8c">&#39;Modules/apimOperation.azuredeploy.bicep&#39;</span> = [
</span></span><span style="display:flex;"><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">functionAppAPI</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">apiManagementApiOperationDefinition</span>: <span style="color:#8be9fd;font-style:italic">operation</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 function app func 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">vaultFunctionAppKey</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></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">for</span> <span style="color:#8be9fd;font-style:italic">function</span> <span style="color:#8be9fd;font-style:italic">in</span> <span style="color:#8be9fd;font-style:italic">uniqueFunctions</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">functionAppName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">function</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#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></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Grant APIM Key Vault Reader for the function 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></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">for</span> (<span style="color:#8be9fd;font-style:italic">function</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">uniqueFunctions</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">function</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">scope</span>: <span style="color:#8be9fd;font-style:italic">vaultFunctionAppKey</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></span><span style="display:flex;"><span>        <span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleDefinitions&#39;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefinitionId</span>
</span></span><span style="display:flex;"><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></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the named values for the function app API keys&#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">functionAppBackendNamedValues</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/namedValues@2022-08-01&#39;</span> = [
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">for</span> (<span style="color:#8be9fd;font-style:italic">function</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">uniqueFunctions</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">function</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#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">function</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#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;key&#39;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f1fa8c">&#39;functionApp&#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">function</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">vaultFunctionAppKey</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></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the backend for the Function 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">functionAppBackend</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">funcBaseUrl</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">functionApp</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 function App API and all its operations - linking the function 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">functionAppAPIAllOperationsPolicy</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">functionAppAPI</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">functionAppBackend</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></span><span style="display:flex;"><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">functionAppAPI</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">functionRelativePath</span>: <span style="color:#8be9fd;font-style:italic">operation</span>.<span style="color:#8be9fd;font-style:italic">rewriteUrl</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">key</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">backendFunctionName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key}}&#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">functionAppAPIOperation</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></code></pre></div><p>The APIM All Operations Policy template provides the link to the APIM Function App Backend as shown below:</p>
<blockquote>
<p>The Delete 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;-webkit-text-size-adjust:none;"><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:#ff79c6">&lt;set-backend-service</span> <span style="color:#50fa7b">id=</span><span style="color:#f1fa8c">&#34;functionapp-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 used to conduct a uri rewrite to point to the specific Function backend as defined in the JSON Control file. The Policy also appends the Function specific SAS Key &ldquo;code&rdquo; Named Value ref to the query parameter set. The actual value is obtained on invocation from 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;-webkit-text-size-adjust:none;"><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;code&#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>__key__<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 makes use of Bicep User Defined Types to conduct validation of the Operation Control JSON 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;-webkit-text-size-adjust:none;"><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:#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:#6272a4">// TYPES: APIM API Operation</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// - API Operation Definition</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// - Query Parameter</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// - Template Parameter</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// - Header</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// - Response</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;APIM API Operation Definition&#39;</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">apiOperationDefinition</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:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">80</span>)
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The resource name&#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">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The backend function name&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">backendFunctionName</span>: <span style="color:#8be9fd;font-style:italic">string</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:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">1000</span>)
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Relative URL rewrite template for the Function backend (in policy).&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">rewriteUrl</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Properties of the Operation Contract&#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:#50fa7b">minLength</span>(<span style="color:#8be9fd;font-style:italic">1</span>)
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">300</span>)
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Operation Name.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;A Valid HTTP Operation Method. Typical Http Methods like GET, PUT, POST but not limited by only them.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">method</span>: <span style="color:#8be9fd;font-style:italic">string</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:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">1000</span>)
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Relative URL template identifying the target resource for this operation. May include parameters. Example: /customers/{cid}/orders/{oid}/?date={date}&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">urlTemplate</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">1000</span>)
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Description of the operation. May include HTML formatting tags.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">description</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Collection of URL template parameters.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">templateParameters</span>: <span style="color:#8be9fd;font-style:italic">templateParameter</span>[]?
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;An entity containing request details.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">request</span>: {
</span></span><span style="display:flex;"><span>      @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Collection of operation request query parameters.&#39;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">queryParameters</span>: <span style="color:#8be9fd;font-style:italic">queryParameter</span>[]?
</span></span><span style="display:flex;"><span>      @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Collection of operation request headers.&#39;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">headers</span>: <span style="color:#8be9fd;font-style:italic">header</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 Operation responses.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">responses</span>: <span style="color:#8be9fd;font-style:italic">response</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">export</span>()
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">queryParameter</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Parameter name.&#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">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Parameter type.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Specifies whether parameter is required or not.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">required</span>: <span style="color:#8be9fd;font-style:italic">bool</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">export</span>()
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">templateParameter</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Parameter name.&#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">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Parameter type.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Specifies whether parameter is required or not.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">required</span>: <span style="color:#8be9fd;font-style:italic">bool</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">export</span>()
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">header</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Header name.&#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">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Header type.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Specifies whether header is required or not.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">required</span>: <span style="color:#8be9fd;font-style:italic">bool</span>?
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Header values.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">values</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">export</span>()
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">type</span> <span style="color:#8be9fd;font-style:italic">response</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Operation response HTTP status code.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">statusCode</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></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;Definition of the operation to create&#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">apiManagementApiOperationDefinition</span> <span style="color:#8be9fd;font-style:italic">apiOperationDefinition</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;Deploy function 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">functionAppAPIGetOperation</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">apiManagementApiOperationDefinition</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">properties</span>: <span style="color:#8be9fd;font-style:italic">apiManagementApiOperationDefinition</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></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;-webkit-text-size-adjust:none;"><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">FUNC</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:#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">// ** 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 function relative 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">functionRelativePath</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 named value name for the workflow key&#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">key</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;&#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">policyURI</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">rawPolicy</span>, <span style="color:#f1fa8c">&#39;__uri__&#39;</span>, <span style="color:#8be9fd;font-style:italic">functionRelativePath</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">policyKEY</span> = <span style="color:#50fa7b">replace</span>(<span style="color:#8be9fd;font-style:italic">policyURI</span>, <span style="color:#f1fa8c">&#39;__key__&#39;</span>, <span style="color:#8be9fd;font-style:italic">key</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">policyKEY</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>Hope this helps, and have fun.</p>
]]></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>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend"&gt;
&lt;img src="https://img.shields.io/badge/Repo-Standard--Logic--App--APIM--Backend-blue?logo=github&amp;amp;style=for-the-badge" alt="GitHub Repository"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After setting up a &lt;a href="https://andrewilson.co.uk/post/2024/01/standard-logic-app-apim-backend/"&gt;Logic App (Standard) Backend in Azure API Management (APIM)&lt;/a&gt; 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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you haven&amp;rsquo;t already I would recommend reading my previous &lt;a href="https://andrewilson.co.uk/post/2024/01/standard-logic-app-apim-backend/"&gt;&lt;strong&gt;post&lt;/strong&gt;&lt;/a&gt; as this one will be working off of the building blocks of the last.&lt;/p&gt;</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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/Andrew-D-Wilson/Standard-Logic-App-APIM-Backend"&gt;
&lt;img src="https://img.shields.io/badge/Repo-Standard--Logic--App--APIM--Backend-blue?logo=github&amp;amp;style=for-the-badge" alt="GitHub Repository"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Updated [31/01/2024]: See&lt;/code&gt; &lt;a href="https://andrewilson.co.uk/post/2024/02/standard-logic-app-apim-backend-swagger/"&gt;New Post&lt;/a&gt; &lt;code&gt;showing methods of linking a Logic App Standard as a Backend to APIM through a Swagger Definition.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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 &lt;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."&gt;directly importing a Logic App (Standard) workflow is not available, only in consumption.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;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:
&lt;img src="https://andrewilson.co.uk/images/posts/2024/01/Overview.png" alt="Overview"&gt;
&lt;/p&gt;</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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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;-webkit-text-size-adjust:none;"><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>Azure API Management | Unintentional Pass through of Subscription Key Header</title><link>https://andrewilson.co.uk/post/2023/11/apim-subscription-key-header/</link><pubDate>Tue, 21 Nov 2023 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2023/11/apim-subscription-key-header/</guid><description>&lt;h2 id="problem-space"&gt;Problem Space&lt;/h2&gt;
&lt;p&gt;There is a potential unintentional side effect when you add a &lt;a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-subscriptions"&gt;APIM subscription key&lt;/a&gt; as a header to an inbound request. The header is not stripped from the request prior to being sent to the configured backend service. Rather it is retained.&lt;/p&gt;
&lt;p&gt;If you manage the backing service and are not concerned with the disclosure of the subscription key, then no problem. &lt;strong&gt;However&lt;/strong&gt;, being overly permissive of this information may make your API more vulnerable to security threats and disallows a separation of concerns.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>There is a potential unintentional side effect when you add a <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-subscriptions">APIM subscription key</a> as a header to an inbound request. The header is not stripped from the request prior to being sent to the configured backend service. Rather it is retained.</p>
<p>If you manage the backing service and are not concerned with the disclosure of the subscription key, then no problem. <strong>However</strong>, being overly permissive of this information may make your API more vulnerable to security threats and disallows a separation of concerns.</p>
<p>The more concerning of the options is where you are using a backing service that is outside of your control, and the backing service being potentially vulnerable to security threats that you are not in a position to manage.</p>
<blockquote>
<p><strong>General Rule of Thumb</strong> : Prevent <em><strong>ANY</strong></em> overly permissive configurations that will make your APIs more vulnerable to security threats.</p>
</blockquote>
<h2 id="solution">Solution</h2>
<p>To strip the header out of the outbound request we can make use of <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-policies">APIM Policies</a>, more specifically the <a href="https://learn.microsoft.com/en-us/azure/api-management/set-header-policy">set-header 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;-webkit-text-size-adjust:none;"><code class="language-xml" data-lang="xml"><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-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>Make sure that the header name is set to the name you have used for your subscription key header, <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-subscriptions#use-a-subscription-key">by default</a> this is set to <em>Ocp-Apim-Subscription-Key</em>.</p>
<p>Lastly, this is not a policy that you have to provide per API Operation, but can be placed at the respective <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-policies#scopes">scope</a> at which you have enabled APIM Subscriptions.</p>
]]></content:encoded></item><item><title>Azure API Management | Product Required Subscription Behaviours</title><link>https://andrewilson.co.uk/post/2022/12/apim-product-required-subscription-behaviours/</link><pubDate>Tue, 20 Dec 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/12/apim-product-required-subscription-behaviours/</guid><description>&lt;h2 id="background--functional-workings-of-apim-subscriptions"&gt;Background | Functional Workings of APIM Subscriptions&lt;/h2&gt;
&lt;p&gt;Subscriptions are a nice and easy method of securing your APIs in APIM, however as I bumped into a small detail around their use the other day, I thought it wise to note it down.&lt;/p&gt;
&lt;p&gt;Azure API Management Subscriptions operate at &lt;strong&gt;three&lt;/strong&gt; scope levels:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;All APIs&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Applies to any API that requires a Subscription.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;As this will allow access to &lt;strong&gt;ANY&lt;/strong&gt; api, use this with caution.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specific APIs&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;These subscriptions are linked to specific APIs, and their keys can only be used by those APIs.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;An API with a Specific subscription, as mentioned above, can be called with a generic All APIs Subscription Key.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Products&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Products are independent of APIs and therefore have their own &amp;lsquo;&lt;em&gt;Subscription Required&lt;/em&gt;&amp;rsquo; setting and behaviours. &lt;em&gt;See Problem Space below.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="problem-space"&gt;Problem Space&lt;/h2&gt;
&lt;p&gt;As mentioned above, because Products are independent of APIs, their subscriptions operate slightly differently and &lt;strong&gt;can cause some ill effects if unknown&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="background--functional-workings-of-apim-subscriptions">Background | Functional Workings of APIM Subscriptions</h2>
<p>Subscriptions are a nice and easy method of securing your APIs in APIM, however as I bumped into a small detail around their use the other day, I thought it wise to note it down.</p>
<p>Azure API Management Subscriptions operate at <strong>three</strong> scope levels:</p>
<ol>
<li><strong>All APIs</strong>
<ul>
<li>Applies to any API that requires a Subscription.</li>
<li><em>As this will allow access to <strong>ANY</strong> api, use this with caution.</em></li>
</ul>
</li>
<li><strong>Specific APIs</strong>
<ul>
<li>These subscriptions are linked to specific APIs, and their keys can only be used by those APIs.</li>
<li><em>An API with a Specific subscription, as mentioned above, can be called with a generic All APIs Subscription Key.</em></li>
</ul>
</li>
<li><strong>Products</strong>
<ul>
<li>Products are independent of APIs and therefore have their own &lsquo;<em>Subscription Required</em>&rsquo; setting and behaviours. <em>See Problem Space below.</em></li>
</ul>
</li>
</ol>
<h2 id="problem-space">Problem Space</h2>
<p>As mentioned above, because Products are independent of APIs, their subscriptions operate slightly differently and <strong>can cause some ill effects if unknown</strong>.</p>
<p>The following behaviours can be observed:</p>
<hr>
<ol>
<li>
<blockquote>
<ul>
<li>API Subscription <strong>Required</strong> | Product Subscription <strong>NOT</strong> Required:
<ul>
<li>The API can now be accessed <strong>without</strong> a Subscription.</li>
<li>If a Subscription is provided it can only be from:
<ul>
<li>All APIs Scoped Subscription Keys</li>
<li>The Products Subscription Keys</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</li>
</ol>
<hr>
<ol start="2">
<li>
<blockquote>
<ul>
<li>API <strong>Specific</strong> Subscription <strong>Required</strong> | Product Subscription <strong>NOT</strong> Required:
<ul>
<li>The API can now be accessed <strong>without</strong> a Subscription.</li>
<li>If a Subscription is provided it can be from:
<ul>
<li><strong>All three</strong> scoped Subscription Keys.</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</li>
</ol>
<hr>
<ol start="3">
<li>
<blockquote>
<ul>
<li>API Subscription <strong>Required</strong> | Product Subscription <strong>Required</strong>:
<ul>
<li>The API <strong>Requires</strong> a Subscription key from either:
<ul>
<li>All APIs Scoped Subscription Keys</li>
<li>The Products Subscription Keys</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</li>
</ol>
<hr>
<ol start="4">
<li>
<blockquote>
<ul>
<li>API <strong>Specific</strong> Subscription <strong>Required</strong> | Product Subscription <strong>Required</strong>:
<ul>
<li>The API <strong>Requires</strong> a Subscription key from <strong>any of the three</strong> Subscription scopes.</li>
</ul>
</li>
</ul>
</blockquote>
</li>
</ol>
<hr>
<ol start="5">
<li>
<blockquote>
<ul>
<li>API Subscription <strong>NOT</strong> Required | Product Subscription <strong>Required</strong>:
<ul>
<li>The API can now be accessed <strong>without</strong> a Subscription.</li>
</ul>
</li>
</ul>
</blockquote>
</li>
</ol>
<h2 id="summary">Summary</h2>
<p>Be very careful with the way you configure your subscription requirements. The only setup with a Product Subscription that will demand your API to require a subscription key is (<strong>setup 3 and 4</strong>).</p>
<p>All other setup options (1, 2, and 5) will leave your API open to be called without a subscription key.</p>
]]></content:encoded></item><item><title>Azure API Management | Subscription Contract Names</title><link>https://andrewilson.co.uk/post/2022/12/apim-subscription-contract-name/</link><pubDate>Tue, 20 Dec 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/12/apim-subscription-contract-name/</guid><description>&lt;h2 id="problem-space"&gt;Problem Space&lt;/h2&gt;
&lt;p&gt;Subscriptions are a nice and easy method of securing your APIs in APIM, however as I bumped into a small detail around their use the other day, I thought it wise to note it down.&lt;/p&gt;
&lt;p&gt;When a Subscription Key is required on an API, as an invoker I will need to provide either a Header or a Parameter to my request which will contain the Subscription Key.&lt;/p&gt;
&lt;p&gt;By default:&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>Subscriptions are a nice and easy method of securing your APIs in APIM, however as I bumped into a small detail around their use the other day, I thought it wise to note it down.</p>
<p>When a Subscription Key is required on an API, as an invoker I will need to provide either a Header or a Parameter to my request which will contain the Subscription Key.</p>
<p>By default:</p>
<ul>
<li>The <strong>Header</strong> is as follows:
<ul>
<li><strong>Ocp-Apim-Subscription-Key</strong>: SubscriptionKey</li>
</ul>
</li>
<li>The Query Parameter is as follows:
<ul>
<li>?<strong>subscription-key</strong>=SubscriptionKey</li>
</ul>
</li>
</ul>
<p>This being said, Azure does also allow you to override these Header and Query Parameter names.</p>
<h3 id="azure-portal">Azure Portal</h3>
<p>To view or change these Subscription Contract Names in the <a href="https://portal.azure.com/">Azure Portal</a>, <em>navigate through to your APIM instance - APIs - Select the API you wish to view/change - Select Settings</em>.</p>
<p>As can be seen by the image below, the header and query parameter name is shown and editable under the Subscription Header in the Portal.</p>
<p>
  <img src="/images/posts/2022/12/SubscriptionContractNamesPortal.png" alt="SubscriptionContractNamesPortal">

</p>
<h3 id="iac--bicep">IaC | Bicep</h3>
<p>When defining your API Management Service APIs in Bicep, there is a property called <strong>subscriptionKeyParameterNames</strong> which defines the <a href="https://learn.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/apis?pivots=deployment-language-bicep#subscriptionkeyparameternamescontract">contract names for your Subscription Header and Query Parameter</a></p>
<p>The Bicep Template will look similar to the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bicep" data-lang="bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">symbolicname</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis@2021-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;string&#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">resourceSymbolicName</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">subscriptionRequired</span> = <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>		<span style="color:#8be9fd;font-style:italic">subscriptionKeyParameterNames</span>: {
</span></span><span style="display:flex;"><span>			<span style="color:#8be9fd;font-style:italic">header</span>: <span style="color:#f1fa8c">&#39;mySubscriptionHeaderName&#39;</span>
</span></span><span style="display:flex;"><span>			<span style="color:#8be9fd;font-style:italic">query</span>: <span style="color:#f1fa8c">&#39;myQueryParameterSubscriptionName&#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></code></pre></div>]]></content:encoded></item><item><title>Azure API Management | API Mocking</title><link>https://andrewilson.co.uk/post/2022/09/apim-api-mocking/</link><pubDate>Sun, 18 Sep 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/09/apim-api-mocking/</guid><description>&lt;h3 id="problem-space"&gt;Problem Space:&lt;/h3&gt;
&lt;p&gt;I have been recently looking into setting up some APIs within API Management. I do not currently have any backing services to hook the API&amp;rsquo;s to and I would like to decouple development of the front end systems from the backend. Thankfully Azure API Management has provided the ability to create mocks for your API&amp;rsquo;s. In this post I will be walking through API mocking and how to achieve this within Bicep Templates for deployment.&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="problem-space">Problem Space:</h3>
<p>I have been recently looking into setting up some APIs within API Management. I do not currently have any backing services to hook the API&rsquo;s to and I would like to decouple development of the front end systems from the backend. Thankfully Azure API Management has provided the ability to create mocks for your API&rsquo;s. In this post I will be walking through API mocking and how to achieve this within Bicep Templates for deployment.</p>
<h3 id="azure-api-management-mocking">Azure API Management mocking</h3>
<p><a href="https://docs.microsoft.com/en-us/azure/api-management/mock-api-responses?tabs=azure-portal">Mocking APIs</a> within APIM has been made super simple and configurable. The mocks that you setup will be split into two parts:</p>
<ol>
<li>Mock sample data and return type.</li>
<li>Mock enablement.</li>
</ol>
<p>The split has been made so that you can have multiple mock samples configured and then enable the ones that you wish to run. We will look into each component separately.</p>
<h3 id="setting-up-mock-sample-data">Setting up mock sample data</h3>
<p>APIM will allow you to setup multiple mock responses but only one per response status code as the mocks samples are identified by their response status codes.</p>
<p>Currently, if you setup multiple samples, only the first sample will only ever be returned.</p>
<p>Mock Samples can be setup for each API within the <code>Operation frontend</code>. The Mock responses and samples can be found under <code>Responses</code>.</p>
<h3 id="enabling-api-mocks">Enabling API mocks</h3>
<p>Mocks are enabled within the <a href="https://docs.microsoft.com/en-us/azure/api-management/api-management-advanced-policies#mock-response">APIM policy</a> blocks:</p>
<ul>
<li>Policy sections: inbound, outbound, on-error</li>
<li>Policy scopes: all scopes
<ul>
<li>Global - All APIs</li>
<li>Product</li>
<li>API - All Operations</li>
<li>API - Individual Operation</li>
</ul>
</li>
</ul>
<h4 id="policy-block-sample">Policy Block Sample</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-xml" data-lang="xml"><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;mock-response</span> <span style="color:#50fa7b">status-code=</span><span style="color:#f1fa8c">&#34;200&#34;</span> <span style="color:#50fa7b">content-type=</span><span style="color:#f1fa8c">&#34;application/json&#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><h3 id="bicep-mock-sample-and-enablement">Bicep Mock Sample and Enablement</h3>
<p>The type of mocking that I wish to be setting up is enabled on the API operation scope and applied to the inbound policy section as shown above.
The Bicep template for this would appear 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;-webkit-text-size-adjust:none;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Configure the API Operation with the mock response sample</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">mockOperation</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis/operations@2021-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;apiOperationName&#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">apimService</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">method</span>: <span style="color:#f1fa8c">&#39;GET&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">urlTemplate</span>: <span style="color:#f1fa8c">&#39;/mockOperation&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">responses</span>: [
</span></span><span style="display:flex;"><span>      {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">statusCode</span>: <span style="color:#8be9fd;font-style:italic">200</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">description</span>: <span style="color:#f1fa8c">&#39;Mock Request&#39;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">representations</span>: [
</span></span><span style="display:flex;"><span>          {
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd;font-style:italic">contentType</span>: <span style="color:#f1fa8c">&#39;application/json&#39;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#8be9fd;font-style:italic">examples</span>: {
</span></span><span style="display:flex;"><span>              <span style="color:#8be9fd;font-style:italic">default</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;jsonMockSample.json&#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></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Configure the API Operation Policy with application/json 200 response</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">apiOperationPolicyDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/apis/operations/policies@2021-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">apiOperation</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">format</span>: <span style="color:#f1fa8c">&#39;xml&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#50fa7b">loadTextContent</span>(<span style="color:#f1fa8c">&#39;policy.xml&#39;</span>)
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Happy Mocking</p>
]]></content:encoded></item><item><title>Azure API Management | Purge Soft-Deleted Instance</title><link>https://andrewilson.co.uk/post/2022/09/apim-purge-soft-deleted-instance/</link><pubDate>Wed, 07 Sep 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/09/apim-purge-soft-deleted-instance/</guid><description>&lt;h3 id="problem-space"&gt;Problem Space:&lt;/h3&gt;
&lt;p&gt;Around June 2020 a change was made to Azure API Management whereby any deletion of the instance via the Azure portal, Azure PowerShell, Azure CLI, and REST API version &lt;code&gt;2020-06-01-preview&lt;/code&gt; or later will result in the instance being &lt;em&gt;&lt;strong&gt;soft-deleted&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is to allow for recoverability of a recently deleted API Management instance, and therefore protecting against accidental deletion of the instance.&lt;/p&gt;
&lt;p&gt;The problem with this is that not all the Azure Resource Management tooling currently supports the management of soft deleted API Management Instances. Currently the only management tooling that supports this feature are the REST API and Azure CLI. You cannot at this point in time list, show, or purge a soft deleted instance in the Management Portal or Azure PowerShell.&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="problem-space">Problem Space:</h3>
<p>Around June 2020 a change was made to Azure API Management whereby any deletion of the instance via the Azure portal, Azure PowerShell, Azure CLI, and REST API version <code>2020-06-01-preview</code> or later will result in the instance being <em><strong>soft-deleted</strong></em>.</p>
<p>This is to allow for recoverability of a recently deleted API Management instance, and therefore protecting against accidental deletion of the instance.</p>
<p>The problem with this is that not all the Azure Resource Management tooling currently supports the management of soft deleted API Management Instances. Currently the only management tooling that supports this feature are the REST API and Azure CLI. You cannot at this point in time list, show, or purge a soft deleted instance in the Management Portal or Azure PowerShell.</p>
<h3 id="solutions">Solutions</h3>
<h4 id="azure-cli">Azure CLI</h4>
<p>As of the 5th of July 2022, you can use the Azure CLI to manage soft-deleted APIM instances. <a href="https://github.com/MicrosoftDocs/azure-docs-cli/blob/main/docs-ref-conceptual/release-notes-azure-cli.md#july-05-2022">Specifically CLI version 2.38.0 and above</a>.</p>
<p>Documentation on the relative management actions that can be applied are shown <a href="https://learn.microsoft.com/en-us/cli/azure/apim/deletedservice?view=azure-cli-latest">here</a>.</p>
<p>To purge a deleted instance, you can use the following commands:</p>
<pre tabindex="0"><code class="language-Azure" data-lang="Azure">az login

az account set --subscription &#34;{SubscriptionId}&#34;

// Using the list command and query argument you can obtain the name and location of your soft deleted APIM Instances

az apim deletedservice list --query &#34;[].[name, location]&#34;

// Since you now know the name and location of all the potential instances you wish to purge, you can now issue the purge command for each instance.

az apim deletedservice purge --service-name &#34;{APIMInstanceName}&#34; --location &#34;{RegionDeployedTo}&#34;
</code></pre><h4 id="rest-api">Rest API</h4>
<p>In-order to purge a soft-deleted APIM instance, you will need to execute the <em>Delete</em> REST API for API Management as per <a href="https://docs.microsoft.com/en-us/rest/api/apimanagement/current-ga/deleted-services/purge?tabs=HTTP">Microsoft Documentation</a>.</p>
<p>To make this simpler, here is some PowerShell using the <code>2021-08-01</code> REST API version and az tooling:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><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">$Region</span> = <span style="color:#f1fa8c">&#39;{Region}&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$APIMInstanceName</span> = <span style="color:#f1fa8c">&#39;{APIMInstanceName}&#39;</span>
</span></span><span style="display:flex;"><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 style="color:#8be9fd;font-style:italic">@</span>{
</span></span><span style="display:flex;"><span>    Method = <span style="color:#f1fa8c">&#39;DELETE&#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">/providers/Microsoft.ApiManagement/locations/</span>$(<span style="color:#8be9fd;font-style:italic">$Region</span>)<span style="color:#f1fa8c">/deletedservices/</span>$(<span style="color:#8be9fd;font-style:italic">$APIMInstanceName</span>)<span style="color:#f1fa8c">?api-version=2021-08-01&#34;</span>
</span></span><span style="display:flex;"><span>    Headers = <span style="color:#8be9fd;font-style:italic">@</span>{
</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></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>]]></content:encoded></item></channel></rss>