<?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>Function App on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/tags/function-app/</link><description>Recent content in Function App on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 03 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/tags/function-app/index.xml" rel="self" type="application/rss+xml"/><item><title>Azure Function Apps | OkObjectResult Returns Empty JSON After Moving to .NET 9 Isolated Worker Runtime</title><link>https://andrewilson.co.uk/post/2025/12/azure-function-apps-okobjectresult-returning-empty-json-object/</link><pubDate>Wed, 03 Dec 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/12/azure-function-apps-okobjectresult-returning-empty-json-object/</guid><description>The Problem I recently upgraded an Azure Function from .NET 8 to .NET 9, and at the same time migrated from the in-process worker to the isolated worker model. After the upgrade, my function that returned OkObjectResult started returning an empty JSON object {} instead of the expected data.
[Function(&amp;#34;MyFunction&amp;#34;)] public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, &amp;#34;post&amp;#34;)] HttpRequest req) { var data = new MyResponse { Name = &amp;#34;Test&amp;#34;, Value = 123 }; return new OkObjectResult(data); // Returns {} instead of expected JSON } Why This Happens There are two key changes that caused this issue:</description><content:encoded><![CDATA[<h2 id="the-problem">The Problem</h2>
<p>I recently upgraded an Azure Function from .NET 8 to .NET 9, and at the same time migrated from the in-process worker to the isolated worker model. After the upgrade, my function that returned <code>OkObjectResult</code> started returning an empty JSON object <code>{}</code> instead of the expected data.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#50fa7b">[Function(&#34;MyFunction&#34;)]</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">public</span> IActionResult Run([HttpTrigger(AuthorizationLevel.Function,  <span style="color:#f1fa8c">&#34;post&#34;</span>)] HttpRequest req)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd">var</span> data = <span style="color:#ff79c6">new</span> MyResponse { Name = <span style="color:#f1fa8c">&#34;Test&#34;</span>, Value = <span style="color:#bd93f9">123</span> };
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">return</span> <span style="color:#ff79c6">new</span> OkObjectResult(data); <span style="color:#6272a4">// Returns {} instead of expected JSON</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="why-this-happens">Why This Happens</h2>
<p>There are two key changes that caused this issue:</p>
<h3 id="1-in-process-to-isolated-worker-migration">1. In-Process to Isolated Worker Migration</h3>
<p>The isolated worker process runs in a separate process from the Functions host. Unlike the in-process model, it doesn&rsquo;t inherit any configuration or serialization settings. You&rsquo;re starting with a clean slate and need to explicitly configure everything.</p>
<h3 id="2-json-serializer-change">2. JSON Serializer Change</h3>
<p>Starting with <a href="https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-3.0?view=aspnetcore-9.0#new-json-serialization">ASP.NET Core 3.0</a>, Microsoft replaced Newtonsoft.Json with System.Text.Json as the default serializer. While both serialize JSON, they have different behaviors:</p>
<ul>
<li><strong>Newtonsoft.Json</strong>: More lenient, serializes public properties and fields</li>
<li><strong>System.Text.Json</strong>: Stricter, only serializes public properties by default</li>
</ul>
<p>When using <code>OkObjectResult</code> (an ASP.NET Core MVC type) in an isolated worker, you need to explicitly configure MVC services. Without this configuration, the serialization doesn&rsquo;t work as expected.</p>
<h2 id="the-solutions">The Solutions</h2>
<p>You have two approaches to fix this, each with different trade-offs:</p>
<h3 id="option-1-use-native-isolated-worker-types-recommended">Option 1: Use Native Isolated Worker Types (Recommended)</h3>
<p>Embrace the isolated worker model by using the native types designed for it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#50fa7b">[Function(&#34;MyFunction&#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">async</span> Task&lt;HttpResponseData&gt; Run([HttpTrigger(AuthorizationLevel.Function, <span style="color:#f1fa8c">&#34;post&#34;</span>)] HttpRequestData req)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd">var</span> data = <span style="color:#ff79c6">new</span> MyResponse { Name = <span style="color:#f1fa8c">&#34;Test&#34;</span>, Value = <span style="color:#bd93f9">123</span> };
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd">var</span> response = req.CreateResponse(HttpStatusCode.OK);
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">await</span> response.WriteAsJsonAsync(data); <span style="color:#6272a4">// Uses System.Text.Json by default</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">return</span> response;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Advantages:</strong></p>
<ul>
<li><strong>Better Performance</strong>: System.Text.Json is significantly faster than Newtonsoft.Json</li>
<li><strong>Lower Costs</strong>: Reduced latency means less execution time, which directly reduces Azure Functions costs (billed per execution time)</li>
<li><strong>Lighter Dependencies</strong>: No need for additional MVC services or packages</li>
<li><strong>Future-Proof</strong>: Aligned with the modern .NET isolated worker architecture</li>
<li><strong>Native Support</strong>: Uses types specifically designed for isolated workers</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li>Requires code changes to migrate from <code>IActionResult</code> to <code>HttpResponseData</code></li>
<li>May need adjustments if you rely on specific Newtonsoft.Json features</li>
</ul>
<h3 id="option-2-add-mvc-services-with-newtonsoftjson-quick-fix">Option 2: Add MVC Services with Newtonsoft.Json (Quick Fix)</h3>
<p>If you need a quick fix or have complex serialization requirements, you can <a href="https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=ihostapplicationbuilder%2Cwindows#json-serialization-with-aspnet-core-integration">add MVC services with Newtonsoft.Json support</a> to your <code>Program.cs</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#ff79c6">using</span> Microsoft.Extensions.Hosting;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd">var</span> builder = FunctionsApplication.CreateBuilder(args);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Add MVC services and configure Newtonsoft.Json</span>
</span></span><span style="display:flex;"><span>builder.Services.AddMvc().AddNewtonsoftJson();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>builder.Build().Run();
</span></span></code></pre></div><p>You&rsquo;ll also need to add the NuGet package:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
</span></span></code></pre></div><p><strong>Advantages:</strong></p>
<ul>
<li>Minimal code changes - keeps existing <code>OkObjectResult</code> code working</li>
<li>Maintains backward compatibility with Newtonsoft.Json serialization behavior</li>
<li>Good for quick migration when you have tight deadlines</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><strong>Higher Costs</strong>: Slower serialization means longer execution time and higher Azure Functions bills</li>
<li><strong>Additional Dependencies</strong>: Requires MVC framework which adds overhead</li>
<li><strong>Technical Debt</strong>: You&rsquo;re opting back into older patterns instead of embracing the new architecture</li>
</ul>
<h2 id="which-should-you-choose">Which Should You Choose?</h2>
<p><strong>For new projects or if you can afford the refactoring time</strong>: Go with Option 1 (native types). The performance benefits and cost savings will compound over time, especially for high-traffic functions.</p>
<p><strong>For quick migrations with tight deadlines</strong>: Option 2 can get you unstuck quickly, but consider it temporary. Plan to refactor to native types when time permits.</p>
<h2 id="takeaway">Takeaway</h2>
<p>When migrating to .NET 9 isolated worker Functions, you&rsquo;re working in a fresh environment that requires explicit configuration. While adding Newtonsoft.Json gets things working quickly, embracing the native isolated worker types with System.Text.Json offers better performance and lower costs (⚠️important factors when Azure Functions are billed per execution time). Choose the approach that balances your immediate needs with long-term architecture goals.</p>
<p>Hope this helps, Happy Coding.</p>
]]></content:encoded></item><item><title>Key Vault Reference | Logic and Function Apps using User-Assigned Managed Identity</title><link>https://andrewilson.co.uk/post/2025/01/logic-and-function-app-keyvault-access-with-user-assigned-identity/</link><pubDate>Mon, 06 Jan 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/01/logic-and-function-app-keyvault-access-with-user-assigned-identity/</guid><description>Overview Prior to the Christmas break I was involved in writing some integrations that used a mixture of Logic Apps Standard and Function Apps. It was agreed as part of the architecture that user-assigned identities would be the best fit. As part of the implementation, I observed that the differences in configuration setup between system-assigned and user-assigned wasn&amp;rsquo;t widely understood. This article aims to show a brief run through of both.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>Prior to the Christmas break I was involved in writing some integrations that used a mixture of Logic Apps Standard and Function Apps. It was agreed as part of the architecture that user-assigned identities would be the best fit. As part of the implementation, I observed that the differences in configuration setup between system-assigned and user-assigned wasn&rsquo;t widely understood. This article aims to show a brief run through of both.</p>
<h2 id="setup-and-difference-with-system-assigned">Setup and Difference with System-Assigned</h2>
<p><strong>System-Assigned</strong></p>
<p>The general process when using a <em>System-Assigned identity</em> is as follows:</p>
<ol>
<li>
<p>Create a Key Vault Instance.</p>
</li>
<li>
<p>Create secrets required by the application.</p>
</li>
<li>
<p>Create the app resource (Logic App / Function App)</p>
<ul>
<li>
<p>As part of the configuration, specify the identity as System Assigned.</p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli#source-app-settings-from-key-vault">Reference the key vault secret(s)</a> in your App Settings.</p>
</li>
</ul>
</li>
<li>
<p>Authorise the applications identity read access to key vault or <a href="/post/2023/11/rbac-key-vault-specific-secret/">specifically the key vaults secret</a>.</p>
</li>
</ol>
<p>The main points with System-Assigned setup is:</p>
<ul>
<li>The identity is tied to the created app resource and its life-cycle</li>
<li>The resource cannot reference key vault secrets at the point of creation
<ul>
<li>Authorisation to read the key vault secrets has not occurred at this point</li>
</ul>
</li>
<li>The identity cannot be associated with other resources</li>
</ul>
<p><strong>User-Assigned</strong></p>
<p>The general process when using a <em>User-Assigned identity</em> is as follows:</p>
<ol>
<li>
<p>Create a Key Vault instance</p>
</li>
<li>
<p>Create secrets required by the application(s)</p>
</li>
<li>
<p>Create the user-assigned identity</p>
</li>
<li>
<p>Authorise the user-assigned identity read access to key vault or <a href="/post/2023/11/rbac-key-vault-specific-secret/">specifically the key vaults secret</a>.</p>
</li>
<li>
<p>Create the app resource (Logic App / Function App)</p>
<p>As part of the resource configuration</p>
<ul>
<li>
<p>Specify the identity as user-assigned and reference the created identity in step 3</p>
</li>
<li>
<p>Specify the identity to be used for key vault reference operations by setting the <code>keyVaultReferenceIdentity</code> property to the resource ID of the user-assigned identity</p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli#source-app-settings-from-key-vault">Reference the key vault secret(s)</a> in your App Settings.</p>
</li>
</ul>
</li>
</ol>
<p>The main points with User-Assigned setup is:</p>
<ul>
<li>The identity is managed outside the context of a resource and its life-cycle</li>
<li>A resource that uses the identity can read secrets from keyvault at the point of creation
<ul>
<li>Given that the authorisation has occurred prior to the resource creation.</li>
</ul>
</li>
<li>The identity can be associated with on or more resources</li>
</ul>
<p>⚠️ <strong>Note</strong> One of the most common gotchas [user-assigned] is missing or forgetting to specify the identity to be used for key vault reference operations (<code>keyVaultReferenceIdentity</code> property - Step 5).</p>
<p>Hope this helps and have fun.</p>
]]></content:encoded></item><item><title>Easy Auth | 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>Overview The recent work 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 best practices that you need to be abiding by. Such as:
Some Potential Risks:</description><content:encoded><![CDATA[<p><a href="https://github.com/Andrew-D-Wilson/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;"><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;"><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;"><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;"><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>Overview 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.
To read-up on how this was achieved with Standard Logic Apps have a look at the following:
Azure API Management | Logic App (Standard) Backend Azure API Management | Logic App (Standard) Backend Using a Swagger Definition Easy Auth | Standard Logic App with Azure API Management 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.</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;"><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;"><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;"><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;"><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;"><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;"><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;"><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;"><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;"><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;"><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></channel></rss>