<?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>IaC on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/tags/iac/</link><description>Recent content in IaC on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 09 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/tags/iac/index.xml" rel="self" type="application/rss+xml"/><item><title>Unit Testing Bicep Logic with BicepConsoleTTK</title><link>https://andrewilson.co.uk/post/2026/05/bicepconsolettk/</link><pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2026/05/bicepconsolettk/</guid><description>Problem Space In most Infrastructure as Code teams, Bicep quality checks start to look mature as soon as linting and deployment validation are in place. In practice, there is still a blind spot: logic-level testing of exported functions, types, and variables.
Most teams validate by deploying to a subscription and checking outcomes afterwards. That is useful, but it is also slow and expensive when what you actually want to verify is pure logic.</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>In most Infrastructure as Code teams, Bicep quality checks start to look mature as soon as linting and deployment validation are in place. In practice, there is still a blind spot: logic-level testing of exported functions, types, and variables.</p>
<p>Most teams validate by deploying to a subscription and checking outcomes afterwards. That is useful, but it is also slow and expensive when what you actually want to verify is pure logic. A shared Bicep library changes, everything still compiles, and then a downstream module fails later in a deployment pipeline because a naming function or constructor behaviour subtly changed. That is exactly the type of issue we normally catch early in application development with unit tests.</p>
<p>If you maintain shared Bicep libraries, this gap hurts quickly:</p>
<ul>
<li>Naming functions drift without anyone noticing</li>
<li>Type constructors change and break downstream modules</li>
<li>Refactors feel risky because feedback loops are too long</li>
</ul>
<p>I wanted a way to unit test Bicep logic directly, without deploying anything.</p>
<h2 id="introducing-bicepconsolettk">Introducing BicepConsoleTTK</h2>
<p>To solve that problem, I created <strong>BicepConsoleTTK</strong> (Bicep Console Test Tool Kit).</p>
<p>It is a Pester-based framework that executes Bicep expressions through the Bicep console REPL, so you can assert outputs in fast, repeatable unit tests.</p>
<p>Repository:</p>
<p><a href="https://github.com/Andrew-D-Wilson/bicep-console-test-framework">
  <img src="https://img.shields.io/badge/GitHub-Bicep--Console--TTK-181717?logo=github" alt="GitHub Repository">

</a>
<a href="https://www.powershellgallery.com/packages/BicepConsoleTTK">
  <img src="https://img.shields.io/powershellgallery/v/BicepConsoleTTK?logo=powershell&amp;label=PowerShell%20Gallery" alt="PowerShell Gallery">

</a></p>
<p>At a high level, the toolkit gives you two commands:</p>
<ul>
<li><code>Import-Bicep</code>: reads one or more Bicep files and extracts the exports you ask for</li>
<li><code>Invoke-BicepExpression</code>: runs those declarations plus your expression in <code>bicep console</code> and returns the result</li>
</ul>
<h2 id="why-this-approach-works">Why This Approach Works</h2>
<p>This lets you test Bicep logic in isolation, before template deployment.</p>
<p>Practical outcomes:</p>
<ul>
<li>Faster feedback during development</li>
<li>More confidence when refactoring shared functions</li>
<li>Cleaner CI pipelines for template libraries</li>
<li>Better separation between unit tests (logic) and integration tests (deployment)</li>
</ul>
<h2 id="features">Features</h2>
<ul>
<li>Familiar import syntax (named imports and wildcard imports)</li>
<li>Multi-file import composition with preserved order</li>
<li>Deduplication when the same member is imported multiple ways</li>
<li>Setup declarations for multi-step scenarios</li>
<li>Pipeline input support</li>
<li>Cleaner Bicep console error reporting</li>
<li>CI/CD-friendly, non-interactive execution</li>
</ul>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>PowerShell 5.1 (Desktop) or 7+</li>
<li>Pester 5.x</li>
<li>Bicep CLI 0.42.1+</li>
<li><code>bicep</code> available on your <code>PATH</code></li>
</ul>
<h2 id="installation">Installation</h2>
<h3 id="from-powershell-gallery">From PowerShell Gallery</h3>
<p><a href="https://www.powershellgallery.com/packages/BicepConsoleTTK">
  <img src="https://img.shields.io/powershellgallery/v/BicepConsoleTTK?logo=powershell&amp;label=PowerShell%20Gallery" alt="PowerShell Gallery">

</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-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Install-Module</span> -Name BicepConsoleTTK -Repository PSGallery
</span></span></code></pre></div><p>In your test file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>BeforeAll {
</span></span><span style="display:flex;"><span>	<span style="color:#8be9fd;font-style:italic">Import-Module</span> BicepConsoleTTK -Force
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="from-source">From Source</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>git clone https://github.com/<span style="color:#8be9fd;font-style:italic">Andrew-D</span>-Wilson/<span style="color:#8be9fd;font-style:italic">bicep-console</span>-test-framework.git
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Import-Module</span> <span style="color:#f1fa8c">&#34;</span><span style="color:#8be9fd;font-style:italic">$PSScriptRoot</span><span style="color:#f1fa8c">/../src/BicepConsoleTTK&#34;</span> -Force
</span></span></code></pre></div><h2 id="copilot-integration">Copilot Integration</h2>
<p>This repository ships two complementary artefacts that teach GitHub Copilot how to write BicepConsoleTTK tests.</p>
<h3 id="agent-skill-recommended">Agent Skill (Recommended)</h3>
<p>The <code>.github/skills/bicepconsolettk/SKILL.md</code> file is a GitHub Copilot agent skill. When Copilot is working in agent mode, it automatically loads this skill whenever the task is related to writing Bicep tests, injecting the full authoring guide into its context.</p>
<p>The skill is discovered automatically from <code>.github/skills/</code> in any repository that contains it.</p>
<h3 id="vs-code-instructions-file">VS Code Instructions File</h3>
<p>The <code>bicepconsolettk.instructions.md</code> file is a VS Code Copilot custom instructions file.</p>
<p>To use it in your own repository:</p>
<ol>
<li>Copy the file to <code>.github/instructions/bicepconsolettk.instructions.md</code></li>
<li>Keep <code>applyTo: &quot;**/*.Tests.ps1&quot;</code> so it is scoped to Pester test files</li>
<li>Ask Copilot to generate or refactor tests in your <code>*.Tests.ps1</code> files</li>
</ol>
<p>With both artefacts in place, Copilot gets better guidance in both agent-driven workflows and editor-scoped instruction workflows.</p>
<h2 id="usage">Usage</h2>
<h3 id="1-import-exports-from-bicep-files">1. Import exports from Bicep files</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$imports</span> = <span style="color:#8be9fd;font-style:italic">Import-Bicep</span> @(
</span></span><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;import {coreParams, newCoreParams} from &#39;</span><span style="color:#8be9fd;font-style:italic">$PSScriptRoot</span><span style="color:#f1fa8c">/../shared/Types.bicep&#39;&#34;</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;import {basicResource}             from &#39;</span><span style="color:#8be9fd;font-style:italic">$PSScriptRoot</span><span style="color:#f1fa8c">/../shared/NamingFunctions.bicep&#39;&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><h3 id="2-evaluate-an-expression">2. Evaluate an expression</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$result</span> = <span style="color:#8be9fd;font-style:italic">Invoke-BicepExpression</span> -b <span style="color:#8be9fd;font-style:italic">$imports</span> -e <span style="color:#f1fa8c">&#34;newCoreParams(&#39;uksouth&#39;, &#39;uks&#39;, &#39;prod&#39;, &#39;myapp&#39;)&#34;</span>
</span></span></code></pre></div><h3 id="3-use-setup-declarations-when-needed">3. Use setup declarations when needed</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$setupDeclarations</span> = @(
</span></span><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;var projectNameStart = &#39;hello&#39;&#34;</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;var projectNameComplete = &#39;</span><span style="color:#f1fa8c">`$</span><span style="color:#f1fa8c">{projectNameStart}world&#39;&#34;</span>,
</span></span><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;var coreParameters coreParams = newCoreParams(&#39;uksouth&#39;, &#39;uks&#39;, &#39;dev&#39;, projectNameComplete)&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">$result</span> = <span style="color:#8be9fd;font-style:italic">Invoke-BicepExpression</span> -b <span style="color:#8be9fd;font-style:italic">$imports</span> -s <span style="color:#8be9fd;font-style:italic">$setupDeclarations</span> -e <span style="color:#f1fa8c">&#34;basicResource(&#39;aks&#39;, coreParameters)&#34;</span>
</span></span></code></pre></div><h2 id="example-pester-test">Example Pester Test</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>BeforeAll {
</span></span><span style="display:flex;"><span>	<span style="color:#8be9fd;font-style:italic">Import-Module</span> BicepConsoleTTK -Force
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Describe <span style="color:#f1fa8c">&#34;Naming Functions&#34;</span> {
</span></span><span style="display:flex;"><span>	BeforeAll {
</span></span><span style="display:flex;"><span>		<span style="color:#8be9fd;font-style:italic">$script:imports</span> = <span style="color:#8be9fd;font-style:italic">Import-Bicep</span> @(
</span></span><span style="display:flex;"><span>			<span style="color:#f1fa8c">&#34;import {coreParams, newCoreParams} from &#39;</span><span style="color:#8be9fd;font-style:italic">$PSScriptRoot</span><span style="color:#f1fa8c">/../shared/Types.bicep&#39;&#34;</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#f1fa8c">&#34;import {basicResource, csResource} from &#39;</span><span style="color:#8be9fd;font-style:italic">$PSScriptRoot</span><span style="color:#f1fa8c">/../shared/NamingFunctions.bicep&#39;&#34;</span>
</span></span><span style="display:flex;"><span>		)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	It <span style="color:#f1fa8c">&#34;basicResource includes abbreviation, project, environment and location&#34;</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#8be9fd;font-style:italic">$result</span> = <span style="color:#8be9fd;font-style:italic">Invoke-BicepExpression</span> -b <span style="color:#8be9fd;font-style:italic">$script:imports</span> `
</span></span><span style="display:flex;"><span>			-e <span style="color:#f1fa8c">&#34;basicResource(&#39;aks&#39;, newCoreParams(&#39;uksouth&#39;, &#39;uks&#39;, &#39;dev&#39;, &#39;myapp&#39;))&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#8be9fd;font-style:italic">$result</span> | Should -Be <span style="color:#f1fa8c">&#34;&#39;aks-myapp-dev-uksouth&#39;&#34;</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Run tests with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">Invoke-Pester</span> -Path ./tests
</span></span></code></pre></div><h2 id="how-it-works-short-version">How It Works (Short Version)</h2>
<p><code>Import-Bicep</code> parses import strings, resolves file paths, and extracts exported declarations from source files.</p>
<p><code>Invoke-BicepExpression</code> sends those declarations and your expression into <code>bicep console</code>, captures output, and translates console noise into readable exceptions when failures occur.</p>
<p>That gives you deterministic, fast unit tests focused on logic instead of deployment orchestration.</p>
<h2 id="where-this-fits-in-your-testing-strategy">Where This Fits in Your Testing Strategy</h2>
<p>Use BicepConsoleTTK for:</p>
<ul>
<li>Function output verification</li>
<li>Naming convention enforcement</li>
<li>Shared type constructor validation</li>
<li>Regression checks during refactoring</li>
</ul>
<p>Still keep deployment/integration tests for:</p>
<ul>
<li>Resource runtime behavior</li>
<li>Policy and RBAC interactions</li>
<li>End-to-end environment validation</li>
</ul>
<p>Both layers matter. This tool improves the unit-testing layer.</p>
<h2 id="in-short">In Short</h2>
<p>BicepConsoleTTK helps you test Bicep exports the same way you test application code: quickly, repeatedly, and early.</p>
<p>If your team relies on shared Bicep libraries, this can remove a lot of friction from your delivery pipeline while increasing confidence in every change.</p>
]]></content:encoded></item><item><title>Azure Key Vault | Access Policies Removed On Deployment</title><link>https://andrewilson.co.uk/post/2026/04/azure-key-vault-access-policy-removed-on-deploy/</link><pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2026/04/azure-key-vault-access-policy-removed-on-deploy/</guid><description>⚠️ NOTE
Microsoft guidance is clear that Azure RBAC should be used for data plane authorization moving forward, instead of legacy access policies
Azure role-based access control (Azure RBAC) vs. access policies (legacy) Provide access to Key Vault keys, certificates, and secrets with Azure role-based access control Problem Space When multiple applications share a single Azure Key Vault, access policy management can become an unexpected source of deployment risk → and the root cause is easy to miss.</description><content:encoded><![CDATA[<hr>
<p>⚠️ <strong>NOTE</strong></p>
<p><code>Microsoft guidance is clear that Azure RBAC should be used for data plane authorization moving forward, instead of legacy access policies</code></p>
<blockquote>
<ul>
<li><a href="https://learn.microsoft.com/azure/key-vault/general/rbac-access-policy">Azure role-based access control (Azure RBAC) vs. access policies (legacy)</a></li>
<li><a href="https://learn.microsoft.com/azure/key-vault/general/rbac-guide">Provide access to Key Vault keys, certificates, and secrets with Azure role-based access control</a></li>
</ul>
</blockquote>
<hr>
<h2 id="problem-space">Problem Space</h2>
<p>When multiple applications share a single Azure Key Vault, access policy management can become an unexpected source of deployment risk → and the root cause is easy to miss.</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:#6272a4">// BICEP</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">KeyVaultDeploy</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2025-05-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#f1fa8c">&#39;&#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">accessPolicies</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 <code>accessPolicies</code> property on the <code>Microsoft.KeyVault/vaults</code> ARM resource is a required field. In a shared Key Vault scenario, where the vault is owned and deployed by one application, the natural thing to do is set this to an empty array as the application does not own the other applications access policies, so it does not declare them.</p>
<p>This is where the problem begins.</p>
<p>When ARM deploys the Key Vault resource with <code>accessPolicies</code> set to an empty array <code>[]</code>, it treats that as the desired state for the vault. Any access policies that existed previously (<em>including those belonging to other applications</em>) are removed.</p>
<p>Here is how the failure pattern plays out in practice:</p>
<ol>
<li><strong>Application A owns the Key Vault</strong> and deploys it with <code>accessPolicies: []</code>.</li>
<li><strong>Immediately after</strong>, Application A&rsquo;s IaC deploys its own access policies via a separate step (for example, using the <code>Microsoft.KeyVault/vaults/accessPolicies</code> child resource). Access is restored for Application A without apparent issue.</li>
<li><strong>Application B&rsquo;s access policies have been silently removed</strong> — it never re-deploys the key vault, only its own access policy step.</li>
<li><strong>Application B fails at runtime</strong> when attempting secret, key, or certificate operations — authorization errors with no obvious cause.</li>
<li><strong>Application B is re-deployed</strong>, its access policies are restored, and both applications work again — until the next time Application A&rsquo;s pipeline runs.</li>
</ol>
<p>This cycle repeats silently. Each Application A deployment is an outage for Application B, and the connection between the two is not obvious unless you know to look for it.</p>
<p>This can happen if you have the following setup:</p>
<ul>
<li>Multiple applications or pipelines sharing a Key Vault</li>
<li>The Key Vault instance deployed as part of one application&rsquo;s IaC</li>
<li>Access configured through Key Vault access policies</li>
<li>Each application&rsquo;s pipeline independently managing only its own policy entries</li>
</ul>
<h2 id="workarounds-still-using-access-policies">Workarounds (Still Using Access Policies)</h2>
<p>If moving to RBAC immediately is not possible, the following workarounds address the underlying coupling problem — but each comes with trade-offs.</p>
<h3 id="1-move-the-key-vault-to-a-core-resources-deployment">1. Move the Key Vault to a Core Resources Deployment</h3>
<p>Extract the Key Vault resource into a dedicated core infrastructure deployment, separate from any application pipeline. Application pipelines then only manage their own access policy entries against the pre-existing vault.</p>
<p>Benefits:</p>
<ul>
<li>The vault is no longer redeployed as part of application changes</li>
<li>Eliminates the empty <code>accessPolicies</code> overwrite problem</li>
<li>Makes ownership of the shared resource explicit</li>
</ul>
<p>Trade-off:</p>
<ul>
<li>When the core resources deployment runs (for environment rebuilds, configuration changes, or disaster recovery), all dependent applications will need to be re-deployed afterwards to restore their access policy entries. This creates an operational dependency that must be planned for and communicated clearly across teams.</li>
</ul>
<h3 id="2-provision-a-separate-key-vault-per-application">2. Provision a Separate Key Vault Per Application</h3>
<p>Give each application its own dedicated Key Vault, eliminating the shared resource entirely.</p>
<p>Benefits:</p>
<ul>
<li>No cross-application policy coupling — each key vault is fully owned by one application</li>
<li>Reduces blast radius of deployment mistakes</li>
<li>Cleaner isolation and tenancy boundaries</li>
</ul>
<p>Trade-offs:</p>
<ul>
<li>More key vaults to provision, monitor, rotate secrets in, and govern</li>
<li>Increases operational overhead for certificate and secret lifecycle management</li>
<li>Harder to get a unified view of secrets across the estate</li>
</ul>
<p>This option improves isolation but does not solve the root-cause pattern; it just limits the blast radius per key vault.</p>
<h2 id="the-real-solution-move-to-azure-rbac">The Real Solution: Move to Azure RBAC</h2>
<p>The correct long-term fix is to stop using access policies for Key Vault data plane authorization entirely and adopt Azure RBAC role assignments.</p>
<p>With RBAC:</p>
<ul>
<li>Role assignments are <strong>additive and independently managed</strong> — assigning a role for Application B does not affect Application A&rsquo;s assignments</li>
<li>Authorization state is managed through Azure&rsquo;s centralized RBAC model, consistent with the rest of the Azure platform</li>
<li>Microsoft explicitly recommends RBAC over access policies for new and migrating workloads</li>
</ul>
<p>The deployment pattern becomes:</p>
<ol>
<li>Deploy the Key Vault resource. The <code>accessPolicies</code> field becomes irrelevant.</li>
<li>Each application independently deploys <code>Microsoft.Authorization/roleAssignments</code> scoped to the vault for its own managed identity or service principal.</li>
<li>An application deployment wont affect another application&rsquo;s authorization.</li>
<li>A redeploy of the Key Vault resource won&rsquo;t remove existing application&rsquo;s authorizations.</li>
</ol>
<p>Practical migration approach:</p>
<ol>
<li>Enable the RBAC permission model on the Key Vault IaC (<code>enableRbacAuthorization: true</code>).</li>
<li>Map existing access policy permissions to the appropriate built-in Key Vault RBAC roles (for example <code>Key Vault Secrets User</code>, <code>Key Vault Certificates User</code>).
<ul>
<li>Assign roles to the required identities at the appropriate scope (Key Vault, Key Vault Secret/Certificate).</li>
</ul>
</li>
<li>Remove legacy access policy configuration from all IaC templates.</li>
<li>Deploy IaC and Validate application behavior against the new authorization model.</li>
</ol>
<p>Useful Microsoft documentation:</p>
<ul>
<li><a href="https://learn.microsoft.com/azure/key-vault/general/rbac-access-policy">RBAC vs access policy comparison and recommendation</a></li>
<li><a href="https://learn.microsoft.com/azure/key-vault/general/rbac-guide">RBAC implementation guidance for Key Vault</a></li>
</ul>
<h2 id="closing-thoughts">Closing Thoughts</h2>
<p>The empty <code>accessPolicies: []</code> pattern is easy to arrive at — the field is required, the application does not own the other policies, so an empty array seems reasonable. In a single-application setup it causes no problems. In a shared-vault, multi-application setup it causes silent, repeating outages that are hard to diagnose without knowing where to look.</p>
<p>The workarounds described here reduce the risk while a migration is planned, but neither fully resolves the underlying problem.</p>
<p>The right answer is Azure RBAC. Role assignments are independent, additive, and do not interfere with each other across application boundaries. Moving to RBAC removes this class of problem entirely.</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #10 | Authoring Practices</title><link>https://andrewilson.co.uk/post/2026/04/bicep-tips-and-tricks-authoring-practices/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2026/04/bicep-tips-and-tricks-authoring-practices/</guid><description>Problem Space As Bicep adoption grows, so does the complexity of the environments and teams using it. Without clear authoring practices, Bicep codebases can quickly become inconsistent, hard to maintain, and error-prone. In this post I wanted to share some practical authoring practices and anti-patterns to help you and your team write better Bicep code.
Why Define and Stick to Your Authoring Practices Defining and following authoring practices ensures:
Consistency across your codebase and team Easier onboarding for new contributors Fewer errors and less technical debt Improved maintainability and clarity Below are some key practices and common anti-patterns to consider.</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>As Bicep adoption grows, so does the complexity of the environments and teams using it. Without clear authoring practices, Bicep codebases can quickly become inconsistent, hard to maintain, and error-prone. In this post I wanted to share some practical authoring practices and anti-patterns to help you and your team write better Bicep code.</p>
<h2 id="why-define-and-stick-to-your-authoring-practices">Why Define and Stick to Your Authoring Practices</h2>
<p>Defining and following authoring practices ensures:</p>
<ul>
<li>Consistency across your codebase and team</li>
<li>Easier onboarding for new contributors</li>
<li>Fewer errors and less technical debt</li>
<li>Improved maintainability and clarity</li>
</ul>
<p>Below are some key practices and common anti-patterns to consider.</p>
<hr>
<h2 id="authoring-practices">Authoring Practices</h2>
<h3 id="1-folder-structure">1. Folder Structure</h3>
<p>Organise your Bicep files in a logical folder structure. For example, group modules by resource type or deployment context. This makes navigation and reuse easier:</p>
<pre tabindex="0"><code>├── modules/
│   ├── storage/
│   └── networking/
├── main.bicep
├── parameters/
</code></pre><h3 id="2-template-structure">2. Template Structure</h3>
<p>Keep your templates clean and modular. Use modules for reusable components, and keep your main entry point focused on orchestration. Avoid putting everything in a single file.</p>
<h3 id="3-well-defined-names">3. Well Defined Names</h3>
<p>Use clear, descriptive names for resources, parameters, and variables. Avoid abbreviations that aren’t widely understood. For example, prefer <code>storageAccountName</code> over <code>saName</code>.</p>
<h3 id="4-descriptions">4. Descriptions</h3>
<p>Add descriptions to parameters, outputs, and resources. This helps users understand intent and usage:</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;Configurable name for the application storage account&#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">storageAccountName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span></code></pre></div><h3 id="5-comments">5. Comments</h3>
<p>Use comments to explain why something is done, not what is done. Avoid echoing the code. Good comments provide context or rationale.</p>
<h3 id="6-constraints-and-metadata">6. Constraints and Metadata</h3>
<p>Leverage allowed values, min/max length, and metadata to enforce constraints and provide guidance:</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">minLength</span>(<span style="color:#8be9fd;font-style:italic">3</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">maxLength</span>(<span style="color:#8be9fd;font-style:italic">24</span>)
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">allowed</span>([ <span style="color:#f1fa8c">&#39;dev&#39;</span> <span style="color:#f1fa8c">&#39;test&#39;</span> <span style="color:#f1fa8c">&#39;prod&#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">environment</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span></code></pre></div><p>Make sure to use these where there is a specific need, over constraining parameters can equally cause issues.</p>
<h3 id="7-contracts">7. Contracts</h3>
<p>Define clear contracts for your modules: what parameters are required, what outputs are provided, and what assumptions are made. Document these in the module and in a README.</p>
<h3 id="8-readme">8. README</h3>
<p>Modules and major orchestrating templates should have a README explaining its purpose and usage. This is invaluable for onboarding and reuse.</p>
<h3 id="9-bicep-linting">9. Bicep Linting</h3>
<p>Use Bicep linting as part of your authoring workflow to catch issues early and enforce consistency. Define team linting rules in <code>bicepconfig.json</code>, run lint checks locally during development, and enforce them in CI to prevent low-quality or non-compliant templates from being merged.</p>
<h3 id="10-ai-generated-templates-and-conformance">10. AI-Generated Templates and Conformance</h3>
<p>If you are using AI to generate Bicep, treat your authoring practices as executable guardrails rather than optional guidance.</p>
<p>Start by defining a clear generation contract in your prompt and repository standards:</p>
<ul>
<li>Require a specific folder structure and file naming convention</li>
<li>Require module contracts (documented params/outputs and assumptions)</li>
<li>Require descriptions, meaningful names, and no dead code</li>
<li>Require lint-clean output before a template is considered complete</li>
</ul>
<p>Then enforce conformance automatically in CI:</p>
<ul>
<li>Validate formatting and linting on every pull request</li>
<li>Fail builds when lint rules are violated</li>
<li>Optionally add policy checks (for example, naming, locations, and SKUs)</li>
<li>Require human review for architectural decisions, not just syntax correctness</li>
</ul>
<p>Finally, use a feedback loop. When reviewers find repeated AI mistakes, update your prompt template, lint configuration, and module examples so the next generation cycle improves by default.</p>
<hr>
<h2 id="anti-patterns">Anti-Patterns</h2>
<h3 id="1-premature-abstraction">1. Premature Abstraction</h3>
<p>Don’t create modules or abstractions before you have a real need. Over-abstraction leads to unnecessary complexity and maintenance overhead.</p>
<h3 id="2-over-specification">2. Over-Specification</h3>
<p>Avoid making every resource parameter configurable if it’s not needed. Too many parameters can confuse users and make templates harder to use.</p>
<h3 id="3-echo-comments">3. Echo Comments</h3>
<p>Comments that simply restate the code add no value. For example:</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:#6272a4">// Set the storage account name</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">storageAccountName</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span></code></pre></div><p>Instead, explain why a value is needed or any constraints.</p>
<h3 id="4-dead-code">4. Dead Code</h3>
<p>Remove unused parameters, variables, and resources. Dead code clutters templates and can cause confusion or errors.</p>
<h3 id="5-generic-copy-paste-documentation">5. Generic Copy-Paste Documentation</h3>
<p>Avoid boilerplate documentation that doesn’t reflect the actual template. Tailor docs and comments to the specific module or resource.</p>
<h3 id="6-poorly-defined-names">6. Poorly Defined Names</h3>
<p>Names like <code>var1</code> or <code>resource2</code> make templates hard to understand. Use meaningful, descriptive names everywhere.</p>
<hr>
<h2 id="conclusion">Conclusion</h2>
<p>Establishing and following authoring practices for Bicep will help your team deliver infrastructure as code that is robust, maintainable, and easy to understand. Avoid common anti-patterns, and invest in clarity and documentation.</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #9 | Prevent a Nasty Refactor with Function Namespaces</title><link>https://andrewilson.co.uk/post/2025/09/bicep-tips-and-tricks-function-namespaces/</link><pubDate>Wed, 17 Sep 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/09/bicep-tips-and-tricks-function-namespaces/</guid><description>Problem Space There have been few times where I have landed into this particular predicament whereby either by my own doing or through the use of another&amp;rsquo;s code base, a deep nested or thoroughly utilised (parameter/variable/or other defined item) has been created with the same name as a Bicep function. As by Murphy&amp;rsquo;s law, its only once you have reached this point of no return that you realise that your items name conflicts.</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>There have been few times where I have landed into this particular predicament whereby either by my own doing or through the use of another&rsquo;s code base, a deep nested or thoroughly utilised (parameter/variable/or other defined item) has been created with the same name as a Bicep function. As by Murphy&rsquo;s law, its only once you have reached this point of no return that you realise that your items name conflicts.</p>
<p>Now if you are like many in your unawares, your thoughts and actions will conclude to a singular one of <em>&rsquo;that sucks&hellip; followed by a nasty refactor</em>'.</p>
<h2 id="solution---namespaces">Solution - Namespaces</h2>
<p>Namespaces are a declarative scope in which identifiers such as the names of types, functions, and variables can be declared. These namespaces are used to organise code into logical groups and to prevent name collisions such as the one you are currently experiencing.</p>
<p>Thankfully, in <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions#namespaces-for-functions">Bicep there are two namespaces</a> where all functions are split, <code>az</code> and <code>sys</code>.</p>
<ul>
<li><strong>az</strong> | Contains functions that are specific to an Azure deployment such as:
<ul>
<li>deployment</li>
<li>environment</li>
<li>resourceGroup</li>
<li>subscription</li>
</ul>
</li>
<li><strong>sys</strong> | Contains functions that are used to construct values, and decorators for parameters and resource loops. This includes but is not limited to:
<ul>
<li>[<strong>Array</strong>] concat</li>
<li>[<strong>File</strong>] loadJsonContent</li>
<li>[<strong>Lambda</strong>] filter</li>
<li>[<strong>Logical</strong>] bool</li>
<li>[<strong>Numeric</strong>] int</li>
<li>[<strong>String</strong>] contains</li>
</ul>
</li>
</ul>
<p>To make use of these namespaces, simply add the namespace identifier in front of the function. The example below shows a real world example of this issue where a parameter name &lsquo;<em>environment</em>&rsquo; has been extensively utilised in this template and many others. This particular template is being used to deploy an AuthProvider in API Management, and the author wishes to utilise the environment function for the <code>authentication.loginEndpoint</code>. Without the use of the az namespace, the environment parameter would need to be refactored both in this template and wider templates for consistency.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#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">Namespace</span> <span style="color:#8be9fd;font-style:italic">Example</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 environment to deploy the resources 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">environment</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></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></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Create a new Auth Provider in APIM Credential Manager</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">AuthorizationProvider</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/authorizationProviders@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">properties</span>: {
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">oauth2</span>: {
</span></span><span style="display:flex;"><span>      ...
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">grantTypes</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">clientCredentials</span>: {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">loginUri</span>: <span style="color:#8be9fd;font-style:italic">az</span>.<span style="color:#50fa7b">environment</span>().<span style="color:#8be9fd;font-style:italic">authentication</span>.<span style="color:#8be9fd;font-style:italic">loginEndpoint</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>As always, have a play, and happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #8 | Agnostic Templates Through Config Files</title><link>https://andrewilson.co.uk/post/2025/09/bicep-tips-and-tricks-agnostic-templates-through-config-files/</link><pubDate>Wed, 03 Sep 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/09/bicep-tips-and-tricks-agnostic-templates-through-config-files/</guid><description>Overview Building on our previous exploration of Typed Variables, today we&amp;rsquo;re diving into one of my favorite patterns for creating maintainable and reusable Bicep templates: the Shared Variable File Pattern. This approach transforms your templates from being tightly coupled to specific configurations into truly agnostic, environment-ready solutions.
The beauty of this pattern lies in its simplicity - by extracting configuration data into external JSON or YAML files, you can create templates that adapt without modification.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>Building on our previous exploration of <a href="/post/2025/08/bicep-tips-and-tricks-typed-variables/">Typed Variables</a>, today we&rsquo;re diving into one of my favorite patterns for creating maintainable and reusable Bicep templates: the <strong>Shared Variable File Pattern</strong>. This approach transforms your templates from being tightly coupled to specific configurations into truly agnostic, environment-ready solutions.</p>
<p>The beauty of this pattern lies in its simplicity - by extracting configuration data into external JSON or YAML files, you can create templates that adapt without modification. When combined with typed variables, this approach becomes even more powerful, providing compile-time validation and enhanced developer experience.</p>
<h2 id="why-use-config-files">Why Use Config Files?</h2>
<p>Before diving into the implementation, let&rsquo;s understand why this pattern is so valuable:</p>
<ol>
<li><strong>Separation of Concerns</strong>: Keep your infrastructure logic separate from configuration data</li>
<li><strong>Reduced Template Complexity</strong>: Remove large, complex variable definitions from your templates for better readability</li>
<li><strong>Reusability</strong>: Share common configurations across multiple templates without duplication</li>
<li><strong>Team Collaboration</strong>: Non-technical team members can modify configurations without touching Bicep code</li>
</ol>
<h2 id="the-pattern-in-action">The Pattern in Action</h2>
<h3 id="traditional-approach-what-we-want-to-avoid">Traditional Approach (What We Want to Avoid)</h3>
<p>Traditionally, you might embed all configuration directly in your Bicep template:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bicep" data-lang="bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">nsgRules</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;AllowManagementEndpoint&#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">description</span>: <span style="color:#f1fa8c">&#39;Management endpoint for Azure portal and PowerShell&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">sourceAddressPrefix</span>: <span style="color:#f1fa8c">&#39;ApiManagement&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">sourcePortRange</span>: <span style="color:#f1fa8c">&#39;*&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">destinationAddressPrefix</span>: <span style="color:#f1fa8c">&#39;VirtualNetwork&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">destinationPortRange</span>: <span style="color:#f1fa8c">&#39;3443&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">protocol</span>: <span style="color:#f1fa8c">&#39;Tcp&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">access</span>: <span style="color:#f1fa8c">&#39;Allow&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">priority</span>: <span style="color:#8be9fd;font-style:italic">100</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">direction</span>: <span style="color:#f1fa8c">&#39;Inbound&#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:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;AllowAzureInfrastructureLoadBalancer&#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">description</span>: <span style="color:#f1fa8c">&#39;Azure Infrastructure Load Balancer&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">sourceAddressPrefix</span>: <span style="color:#f1fa8c">&#39;AzureLoadBalancer&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">sourcePortRange</span>: <span style="color:#f1fa8c">&#39;*&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">destinationAddressPrefix</span>: <span style="color:#f1fa8c">&#39;VirtualNetwork&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">destinationPortRange</span>: <span style="color:#f1fa8c">&#39;6390&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">protocol</span>: <span style="color:#f1fa8c">&#39;Tcp&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">access</span>: <span style="color:#f1fa8c">&#39;Allow&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">priority</span>: <span style="color:#8be9fd;font-style:italic">110</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">direction</span>: <span style="color:#f1fa8c">&#39;Inbound&#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:#6272a4">// ... many more rules</span>
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>This approach has several downsides:</p>
<ul>
<li>Templates become bloated and hard to read</li>
<li>Changes require modifying Bicep code</li>
<li>No separation between infrastructure logic and configuration data</li>
</ul>
<h3 id="modern-approach-with-config-files">Modern Approach with Config Files</h3>
<p>Let&rsquo;s transform this using the shared variable file pattern combined with typed variables.</p>
<h4 id="step-1-create-your-config-file">Step 1: Create Your Config File</h4>
<p>Create the configuration file for your deployment:</p>
<p><strong>configs/nsg-rules.json</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;securityRules&#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;AllowManagementEndpoint&#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;description&#34;</span>: <span style="color:#f1fa8c">&#34;Management endpoint for Azure portal and PowerShell&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;sourceAddressPrefix&#34;</span>: <span style="color:#f1fa8c">&#34;ApiManagement&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;sourcePortRange&#34;</span>: <span style="color:#f1fa8c">&#34;*&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;destinationAddressPrefix&#34;</span>: <span style="color:#f1fa8c">&#34;VirtualNetwork&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;destinationPortRange&#34;</span>: <span style="color:#f1fa8c">&#34;3443&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;protocol&#34;</span>: <span style="color:#f1fa8c">&#34;Tcp&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;access&#34;</span>: <span style="color:#f1fa8c">&#34;Allow&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;priority&#34;</span>: <span style="color:#bd93f9">100</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;direction&#34;</span>: <span style="color:#f1fa8c">&#34;Inbound&#34;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;AllowDeveloperAccess&#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;description&#34;</span>: <span style="color:#f1fa8c">&#34;Allow developer access from corporate network&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;sourceAddressPrefix&#34;</span>: <span style="color:#f1fa8c">&#34;10.0.0.0/8&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;sourcePortRange&#34;</span>: <span style="color:#f1fa8c">&#34;*&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;destinationAddressPrefix&#34;</span>: <span style="color:#f1fa8c">&#34;VirtualNetwork&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;destinationPortRange&#34;</span>: <span style="color:#f1fa8c">&#34;443&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;protocol&#34;</span>: <span style="color:#f1fa8c">&#34;Tcp&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;access&#34;</span>: <span style="color:#f1fa8c">&#34;Allow&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;priority&#34;</span>: <span style="color:#bd93f9">200</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;direction&#34;</span>: <span style="color:#f1fa8c">&#34;Inbound&#34;</span>
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="step-2-define-typed-variables">Step 2: Define Typed Variables</h4>
<p>Create a user-defined type to ensure your config files match the expected structure:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bicep" data-lang="bicep"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// User-Defined Types</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ******************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">sealed</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Defines the structure for NSG security rule properties.&#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">nsgSecurityRuleProperties</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Description of the security rule.&#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;Source address prefix or tag.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sourceAddressPrefix</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;Source port range.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sourcePortRange</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;Destination address prefix or tag.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">destinationAddressPrefix</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;Destination port range.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">destinationPortRange</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;Network protocol (Tcp, Udp, or *).&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">protocol</span>: <span style="color:#f1fa8c">&#39;Tcp&#39;</span> | <span style="color:#f1fa8c">&#39;Udp&#39;</span> | <span style="color:#f1fa8c">&#39;*&#39;</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Access type (Allow or Deny).&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">access</span>: <span style="color:#f1fa8c">&#39;Allow&#39;</span> | <span style="color:#f1fa8c">&#39;Deny&#39;</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Priority value (100-4096).&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">priority</span>: <span style="color:#8be9fd;font-style:italic">int</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Direction (Inbound or Outbound).&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">direction</span>: <span style="color:#f1fa8c">&#39;Inbound&#39;</span> | <span style="color:#f1fa8c">&#39;Outbound&#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:#50fa7b">sealed</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Defines the structure for NSG security rule.&#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">nsgSecurityRule</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Name of the security rule.&#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;Properties of the security rule.&#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">nsgSecurityRuleProperties</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">sealed</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Defines the structure for NSG configuration file.&#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">nsgConfig</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Array of security rules.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">securityRules</span>: <span style="color:#8be9fd;font-style:italic">nsgSecurityRule</span>[]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="step-3-load-and-use-configuration">Step 3: Load and Use Configuration</h4>
<p>Now your Bicep template becomes clean and agnostic:</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:#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;Environment to deploy to.&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">environment</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">// Load configuration with full type safety</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">nsgConf</span> <span style="color:#8be9fd;font-style:italic">nsgConfig</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./configs/nsg-rules.json&#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:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">networkSecurityGroup</span> <span style="color:#f1fa8c">&#39;Microsoft.Network/networkSecurityGroups@2024-01-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;nsg-apim&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#50fa7b">resourceGroup</span>().<span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">securityRules</span>: <span style="color:#8be9fd;font-style:italic">nsgConfig</span>.<span style="color:#8be9fd;font-style:italic">securityRules</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="advanced-techniques">Advanced Techniques</h2>
<h3 id="multi-component-configuration-files">Multi-Component Configuration Files</h3>
<p>You can organise multiple configuration aspects in a single file and load only what you need:</p>
<p><strong>configs/apim-config.json</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;networking&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;securityRules&#34;</span>: [...],
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;subnets&#34;</span>: [...]
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;apim&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;sku&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;Developer&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#ff79c6">&#34;capacity&#34;</span>: <span style="color:#bd93f9">1</span>
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;policies&#34;</span>: [...]
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;monitoring&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;logAnalytics&#34;</span>: {...},
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;alerts&#34;</span>: [...]
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Load specific sections using JSONPath:</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:#6272a4">// Load only the networking configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">networkingConfig</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./configs/apim-config.json&#39;</span>, <span style="color:#f1fa8c">&#39;networking&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Load only the APIM configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">apimConfig</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./configs/apim-config.json&#39;</span>, <span style="color:#f1fa8c">&#39;apim&#39;</span>)
</span></span></code></pre></div><h2 id="best-practices">Best Practices</h2>
<ol>
<li><strong>Use Typed Variables</strong>: Define user-defined types for your configuration structures - this provides compile-time validation and excellent IntelliSense support</li>
<li><strong>Logical File Organisation</strong>: Create separate config files for different aspects (networking, security, monitoring) rather than one monolithic file</li>
<li><strong>Validate Early</strong>: Let typed variables catch configuration mismatches during authoring, not deployment</li>
<li><strong>Size Considerations</strong>: Remember that loaded content is included in the generated ARM template (4MB limit)</li>
<li><strong>Version Control</strong>: Keep config files in source control alongside your Bicep templates</li>
</ol>
<h2 id="real-world-benefits">Real-World Benefits</h2>
<p>This pattern has transformed how I approach Bicep development:</p>
<ul>
<li><strong>Faster Development</strong>: IntelliSense support with typed variables makes configuration editing a breeze</li>
<li><strong>Fewer Deployment Failures</strong>: Compile-time validation catches configuration errors before deployment</li>
<li><strong>Better Team Collaboration</strong>: Operations teams can modify configs without touching infrastructure code</li>
<li><strong>Easier Maintenance</strong>: Changes to configuration don&rsquo;t require Bicep code modifications</li>
</ul>
<h2 id="summary">Summary</h2>
<p>The shared variable file pattern, enhanced with typed variables, creates a powerful combination for building maintainable, agnostic Bicep templates. By separating configuration from infrastructure logic, you gain flexibility, reusability, and compile-time safety that makes your Infrastructure as Code truly robust. Happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #7 | From Static to Dynamic Config</title><link>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-static-to-dynamic-config/</link><pubDate>Wed, 27 Aug 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-static-to-dynamic-config/</guid><description>Overview One of my core goals when writing IaC templates is ensuring reusability of common components, resources, and in this case, configuration. More often than not, I see configuration that is broadly common between resources (except for one or two properties) being duplicated throughout templates. This duplication means that changing a single property value requires updates across the entire codebase—a change that&amp;rsquo;s not trivial to manage unless you&amp;rsquo;re well-versed with the codebase and understand all areas where the configuration is implemented.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>One of my core goals when writing IaC templates is ensuring reusability of common components, resources, and in this case, configuration. More often than not, I see configuration that is broadly common between resources (except for one or two properties) being duplicated throughout templates. This duplication means that changing a single property value requires updates across the entire codebase—a change that&rsquo;s not trivial to manage unless you&rsquo;re well-versed with the codebase and understand all areas where the configuration is implemented.</p>
<p>This pattern becomes particularly problematic as your infrastructure grows in complexity. Consider scenarios where you need to update a common tag value, modify a naming convention, or adjust a configuration parameter across dozens of resources. Without proper abstraction, these seemingly simple changes can become error-prone maintenance nightmares.</p>
<p>In this post, I&rsquo;ll demonstrate two powerful Bicep techniques to transform static, duplicated configuration into dynamic, reusable patterns that will make your templates more maintainable and less prone to configuration drift.</p>
<h2 id="common-configuration-scenarios">Common Configuration Scenarios</h2>
<p>Before diving into solutions, let&rsquo;s examine two common scenarios where static configuration creates maintenance headaches:</p>
<h3 id="scenario-1-resource-tagging">Scenario 1: Resource Tagging</h3>
<p>Every Azure resource should be properly tagged for governance, cost tracking, and management. However, I frequently see templates where tags are copy-pasted across resources, creating maintenance debt:</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:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">storageAccount</span> <span style="color:#f1fa8c">&#39;Microsoft.Storage/storageAccounts@2025-01-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#6272a4">// ... other properties</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">BusinessUnit</span>: <span style="color:#f1fa8c">&#39;BicepTipsAndTricks&#39;</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 style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Region</span>: <span style="color:#8be9fd;font-style:italic">region</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;Storage Account&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f1fa8c">&#39;hidden-title&#39;</span>: <span style="color:#f1fa8c">&#39;Bicep Tips and Tricks Storage&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#6272a4">// ... other properties</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This approach works for a single resource, but imagine maintaining this across 50+ resources. When the business unit name changes or you need to add a new compliance tag, you&rsquo;re looking at a significant refactoring effort.</p>
<h3 id="scenario-2-complex-configuration-structures">Scenario 2: Complex Configuration Structures</h3>
<p>Complex JSON configurations, such as Consumption Logic App workflow definitions, often contain embedded values that need to vary between environments or deployments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;definition&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;Condition_-_Morning_or_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;Terminate_-_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                        },
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;else&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;Terminate_-_Morning&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;expression&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;and&#34;</span>: [
</span></span><span style="display:flex;"><span>                        {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;greaterOrEquals&#34;</span>: [
</span></span><span style="display:flex;"><span>                                <span style="color:#f1fa8c">&#34;@utcNow(&#39;H:mm:ss&#39;)&#34;</span>,
</span></span><span style="display:flex;"><span>                                <span style="color:#f1fa8c">&#34;12:00:00&#34;</span> <span style="color:#6272a4">// ← Currently hard-coded static configuration
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                            ]
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    ]
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;If&#34;</span>
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;outputs&#34;</span>: {},
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;parameters&#34;</span>: {},
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;triggers&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;Recurrence_-_Start&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;evaluatedRecurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Day&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#bd93f9">1</span>, <span style="color:#6272a4">// ← Currently hard-coded static configuration
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                    <span style="color:#ff79c6">&#34;schedule&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;hours&#34;</span>: [
</span></span><span style="display:flex;"><span>                            <span style="color:#f1fa8c">&#34;11&#34;</span>
</span></span><span style="display:flex;"><span>                        ]
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;recurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Hour&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#f1fa8c">&#34;2&#34;</span> <span style="color:#6272a4">// ← Currently hard-coded static configuration
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Recurrence&#34;</span>
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;parameters&#34;</span>: {}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In this Consumption Logic App workflow, the recurrence interval, evaluatedRecurrence interval, and condition time values are hard-coded. If you need different intervals or values for different environments (perhaps more frequent polling in production), you&rsquo;d need to maintain separate configuration files or manually edit values during deployment.</p>
<h2 id="my-recommended-approaches">My Recommended Approaches</h2>
<h3 id="approach-1-union-function-for-object-composition">Approach 1: Union Function for Object Composition</h3>
<p>The <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-object#union"><code>union()</code></a> function is perfect for combining base configuration with resource-specific overrides. This approach works exceptionally well for scenarios like tagging, where you have a core set of common properties and some resource-specific additions.</p>
<p><strong>The Problem:</strong> Without union, you end up repeating common tags across every resource:</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:#6272a4">// Bad: Repeated configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">storageAccount</span> <span style="color:#f1fa8c">&#39;Microsoft.Storage/storageAccounts@2025-01-01&#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:#8be9fd;font-style:italic">BusinessUnit</span>: <span style="color:#f1fa8c">&#39;BicepTipsAndTricks&#39;</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 style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Region</span>: <span style="color:#8be9fd;font-style:italic">region</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;Storage Account&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f1fa8c">&#39;hidden-title&#39;</span>: <span style="color:#f1fa8c">&#39;Bicep Tips and Tricks Storage&#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:#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></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">BusinessUnit</span>: <span style="color:#f1fa8c">&#39;BicepTipsAndTricks&#39;</span>  <span style="color:#6272a4">// Duplicated!</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 style="color:#6272a4">// Duplicated!</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>  <span style="color:#6272a4">// Duplicated!</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">Region</span>: <span style="color:#8be9fd;font-style:italic">region</span>  <span style="color:#6272a4">// Duplicated!</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;Key Vault&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f1fa8c">&#39;hidden-title&#39;</span>: <span style="color:#f1fa8c">&#39;Bicep Tips and Tricks Key Vault&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>The Solution:</strong> Use union to combine base and specific configurations:</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:#6272a4">// Good: Centralized common configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Parameters **</span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">environment</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 Azure region to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">region</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;UkSouth&#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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">coreTags</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">BusinessUnit</span>: <span style="color:#f1fa8c">&#39;BicepTipsAndTricks&#39;</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 style="color:#8be9fd;font-style:italic">Environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">Region</span>: <span style="color:#8be9fd;font-style:italic">region</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">// Create resource-specific tag combinations</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">storageAccountTags</span> = <span style="color:#50fa7b">union</span>(<span style="color:#8be9fd;font-style:italic">coreTags</span>, {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;Storage Account&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;hidden-title&#39;</span>: <span style="color:#f1fa8c">&#39;Bicep Tips and Tricks Storage&#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">var</span> <span style="color:#8be9fd;font-style:italic">keyVaultTags</span> = <span style="color:#50fa7b">union</span>(<span style="color:#8be9fd;font-style:italic">coreTags</span>, {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">ResourceName</span>: <span style="color:#f1fa8c">&#39;Key Vault&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;hidden-title&#39;</span>: <span style="color:#f1fa8c">&#39;Bicep Tips and Tricks Key Vault&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">DataClassification</span>: <span style="color:#f1fa8c">&#39;Confidential&#39;</span>  <span style="color:#6272a4">// Additional tag specific to Key Vault</span>
</span></span><span style="display:flex;"><span>})
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">storageAccount</span> <span style="color:#f1fa8c">&#39;Microsoft.Storage/storageAccounts@2025-01-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;mystorageaccount&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">region</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: <span style="color:#8be9fd;font-style:italic">storageAccountTags</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></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">keyVault</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:#f1fa8c">&#39;mykeyvault&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">region</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tags</span>: <span style="color:#8be9fd;font-style:italic">keyVaultTags</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">subscription</span>().<span style="color:#8be9fd;font-style:italic">tenantId</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Key Benefits:</strong></p>
<ul>
<li><strong>Single source of truth</strong>: Common tags are defined once in <code>coreTags</code></li>
<li><strong>Easy maintenance</strong>: Update business unit name? Change it in one place</li>
<li><strong>Flexible</strong>: Each resource can still have unique tags</li>
</ul>
<h3 id="approach-2-token-replacement-for-complex-configurations">Approach 2: Token Replacement for Complex Configurations</h3>
<p>For complex JSON configurations that need dynamic values, token replacement provides an elegant solution. This approach is particularly powerful when working with imported JSON files that contain configuration.</p>
<p><strong>The Problem:</strong> Static values embedded in complex configurations:</p>
<p><strong>The Solution:</strong> Use token placeholders and replacement functions.</p>
<p>First, modify your JSON configuration file to use tokens:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;definition&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;Condition_-_Morning_or_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;Terminate_-_Afternoon&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                        },
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;else&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;actions&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;Terminate_-_Morning&#34;</span>: {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;inputs&#34;</span>: {
</span></span><span style="display:flex;"><span>                                <span style="color:#ff79c6">&#34;runStatus&#34;</span>: <span style="color:#f1fa8c">&#34;Succeeded&#34;</span>
</span></span><span style="display:flex;"><span>                            },
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Terminate&#34;</span>
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;expression&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;and&#34;</span>: [
</span></span><span style="display:flex;"><span>                        {
</span></span><span style="display:flex;"><span>                            <span style="color:#ff79c6">&#34;greaterOrEquals&#34;</span>: [
</span></span><span style="display:flex;"><span>                                <span style="color:#f1fa8c">&#34;@utcNow(&#39;H:mm:ss&#39;)&#34;</span>,
</span></span><span style="display:flex;"><span>                                <span style="color:#f1fa8c">&#34;__schedule_time__&#34;</span>  <span style="color:#6272a4">// ← Token for schedule time
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                            ]
</span></span><span style="display:flex;"><span>                        }
</span></span><span style="display:flex;"><span>                    ]
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;runAfter&#34;</span>: {},
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;If&#34;</span>
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;outputs&#34;</span>: {},
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;parameters&#34;</span>: {},
</span></span><span style="display:flex;"><span>        <span style="color:#ff79c6">&#34;triggers&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#ff79c6">&#34;Recurrence_-_Start&#34;</span>: {
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;evaluatedRecurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Day&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#bd93f9">1</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;schedule&#34;</span>: {
</span></span><span style="display:flex;"><span>                        <span style="color:#ff79c6">&#34;hours&#34;</span>: [
</span></span><span style="display:flex;"><span>                            <span style="color:#f1fa8c">&#34;__schedule_hour__&#34;</span>  <span style="color:#6272a4">// ← Token for schedule hour
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                        ]
</span></span><span style="display:flex;"><span>                    }
</span></span><span style="display:flex;"><span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;recurrence&#34;</span>: {
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;frequency&#34;</span>: <span style="color:#f1fa8c">&#34;Hour&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#ff79c6">&#34;interval&#34;</span>: <span style="color:#f1fa8c">&#34;__interval__&#34;</span>  <span style="color:#6272a4">// ← Token for interval
</span></span></span><span style="display:flex;"><span><span style="color:#6272a4"></span>                },
</span></span><span style="display:flex;"><span>                <span style="color:#ff79c6">&#34;type&#34;</span>: <span style="color:#f1fa8c">&#34;Recurrence&#34;</span>
</span></span><span style="display:flex;"><span>            }
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;parameters&#34;</span>: {}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then, create a robust token replacement system in your Bicep template:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bicep" data-lang="bicep"><span style="display:flex;"><span><span style="color:#6272a4">// ** Imported Types and Functions **</span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Token Replacement 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:#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">TokenReplacement</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Token to be replaced&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">token</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;Replacement value&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">replacement</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;String Tokens Replacement Function&#39;</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">func</span> <span style="color:#50fa7b">stringTokensReplacement</span>(<span style="color:#8be9fd;font-style:italic">stringValue</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">tokenReplacements</span> <span style="color:#8be9fd;font-style:italic">TokenReplacement</span>[]) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#50fa7b">reduce</span>(<span style="color:#8be9fd;font-style:italic">tokenReplacements</span>, <span style="color:#8be9fd;font-style:italic">stringValue</span>, (<span style="color:#8be9fd;font-style:italic">current</span>, <span style="color:#8be9fd;font-style:italic">next</span>) =&gt; <span style="color:#50fa7b">replace</span>(<span style="color:#50fa7b">string</span>(<span style="color:#8be9fd;font-style:italic">current</span>), <span style="color:#8be9fd;font-style:italic">next</span>.<span style="color:#8be9fd;font-style:italic">token</span>, <span style="color:#8be9fd;font-style:italic">next</span>.<span style="color:#8be9fd;font-style:italic">replacement</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The interval for the Logic App trigger&#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">logicAppInterval</span> <span style="color:#8be9fd;font-style:italic">int</span> = <span style="color:#8be9fd;font-style:italic">2</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 schedule hour for the Logic App trigger&#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">scheduleHour</span> <span style="color:#8be9fd;font-style:italic">int</span> = <span style="color:#8be9fd;font-style:italic">11</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 schedule time for condition comparison&#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">scheduleTime</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;12:00:00&#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 environment for deployment&#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">environment</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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">logicAppConsumptionWorkflow</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./logicAppConsumptionWorkflow.json&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Define all token replacements in one place</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">tokenReplacements</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">token</span>: <span style="color:#f1fa8c">&#39;__interval__&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">replacement</span>: <span style="color:#50fa7b">string</span>(<span style="color:#8be9fd;font-style:italic">logicAppInterval</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">token</span>: <span style="color:#f1fa8c">&#39;__schedule_hour__&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">replacement</span>: <span style="color:#50fa7b">string</span>(<span style="color:#8be9fd;font-style:italic">scheduleHour</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">token</span>: <span style="color:#f1fa8c">&#39;__schedule_time__&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">replacement</span>: <span style="color:#8be9fd;font-style:italic">scheduleTime</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">// Apply all token replacements</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">processedWorkflowDefinition</span> = <span style="color:#50fa7b">json</span>(<span style="color:#50fa7b">stringTokensReplacement</span>(
</span></span><span style="display:flex;"><span>  <span style="color:#50fa7b">string</span>(<span style="color:#8be9fd;font-style:italic">logicAppConsumptionWorkflow</span>),
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">tokenReplacements</span>
</span></span><span style="display:flex;"><span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">logicApp</span> <span style="color:#f1fa8c">&#39;Microsoft.Logic/workflows@2023-12-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;my-dynamic-logic-app-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">environment</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">location</span>: <span style="color:#50fa7b">resourceGroup</span>().<span style="color:#8be9fd;font-style:italic">location</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">definition</span>: <span style="color:#8be9fd;font-style:italic">processedWorkflowDefinition</span>.<span style="color:#8be9fd;font-style:italic">definition</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">parameters</span>: <span style="color:#8be9fd;font-style:italic">processedWorkflowDefinition</span>.<span style="color:#8be9fd;font-style:italic">parameters</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Key Benefits:</strong></p>
<ul>
<li><strong>Environment-specific values</strong>: Different intervals for dev/test/prod</li>
<li><strong>Centralized configuration</strong>: All replacements defined in one place</li>
<li><strong>Scalable</strong>: Easy to add new tokens as requirements grow</li>
<li><strong>Version control friendly</strong>: JSON templates remain clean and readable</li>
</ul>
<h2 id="summary">Summary</h2>
<p>Transforming static configuration into dynamic, reusable patterns is essential for maintainable Infrastructure as Code. Use the <code>union()</code> function when combining common configuration with resource-specific properties (like tags), and token replacement for complex JSON configurations that need dynamic values injected. Both approaches centralize configuration management, reduce duplication, and make your Bicep templates more maintainable across environments. The next time you find yourself copy-pasting configuration, choose the right pattern and eliminate that technical debt!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #6 | Typed Variables</title><link>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-typed-variables/</link><pubDate>Wed, 20 Aug 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-typed-variables/</guid><description>Overview In late May this year, an exciting but semi overlooked feature was released, and I absolutely love it - Typed Variables!
Prior to this release, variable types were inferred through the value, which is fine for most statically defined content within a template, but there are cases that I will go through in this post where typing your variables really does make a big difference.
Why Use Typed Variables Before I get going, let me walk through why you should consider using typed variables:</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>In late <a href="https://github.com/Azure/bicep/releases/tag/v0.36.1">May this year</a>, an exciting but semi overlooked feature was released, and I absolutely love it - <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/variables#typed-variables">Typed Variables</a>!</p>
<p>Prior to this release, variable types were inferred through the value, which is fine for most statically defined content within a template, but there are cases that I will go through in this post where typing your variables really does make a big difference.</p>
<h2 id="why-use-typed-variables">Why Use Typed Variables</h2>
<p>Before I get going, let me walk through why you should consider using typed variables:</p>
<ol>
<li><strong>Fail-Fast Error Detection</strong>: Typed variables enable the Bicep compiler to validate assigned values against declared types during authoring and compilation. This helps catch mistakes early, reducing deployment failures.</li>
<li><strong>Clearer Intent</strong>: Declaring types communicates your intent directly in the code, making it obvious how each variable should be used and what kind of data it should hold.</li>
<li><strong>Enhanced IntelliSense Support</strong>: Editors like Visual Studio Code offer richer autocompletion and validation for typed variables, speeding up development and reducing errors.</li>
<li><strong>Safer Refactoring</strong>: When you change variable values or types, the compiler immediately flags mismatches, making refactoring safer and more predictable.</li>
</ol>
<h2 id="setup">Setup</h2>
<p>Defining a typed variable is as simple as the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#ff79c6">&lt;</span><span style="color:#8be9fd;font-style:italic">variable</span><span style="color:#ff79c6">-</span><span style="color:#8be9fd;font-style:italic">name</span><span style="color:#ff79c6">&gt;</span> <span style="color:#ff79c6">&lt;</span><span style="color:#8be9fd;font-style:italic">data</span><span style="color:#ff79c6">-</span><span style="color:#8be9fd;font-style:italic">type</span><span style="color:#ff79c6">&gt;</span> = <span style="color:#ff79c6">&lt;</span><span style="color:#8be9fd;font-style:italic">variable</span><span style="color:#ff79c6">-</span><span style="color:#8be9fd;font-style:italic">value</span><span style="color:#ff79c6">&gt;</span>
</span></span></code></pre></div><blockquote>
<p>⚠️ <strong>Note</strong>: Requires Bicep version <code>0.36.X</code> or later.</p>
</blockquote>
<p>Typed variables support both the standard set of base data types - string, int, bool, object, array - or for the more advanced, <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-data-types">User-defined data types</a> and <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-data-types#resource-derived-types">Resource-derived types</a>.</p>
<h2 id="my-top-two-use-cases">My Top Two Use Cases</h2>
<h3 id="1-clear-intent">1. Clear Intent</h3>
<p>The first major use case for typed variables is improving code clarity and maintainability, especially when working with functions that return complex objects. Without type declarations, it can be difficult to understand what a function returns or how to properly use the resulting variable.</p>
<p>Consider this example with a custom function:</p>
<blockquote>
<p>Un-Typed Variable</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></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Functions **</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">func</span> <span style="color:#50fa7b">myFunction</span>(<span style="color:#8be9fd;font-style:italic">param1</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">param2</span> <span style="color:#8be9fd;font-style:italic">int</span>) <span style="color:#8be9fd;font-style:italic">object</span> =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property1</span>: <span style="color:#8be9fd;font-style:italic">param1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property2</span>: <span style="color:#8be9fd;font-style:italic">param2</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Un-typed - No IntelliSense on variable use or expectation of variable type.</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">variable</span> = <span style="color:#50fa7b">myFunction</span>(<span style="color:#f1fa8c">&#39;example&#39;</span>, <span style="color:#8be9fd;font-style:italic">42</span>)
</span></span></code></pre></div><p>In this un-typed scenario, several issues arise:</p>
<ul>
<li><strong>Unclear return type</strong>: The function returns a generic <code>object</code>, making it unclear what properties are available</li>
<li><strong>No IntelliSense support</strong>: When using <code>variable.</code>, your editor can&rsquo;t help you with autocompletion</li>
<li><strong>Hidden intent</strong>: Other developers (or future you) must examine the function implementation to understand what it returns</li>
<li><strong>Error-prone usage</strong>: Typos in property names won&rsquo;t be caught until deployment time</li>
</ul>
<p>Now let&rsquo;s see how typed variables solve these problems:</p>
<blockquote>
<p>Typed Variable</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></span><span style="display:flex;"><span><span style="color:#6272a4">// User Defined-Types</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *********************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">sealed</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Defines the structure for myFunction output.&#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">myFunctionOutputType</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The first property of the output.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property1</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 second property of the output.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property2</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">// ** Functions **</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">func</span> <span style="color:#50fa7b">myFunction</span>(<span style="color:#8be9fd;font-style:italic">param1</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">param2</span> <span style="color:#8be9fd;font-style:italic">int</span>) <span style="color:#8be9fd;font-style:italic">myFunctionOutputType</span> =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property1</span>: <span style="color:#8be9fd;font-style:italic">param1</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">property2</span>: <span style="color:#8be9fd;font-style:italic">param2</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Typed - Includes IntelliSense, code clarity, and refactor safety on variable use.</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">typedVariable</span> <span style="color:#8be9fd;font-style:italic">myFunctionOutputType</span> = <span style="color:#50fa7b">myFunction</span>(<span style="color:#f1fa8c">&#39;example&#39;</span>, <span style="color:#8be9fd;font-style:italic">42</span>)
</span></span></code></pre></div><p>The typed approach delivers immediate improvements:</p>
<ul>
<li><strong>Crystal clear intent</strong>: The type definition explicitly documents what the function returns and what each property represents</li>
<li><strong>Enhanced developer experience</strong>: Full IntelliSense support when working with the variable, including property names and descriptions</li>
<li><strong>Compile-time safety</strong>: Any mismatch between the function&rsquo;s actual return value and the declared type will be caught during authoring and compilation</li>
<li><strong>Better maintainability</strong>: Changes to the function&rsquo;s return structure must be reflected in the type definition, ensuring consistency across the codebase</li>
<li><strong>Team collaboration</strong>: New team members can quickly understand the data structure without diving into function implementations</li>
</ul>
<p>This pattern is especially valuable in larger Bicep templates where functions might be defined in one section and used much later in the file, or using imported functions as discussed earlier in the series.</p>
<h3 id="2-file-functions">2. File functions</h3>
<p>One of the most powerful applications of typed variables is when working with Bicep&rsquo;s file functions such as <code>loadJsonContent()</code> and <code>loadYamlContent()</code>. Without typed variables, these functions return as an <code>Any object</code>, providing no compile-time validation for the loaded content.</p>
<p>Let&rsquo;s look at a practical example where we&rsquo;re loading configuration data from an external JSON file:</p>
<blockquote>
<p>JSON config file</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-JSON" data-lang="JSON"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#ff79c6">&#34;sku&#34;</span>: {
</span></span><span style="display:flex;"><span>		<span style="color:#ff79c6">&#34;name&#34;</span>: <span style="color:#f1fa8c">&#34;Standard&#34;</span>,
</span></span><span style="display:flex;"><span>		<span style="color:#ff79c6">&#34;tier&#34;</span>: <span style="color:#f1fa8c">&#34;Standard&#34;</span>
</span></span><span style="display:flex;"><span>	},
</span></span><span style="display:flex;"><span>	<span style="color:#ff79c6">&#34;kind&#34;</span>: <span style="color:#f1fa8c">&#34;StorageV2&#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;supportsHttpsTrafficOnly&#34;</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>Un-Typed Variable</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></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">resourceConfig</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./Config/resource.config.json&#39;</span>)
</span></span></code></pre></div><p>With the un-typed approach above, <code>resourceConfig</code> is treated as a generic <code>object</code>. This means:</p>
<ul>
<li>No compile-time validation of the JSON structure</li>
<li>No documentation about what the configuration should contain</li>
</ul>
<p>Now let&rsquo;s see how typed variables transform this experience:</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:#6272a4">// User Defined-Types</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// *********************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">sealed</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Defines the structure for importing a JSON File resource with SKU, kind, and properties.&#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">resourceImportType</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The SKU details for the resource.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">sku</span>: {
</span></span><span style="display:flex;"><span>    @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The name of the SKU.&#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 tier of the SKU (e.g., Standard, Premium).&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tier</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 kind of the resource.&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">kind</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 properties of the resource.&#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">description</span>(<span style="color:#f1fa8c">&#39;Indicates whether only HTTPS traffic is supported.&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">supportsHttpsTrafficOnly</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></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">typedResourceConfig</span> <span style="color:#8be9fd;font-style:italic">resourceImportType</span> = <span style="color:#50fa7b">loadJsonContent</span>(<span style="color:#f1fa8c">&#39;./Config/resource.config.json&#39;</span>)
</span></span></code></pre></div><p>With the typed variable approach, we gain several significant benefits:</p>
<ul>
<li><strong>Compile-time validation</strong>: If the JSON file doesn&rsquo;t match the defined structure, Bicep will catch this during authoring and compilation</li>
<li><strong>Rich IntelliSense</strong>: When you type <code>typedResourceConfig.</code>, your editor will show you the available properties with their descriptions</li>
<li><strong>Self-documenting code</strong>: The type definition serves as living documentation of the expected configuration structure</li>
<li><strong>Refactoring safety</strong>: If you change the type definition, all usages will be validated automatically</li>
</ul>
<p>This approach is particularly valuable when working with complex configuration files or when multiple team members need to understand the expected data structure.</p>
<h2 id="summary">Summary</h2>
<p>Typed variables are a game changer for Bicep development, offering compile-time validation, enhanced IntelliSense, and self-documenting code that makes your templates more robust and maintainable. Make sure to give them a try, and happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #5 | From Documentation to Deployment-Time Validation: Conditional Parameter Requirements</title><link>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-conditional-mandatory-parameters/</link><pubDate>Wed, 13 Aug 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-conditional-mandatory-parameters/</guid><description>Overview In Bicep templates, we sometimes encounter scenarios where certain parameters should be mandatory based on the value of another parameter. For example, when deploying to production environments, you might require additional configuration parameters that are optional for development environments.
One of the common ways in which I have seen this handled is through documentation, which can lead to deployment failures and inconsistent configurations across environments. This post explores how to implement fail-fast validation using Bicep&amp;rsquo;s built-in capabilities to enforce these conditional requirements at deployment time.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>In Bicep templates, we sometimes encounter scenarios where certain parameters should be mandatory based on the value of another parameter. For example, when deploying to production environments, you might require additional configuration parameters that are optional for development environments.</p>
<p>One of the common ways in which I have seen this handled is through documentation, which can lead to deployment failures and inconsistent configurations across environments. This post explores how to implement fail-fast validation using Bicep&rsquo;s built-in capabilities to enforce these conditional requirements at deployment time.</p>
<h3 id="example-of-a-documentation-only-approach">Example of a Documentation-Only Approach</h3>
<p>Handling conditional parameter requirements through documentation alone:</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;Environment to deploy 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">environment</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;Resource configuration - REQUIRED for prod environment!&#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">resourceConfig</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">// Additional parameters that should be required in prod</span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Monitoring configuration - REQUIRED for prod environment!&#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">monitoringConfig</span> <span style="color:#8be9fd;font-style:italic">object</span> = {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Backup configuration - REQUIRED for prod environment!&#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">backupRetentionDays</span> <span style="color:#8be9fd;font-style:italic">int</span> = <span style="color:#8be9fd;font-style:italic">0</span>
</span></span></code></pre></div><p><strong>Problems with this approach:</strong></p>
<ul>
<li>No enforcement at deployment time</li>
<li>Deployments can succeed with missing critical configuration</li>
<li>Relies on human memory and documentation</li>
<li>Inconsistent environments due to missing parameters</li>
<li>Production issues from misconfiguration</li>
</ul>
<h2 id="recommended-approach-fail-fast-validation">Recommended Approach: Fail-Fast Validation</h2>
<p>I would recommend using the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-flow-control#fail">Bicep <code>fail()</code></a> function combined with conditional logic to validate parameters early in the deployment process. This approach provides immediate feedback and prevents deployments with invalid configurations, such as in the following examples:</p>
<ul>
<li>Production environments - Storage deployments requiring backup retention settings for production</li>
<li>Key Vault requiring network access rules when public access is disabled</li>
</ul>
<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;Environment to deploy 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">environment</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;&#39;&#39;Resource Configuration:
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">                - **Optional** When environment is dev / test.
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">                - **Required** When environment is prod.&#39;&#39;&#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">resourceConfig</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Resource Configuration Validation Result&#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">resourceConfig_Result</span> = <span style="color:#8be9fd;font-style:italic">environment</span> <span style="color:#ff79c6">==</span> <span style="color:#f1fa8c">&#39;prod&#39;</span> <span style="color:#ff79c6">&amp;&amp;</span> <span style="color:#50fa7b">empty</span>(<span style="color:#8be9fd;font-style:italic">resourceConfig</span>)
</span></span><span style="display:flex;"><span>  ? <span style="color:#50fa7b">fail</span>(<span style="color:#f1fa8c">&#39;resourceConfig is required to deploy this template in the prod Environment.&#39;</span>)
</span></span><span style="display:flex;"><span>  : {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#8be9fd;font-style:italic">resourceConfig</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">valueProvided</span>: <span style="color:#ff79c6">!</span><span style="color:#50fa7b">empty</span>(<span style="color:#8be9fd;font-style:italic">resourceConfig</span>)
</span></span><span style="display:flex;"><span>    }
</span></span></code></pre></div><blockquote>
<p>⚠️ <strong>Note</strong>: Make deployment failures informative and actionable, helping your team understand exactly what&rsquo;s needed to fix the issue.</p>
</blockquote>
<h3 id="why-this-approach-is-useful">Why this approach is useful</h3>
<ul>
<li><strong>Enforces deployment rules</strong>: Prevents deployment in &ldquo;prod&rdquo; if critical configuration is missing, ensuring required configuration is provided before any resources are created.</li>
<li><strong>Fail-fast validation</strong>: Catches configuration errors at the start of deployment, saving time and preventing partial deployments.</li>
<li><strong>Conditional resource creation</strong>: You can use the <code>valueProvided</code> property to conditionally deploy resources or set properties only when configuration is supplied.</li>
<li><strong>Parameter validation</strong>: Centralizes validation logic, making it easier to maintain and extend checks for other environments or parameters in the future.</li>
<li><strong>Compliance requirements</strong>: Ensures production environments always meet security and operational standards.</li>
</ul>
<h2 id="summary">Summary</h2>
<p>Conditional mandatory parameters in Bicep templates are a powerful way to enforce deployment standards and prevent configuration errors. Remember to make deployment failures informative and actionable, helping your team understand exactly what&rsquo;s needed to fix the issue. Hope this helps, and happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #4 | Shared Variables</title><link>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-shared-variables/</link><pubDate>Wed, 06 Aug 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/08/bicep-tips-and-tricks-shared-variables/</guid><description>Overview This week is a simple one, but works wonders in maintainability and consistency.
There are often cases where you will need to define static values that don&amp;rsquo;t change frequently, if at all, and more importantly, you seem to be setting these up frequently for multiple templates. Here are some examples that I have seen:
Multi-Environment Deployments
Different environments (dev, staging, prod) that share common configuration but need environment-specific values:</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>This week is a simple one, but works wonders in maintainability and consistency.</p>
<p>There are often cases where you will need to define static values that don&rsquo;t change frequently, if at all, and more importantly, you seem to be setting these up frequently for multiple templates. Here are some examples that I have seen:</p>
<ol>
<li>
<p>Multi-Environment Deployments</p>
<p>Different environments (dev, staging, prod) that share common configuration but need environment-specific values:</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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">environmentConfig</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dev</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</span>: <span style="color:#f1fa8c">&#39;Basic&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">staging</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</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">prod</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</span>: <span style="color:#f1fa8c">&#39;Premium&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></li>
<li>
<p>Organisational Standards</p>
<p>When you need to enforce company-wide conventions and policies.</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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">mandatoryTags</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">costCenter</span>: <span style="color:#f1fa8c">&#39;IT-001&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dataClassification</span>: <span style="color:#f1fa8c">&#39;internal&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">businessUnit</span>: <span style="color:#f1fa8c">&#39;engineering&#39;</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></code></pre></div></li>
<li>
<p>Object or Resource Configurations</p>
<p>When you have configurations that would be repeated across multiple templates.</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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">subnetConfigurations</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;web-subnet&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">addressPrefix</span>: <span style="color:#f1fa8c">&#39;10.0.1.0/24&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">serviceEndpoints</span>: [<span style="color:#f1fa8c">&#39;Microsoft.Storage&#39;</span>, <span style="color:#f1fa8c">&#39;Microsoft.KeyVault&#39;</span>]
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;api-subnet&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">addressPrefix</span>: <span style="color:#f1fa8c">&#39;10.0.2.0/24&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">serviceEndpoints</span>: [<span style="color:#f1fa8c">&#39;Microsoft.Sql&#39;</span>, <span style="color:#f1fa8c">&#39;Microsoft.KeyVault&#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">// OR</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">keyVaultSecretsUserRoleDefId</span> = <span style="color:#f1fa8c">&#39;4633458b-17de-408a-b874-0445c86b69e6&#39;</span>
</span></span></code></pre></div></li>
</ol>
<p>You might think, &ldquo;Hey, the values don&rsquo;t change very often, so what&rsquo;s the big deal? So what if I set them up many times across my templates?&rdquo; Not to be a pessimist, but it&rsquo;s usually at this point that Murphy&rsquo;s Law comes into effect and the values will need to change! Would you not rather there be a single point where you can update these values and they ripple through your templates like a stone hitting water?</p>
<p>Well, you can. Simply put, <strong>Shared Variables</strong>.</p>
<h2 id="recommended-approach">Recommended Approach</h2>
<p>My recommended approach is to leverage <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-import">Bicep Imports</a>. Create a Common folder within your <code>IaC</code> directory, and then a <code>variables.bicep</code> file within:</p>
<pre tabindex="0"><code>IaC
  ↳ Common
    ↳ variables.bicep
  ↳ main.bicep
</code></pre><p>This will form the basis of your shared variables that can be used across your deployment templates.</p>
<p>Then find all the relevant candidates and move these across to the shared variables template. Include the <code>@export()</code> decorator to each variable; this is used to allow the variable to be imported into other Bicep files.</p>
<blockquote>
<p>For Example</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">Shared</span> <span style="color:#8be9fd;font-style:italic">Variables</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:#50fa7b">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Shared Variable for environment configurations&#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">environmentConfig</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dev</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</span>: <span style="color:#f1fa8c">&#39;Basic&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">staging</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</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">prod</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">sku</span>: <span style="color:#f1fa8c">&#39;Premium&#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">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Shared Variable for tagging resources&#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">mandatoryTags</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">costCenter</span>: <span style="color:#f1fa8c">&#39;IT-001&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dataClassification</span>: <span style="color:#f1fa8c">&#39;internal&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">businessUnit</span>: <span style="color:#f1fa8c">&#39;engineering&#39;</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></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;Shared Variable for resource configuration&#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">subnetConfigurations</span> = [
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;web-subnet&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">addressPrefix</span>: <span style="color:#f1fa8c">&#39;10.0.1.0/24&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">serviceEndpoints</span>: [<span style="color:#f1fa8c">&#39;Microsoft.Storage&#39;</span>, <span style="color:#f1fa8c">&#39;Microsoft.KeyVault&#39;</span>]
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;api-subnet&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">addressPrefix</span>: <span style="color:#f1fa8c">&#39;10.0.2.0/24&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">serviceEndpoints</span>: [<span style="color:#f1fa8c">&#39;Microsoft.Sql&#39;</span>, <span style="color:#f1fa8c">&#39;Microsoft.KeyVault&#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">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Shared Variable for Key Vault Secrets User Role Definition ID&#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></code></pre></div><p>These can then be used in your deployment templates 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">Main</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">// ** Shared Imports **</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">import</span> { <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefId</span> } <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./Common/variables.bicep&#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></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Variables **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ** Resources **</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// ***************</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">roleassignment</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">logicAppName</span>, <span style="color:#8be9fd;font-style:italic">keyVaultSecretsUserRoleDefId</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">resourceId</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></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="best-practices-for-using-shared-variables">Best Practices for Using Shared Variables</h2>
<ol>
<li><strong>Keep it Simple</strong>: Only share variables that are common and stable.</li>
<li><strong>Tight Control</strong>: Treat shared variables as critical infrastructure code.</li>
<li><strong>Documentation</strong>: Clearly document and describe what each variable represents or is used for.</li>
<li><strong>Selective Imports</strong>: Don&rsquo;t import everything with <code>*</code>; be selective about what needs to be imported into deployment templates.</li>
</ol>
<h2 id="when-not-to-use-shared-variables">When NOT to Use Shared Variables</h2>
<ul>
<li>For values that change frequently or are deployment-specific</li>
<li>For simple, one-off configurations</li>
<li>For sensitive values (use parameters or Key Vault references instead)</li>
</ul>
<h2 id="summary">Summary</h2>
<p>Shared variables help eliminate duplication and improve consistency across your Bicep templates. This simple approach gives you a single point of truth for common configurations, making updates easier and reducing the risk of inconsistencies across environments. Hope this helps, and happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #3 | Naming Convention and Functions</title><link>https://andrewilson.co.uk/post/2025/07/bicep-tips-and-tricks-naming-convention-functions/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/07/bicep-tips-and-tricks-naming-convention-functions/</guid><description>Overview One of my bugbears is seeing either a complete lack of naming conventions or manual naming mechanisms that introduce human error through mistakes and misunderstandings. Naming conventions are incredibly important, but equally critical is how they&amp;rsquo;re implemented and maintained. Let&amp;rsquo;s explore a better approach.
What is a Naming Convention and Why Do We Need One?
A naming convention is a set of rules for naming Resource Groups and Resources (among other Azure components).</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>One of my bugbears is seeing either a complete lack of naming conventions or manual naming mechanisms that introduce human error through mistakes and misunderstandings. Naming conventions are incredibly important, but equally critical is how they&rsquo;re implemented and maintained. Let&rsquo;s explore a better approach.</p>
<p><strong>What is a Naming Convention and Why Do We Need One?</strong></p>
<p>A naming convention is a set of rules for naming Resource Groups and Resources (among other Azure components). These rules define the structure and composition of names, ensuring clarity, consistency, and compliance with Azure naming requirements such as length limits, valid characters, and scope uniqueness.</p>
<p>Common components that make up resource names include:</p>
<ul>
<li>Location</li>
<li>Environment</li>
<li>Project Prefix</li>
<li>Resource Abbreviation</li>
</ul>
<p>Naming conventions aren&rsquo;t one-size-fits-all and require tailoring to your specific needs. Any changes should be considered across all systems to maintain a single source of truth. Well-defined naming conventions significantly improve the readability and maintainability of your Azure estate, aligning with best practices outlined in the <a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming">Cloud Adoption Framework</a>.</p>
<p><strong>Example convention:</strong> <code>{Resource Type}-{Project}-{Environment}-{Location}</code><br>
<strong>Result:</strong> LogicAppName: <code>logic-btt-dev-ukwest</code></p>
<p><strong>Anti-patterns to Avoid</strong></p>
<blockquote>
<p><strong>Hard-coded resource names:</strong></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:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;MyLogicApp&#39;</span>
</span></span></code></pre></div><p><em>Issues:</em> Poor maintainability, readability, consistency, and convention adherence</p>
</blockquote>
<blockquote>
<p><strong>Hard-coded naming variables:</strong></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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">lgName</span> = <span style="color:#f1fa8c">&#39;MyLogicApp&#39;</span>
</span></span></code></pre></div><p><em>Issues:</em> Poor maintainability across templates, inconsistency, and no convention</p>
</blockquote>
<blockquote>
<p><strong>Hard-coded naming convention:</strong></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:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">lgName</span> = <span style="color:#f1fa8c">&#39;logic-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">project</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">location</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span></code></pre></div><p><em>Issues:</em> Poor maintainability across templates, template inconsistency, and scattered convention logic</p>
</blockquote>
<h2 id="recommended-approach">Recommended Approach</h2>
<p>My recommended approach leverages <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-functions">User-defined functions</a> to provide consistent and maintainable naming conventions. Combined with <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-import">Bicep Imports</a>, this ensures consistency across all templates.</p>
<p>For enhanced maintainability, I also recommend implementing <a href="/post/2025/07/bicep-tips-and-tricks-core-parameters-and-constructors/">centralized core parameters with types and constructors</a>. This approach significantly reduces the number of function parameters needed for each naming operation.</p>
<p><strong>Implementation Structure</strong></p>
<p>Create a <code>Common</code> folder within your IaC directory:</p>
<pre tabindex="0"><code>IaC
  ↳ Common
    ↳ types.bicep
    ↳ nameConventionFunctions.bicep
  ↳ main.bicep
</code></pre><ul>
<li><strong>types.bicep</strong> - Contains core parameter user-defined types and constructor functions</li>
<li><strong>nameConventionFunctions.bicep</strong> - Contains naming convention functions</li>
</ul>
<p><strong>Core Types Setup</strong></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">Shared</span> <span style="color:#8be9fd;font-style:italic">Types</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:#6272a4">// ** User Defined Types and Constructors **</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">// TYPE: Core 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">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Core Parameters Definition for Bicep Templates&#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">coreParams</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Location to deploy resources to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Location Short Name for resource naming&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">locationShortName</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;Environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</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;Project Prefix for resource naming&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Core Parameters Constructor&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">newCoreParams</span>(
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">locationShortName</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>) <span style="color:#8be9fd;font-style:italic">coreParams</span> =&gt; {
</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">locationShortName</span>: <span style="color:#8be9fd;font-style:italic">locationShortName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span>: <span style="color:#8be9fd;font-style:italic">projectPrefix</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>Naming Convention Functions</strong></p>
<p>I&rsquo;ve structured my naming conventions using these key parameters:</p>
<ul>
<li><strong>Resource Abbreviation</strong> - Identifies the resource type (<a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations">Azure abbreviations reference</a>)</li>
<li><strong>Project Prefix</strong> - Identifies the project</li>
<li><strong>Environment</strong> - Identifies the deployment environment</li>
<li><strong>Location</strong> - Identifies the deployment location (optional for global resources)</li>
<li><strong>Context</strong> - Describes the resource&rsquo;s purpose (optional)</li>
</ul>
<p>The following functions cover some common naming scenarios:</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">Name</span> <span style="color:#8be9fd;font-style:italic">Constructor</span> <span style="color:#8be9fd;font-style:italic">Functions</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:#6272a4">// ** Shared Imports **</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">import</span> { <span style="color:#8be9fd;font-style:italic">coreParams</span> } <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./types.bicep&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Resource Name Constructors</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">// Basic</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;Generates a resource name based on the provided parameters (used for common usage resources)&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">basicResource</span>(<span style="color:#8be9fd;font-style:italic">resourceAbbreviation</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</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">resourceAbbreviation</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">location</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:#50fa7b">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Generates a resource name based on the provided parameters but ignoring the location (used for common usage resources that are not location specific)&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">unlocalisedBasicResource</span>(<span style="color:#8be9fd;font-style:italic">resourceAbbreviation</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</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">resourceAbbreviation</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</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:#6272a4">// Context Specific</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;Generates a Context Specific Resource Name based on the provided parameters&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">csResource</span>(<span style="color:#8be9fd;font-style:italic">resourceAbbreviation</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>, <span style="color:#8be9fd;font-style:italic">contextName</span> <span style="color:#8be9fd;font-style:italic">string</span>) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</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">resourceAbbreviation</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">contextName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">location</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:#6272a4">// Resource Group</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;Generates a Resource Group name based on the provided parameters&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">resourceGroup</span>(<span style="color:#8be9fd;font-style:italic">contextName</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;rg-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">contextName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">location</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:#50fa7b">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Generates a Resource Group name based on the provided parameters but without an env specified&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">resourceGroupNonEnvSpecific</span>(<span style="color:#8be9fd;font-style:italic">contextName</span> <span style="color:#8be9fd;font-style:italic">string</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#f1fa8c">&#39;rg-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">contextName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">location</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-shared&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Storage Account</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;Generates a Storage Account Resource Name based on the provided parameters&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">storageAccountResource</span>(<span style="color:#8be9fd;font-style:italic">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</span>, <span style="color:#8be9fd;font-style:italic">contextName</span> <span style="color:#8be9fd;font-style:italic">string</span>?) <span style="color:#8be9fd;font-style:italic">string</span> =&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#50fa7b">empty</span>(<span style="color:#8be9fd;font-style:italic">contextName</span>)
</span></span><span style="display:flex;"><span>    ? <span style="color:#f1fa8c">&#39;st</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">locationShortName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    : <span style="color:#f1fa8c">&#39;st</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">contextName</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">locationShortName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span></code></pre></div><p><strong>Usage Example</strong></p>
<p>Here&rsquo;s how to use these functions in your main deployment template:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#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">Main</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">// ** Shared Imports **</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">import</span> { <span style="color:#8be9fd;font-style:italic">newCoreParams</span> } <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./Common/types.bicep&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">import</span> <span style="color:#ff79c6">*</span> <span style="color:#8be9fd;font-style:italic">as</span> <span style="color:#8be9fd;font-style:italic">newName</span> <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./Common/nameConventionFunctions.bicep&#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;Location to deploy resources to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Location Short Name for resource naming&#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">locationShortName</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;Environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">environment</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;Project Prefix for resource naming&#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">projectPrefix</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;myproject&#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">coreParameters</span> = <span style="color:#50fa7b">newCoreParams</span>(<span style="color:#8be9fd;font-style:italic">location</span>, <span style="color:#8be9fd;font-style:italic">locationShortName</span>, <span style="color:#8be9fd;font-style:italic">environment</span>, <span style="color:#8be9fd;font-style:italic">projectPrefix</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Standard Logic App Resource Names</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">logicAppName</span> = <span style="color:#8be9fd;font-style:italic">newName</span>.<span style="color:#50fa7b">basicResource</span>(<span style="color:#f1fa8c">&#39;logic&#39;</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">var</span> <span style="color:#8be9fd;font-style:italic">appServicePlanName</span> = <span style="color:#8be9fd;font-style:italic">newName</span>.<span style="color:#50fa7b">csResource</span>(<span style="color:#f1fa8c">&#39;asp&#39;</span>, <span style="color:#8be9fd;font-style:italic">coreParameters</span>, <span style="color:#f1fa8c">&#39;lg&#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">storageAccountName</span> = <span style="color:#8be9fd;font-style:italic">newName</span>.<span style="color:#50fa7b">storageAccountResource</span>(<span style="color:#8be9fd;font-style:italic">coreParameters</span>, <span style="color:#f1fa8c">&#39;lg&#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></span></code></pre></div><p><strong>Generated Names:</strong></p>
<ul>
<li><strong>Logic App:</strong> <code>logic-myproject-dev-ukwest</code></li>
<li><strong>App Service Plan:</strong> <code>asp-myproject-lg-dev-ukwest</code></li>
<li><strong>Storage Account:</strong> <code>stmyprojectlgdevukw</code></li>
</ul>
<h2 id="summary">Summary</h2>
<p>Implementing a robust naming convention is crucial for Azure resource management, but the mechanism matters just as much as the convention itself. By using Bicep user-defined functions combined with centralized core parameters, you can:</p>
<ul>
<li><strong>Eliminate human error</strong> from manual naming processes</li>
<li><strong>Ensure consistency</strong> across all templates and environments</li>
<li><strong>Improve maintainability</strong> with centralized naming logic</li>
<li><strong>Enhance readability</strong> of your Infrastructure as Code</li>
<li><strong>Align with best practices</strong> from the Cloud Adoption Framework</li>
</ul>
<p>This approach transforms naming from a scattered, error-prone process into a centralized, reliable system that scales with your infrastructure needs. The initial setup investment pays dividends in reduced maintenance overhead and improved deployment reliability. Happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #2 | Centralize Core Parameters with Types, Constructors, and Imports</title><link>https://andrewilson.co.uk/post/2025/07/bicep-tips-and-tricks-core-parameters-and-constructors/</link><pubDate>Wed, 23 Jul 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/07/bicep-tips-and-tricks-core-parameters-and-constructors/</guid><description>Overview When building IaC templates we strive to enable them to be environment agnostic, configurable even. One of the mechanisms that we do this is through lots of &amp;ldquo;Core Parameters&amp;rdquo; that disseminate the fundamental details of our deployment and resources. The number of core parameters is often variable but the verdict is always true, three or more usually does the trick. These Core Parameters are passed into the main deployment template and any other sub deployment template (Module) too.</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>When building IaC templates we strive to enable them to be environment agnostic, configurable even. One of the mechanisms that we do this is through lots of &ldquo;<em>Core Parameters</em>&rdquo; that disseminate the fundamental details of our deployment and resources. The number of core parameters is often variable but the verdict is always true, three or more usually does the trick. These Core Parameters are passed into the main deployment template and any other sub deployment template (Module) too. These may include but are not limited to:</p>
<ul>
<li>Environment</li>
<li>Location/Region</li>
<li>Project/Application Prefix</li>
</ul>
<p>But why am I going on about this, why is it a problem. Well it&rsquo;s not a problem as much as it&rsquo;s a readability and maintainability issue. Think about it, every template now requires three or more core parameters defined, with every module call having to define them as parameters to be passed in. Following this, if there is a change, the change will need to occur everywhere, and let&rsquo;s hope that the descriptions/metadata has been kept up to date too!</p>
<p>My recommendation to resolve this issue involves three Bicep concepts:</p>
<ol>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-data-types">User-defined data types</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/user-defined-functions">User-defined functions</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-import">Imports</a></li>
</ol>
<h2 id="recommendation-broken-down">Recommendation broken down</h2>
<p><strong>1. Define our source of truth Core Parameters | User-defined data type</strong></p>
<p>User-defined data types provide us a way to define our own data object containing all the core parameters that we use throughout such as the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#6272a4">// Bicep</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;Core Parameters Definition for Bicep Templates&#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">coreParams</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Location to deploy resources to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</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;Project Prefix for resource naming&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>The decorator <code>@sealed()</code> means that you are only permitting the use of properties specifically included in the type definition. This helps with making sure there is only one single source of truth for the coreParams definition.</p>
</blockquote>
<p>The type definition means that we can pass through a single parameter to our deployment templates, and manage change in a single place.</p>
<p><strong>2. Create a Constructor to setup our Core Parameters | User-defined function</strong></p>
<p>To aid in the initialization of the coreParams type, I typically create a user-defined function (<em>Constructor</em>) which sets up the initial state by assigning values to the respective properties. This ensures the Core Params object starts in a valid, predictable state. The function would look like this:</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:#6272a4">// Bicep</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;Core Parameters Constructor&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">newCoreParams</span>(
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>) <span style="color:#8be9fd;font-style:italic">coreParams</span> =&gt; {
</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">environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span>: <span style="color:#8be9fd;font-style:italic">projectPrefix</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>3. Promote Shared Use of the Type and Constructor | Imports</strong></p>
<p>The user defined type and function alone would not make this an effective recommendation due to the duplication of both the type and function definition on all templates. However, due to the recent introduction of exports and imports, we can continue on the path of a single and reusable single source of truth.</p>
<p>To make this work, what I would suggest is to create a new folder in your IaC location called <code>Common</code>, in this folder create a new <code>bicep</code> file called <code>types.bicep</code>. This is the shared bicep file that we are going to use for our new type and constructor.</p>
<p>An example of this setup is as follows:</p>
<ul>
<li><code>IaC → Common → types.bicep</code></li>
</ul>
<blockquote>
<p>Shared Types Template</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:#6272a4">// Bicep</span>
</span></span><span style="display:flex;"><span>
</span></span><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">Shared</span> <span style="color:#8be9fd;font-style:italic">Types</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:#6272a4">// ** User Defined Types and Constructors **</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">// TYPE: Core 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">export</span>()
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Core Parameters Definition for Bicep Templates&#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">coreParams</span> = {
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Location to deploy resources to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>  @<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</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;Project Prefix for resource naming&#39;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Core Parameters Constructor&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">func</span> <span style="color:#50fa7b">newCoreParams</span>(
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">environment</span> <span style="color:#8be9fd;font-style:italic">string</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span> <span style="color:#8be9fd;font-style:italic">string</span>
</span></span><span style="display:flex;"><span>) <span style="color:#8be9fd;font-style:italic">coreParams</span> =&gt; {
</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">environment</span>: <span style="color:#8be9fd;font-style:italic">environment</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">projectPrefix</span>: <span style="color:#8be9fd;font-style:italic">projectPrefix</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The <code>@export()</code> decorator is used to allow the type and function to be imported into other Bicep files.</p>
<p>Now we can use the import syntax in our main and sub deployment (module) templates, allowing use of the single defined type and function. In the main template we import the constructor and assign the initialized object to our coreParameters variable. For our sub deployment (module) templates we import the coreParams type so we can use it as a parameter definition. Both combined allow simplified module reference definitions and assignments. This can be seen in the following example templates:</p>
<blockquote>
<p>Main Deployment Template</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:#6272a4">// Bicep</span>
</span></span><span style="display:flex;"><span>
</span></span><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">Main</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">// ** Shared Imports **</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">import</span> { <span style="color:#8be9fd;font-style:italic">newCoreParams</span> } <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./Common/types.bicep&#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;Location to deploy resources to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">location</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span 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;Environment to deploy to&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">param</span> <span style="color:#8be9fd;font-style:italic">environment</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;Project Prefix for resource naming&#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">projectPrefix</span> <span style="color:#8be9fd;font-style:italic">string</span> = <span style="color:#f1fa8c">&#39;myProject&#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">coreParameters</span> = <span style="color:#50fa7b">newCoreParams</span>(<span style="color:#8be9fd;font-style:italic">location</span>, <span style="color:#8be9fd;font-style:italic">environment</span>, <span style="color:#8be9fd;font-style:italic">projectPrefix</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;Demonstration of the core parameters being passed to a submodule&#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">subDeploy</span> <span style="color:#f1fa8c">&#39;./subDeploy.bicep&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;subDeploy&#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">coreParameters</span>: <span style="color:#8be9fd;font-style:italic">coreParameters</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>Sub Deployment (Module) Template</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:#6272a4">// Bicep</span>
</span></span><span style="display:flex;"><span>
</span></span><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">Resources</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">// ** Shared Imports **</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">import</span> { <span style="color:#8be9fd;font-style:italic">coreParams</span> } <span style="color:#8be9fd;font-style:italic">from</span> <span style="color:#f1fa8c">&#39;./Common/types.bicep&#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;Core Parameters for the deployment&#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">coreParameters</span> <span style="color:#8be9fd;font-style:italic">coreParams</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;The name of the resource to deploy&#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">resourceName</span> = <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">projectPrefix</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">coreParameters</span>.<span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-resource&#39;</span>
</span></span></code></pre></div><h2 id="summary">Summary</h2>
<p>Managing core parameters in Bicep templates can quickly become unwieldy as your infrastructure grows. By leveraging user-defined types, constructors, and imports, you can centralize your parameter definitions, improve readability, and simplify maintenance. This approach ensures consistency across your deployments and makes future changes easier to manage. Happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep Tips and Tricks | #1 | Template Versioning and Applying to Azure Resource Tags</title><link>https://andrewilson.co.uk/post/2025/07/bicep-template-versioning-resource-tags-tips-tricks-azure-devops/</link><pubDate>Wed, 16 Jul 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/07/bicep-template-versioning-resource-tags-tips-tricks-azure-devops/</guid><description>The first of many For those who know me well, starting a bicep tips and tricks series would not be a surprise to them. The moment the Bicep language was introduced, I knew I would be completely obsessed. I love writing bicep templates and even more the clever refinement to make them reusable, configurable, manageable, readable&amp;hellip; I really enjoy sharing my experiences with Bicep, so here it begins on the wider front.</description><content:encoded><![CDATA[<h2 id="the-first-of-many">The first of many</h2>
<p>For those who know me well, starting a bicep tips and tricks series would not be a surprise to them. The moment the Bicep language was introduced, I knew I would be completely obsessed. I love writing bicep templates and even more the clever refinement to make them reusable, configurable, manageable, readable&hellip; I really enjoy sharing my experiences with Bicep, so here it begins on the wider front. From one Bicep nerd to another, I hope you find these tips useful, happy templating!</p>
<h2 id="why-is-versioning-important">Why is versioning important</h2>
<p>Versioning is a fundamental practice in software development that helps us manage change effectively. It provides a structured way to track and communicate updates, ensuring clarity and consistency throughout the development lifecycle.</p>
<ul>
<li>
<p>Why apply a version to your templates?</p>
<p>Applying versioning to templates ensures you can track changes, maintain consistency, and know exactly which version of your infrastructure code was used for any deployment. It supports best practices like binary promotion, simplifies troubleshooting, and helps teams coordinate updates and rollbacks with confidence.</p>
</li>
<li>
<p>Why apply the version as a tag to Azure Resources?</p>
<p>Tagging Azure resources with the template version gives you direct visibility into what was deployed, right from the Azure portal or API. This makes audits, governance, and troubleshooting much easier, as you can instantly see which template version created or updated a resource. It also helps correlate infrastructure changes with application releases and supports compliance requirements for traceability.</p>
</li>
</ul>
<p>ARM templates have a Json property right at the top of the file underneath <code>$schema</code> called <code>contentVersion</code>. By default and if never changed, this will always be <code>1.0.0.0</code>. As part of our versioning practice we can make sure that the templates that we deploy make use of the same version that is applied to other built artifacts. This allows us to track deployments and their respective templates through versions.</p>
<h2 id="how-to-version-templates-using-azure-devops">How to version templates using Azure DevOps</h2>
<p>As part of a YAML CI/CD pipeline I typically have a build stage, with a inner Test and Version ARM Templates Job. The focus of the job is to do two things:</p>
<ol>
<li>Using the az cli - Build the Bicep templates
<ul>
<li>I also include the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/linter">Bicep linting file</a>, this means that as the templates are being transpiled into ARM I am also getting any build errors and warnings. I output these as logissues to the Azure DevOps Pipeline for visibility.</li>
</ul>
</li>
<li>Version the built ARM JSON artifacts to support Binary promotion and align with versioning practices.</li>
</ol>
<p>I use the following tasks to complete the tasks:</p>
<ol>
<li><strong>AzureCLI@2</strong> - used to build the Bicep templates (transpile into ARM) and log any warnings or errors.</li>
<li><strong><a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task">VersionJSONFile@3</a></strong> - used to version stamp the ARM templates.</li>
<li><strong>CopyFiles@2</strong> - Used to copy the versioned ARM artifacts to the staging directory.</li>
<li><strong>PublishPipelineArtifact@1</strong> - used to publish the ARM artifacts to the pipeline so they can be downloaded in future deployment stages.</li>
</ol>
<p>Here is a sample YAML template:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#6272a4"># Yaml</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">task</span>: AzureCLI@2
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">displayName</span>: <span style="color:#f1fa8c">&#39;Build Bicep Files&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">inputs</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">azureSubscription</span>: <span style="color:#f1fa8c">&#39;xxyyzz&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">scriptType</span>: <span style="color:#f1fa8c">&#39;ps&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">scriptLocation</span>: <span style="color:#f1fa8c">&#39;inlineScript&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">useGlobalConfig</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">powershellerrorActionPreference</span>: <span style="color:#f1fa8c">&#39;continue&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">inlineScript</span>: |<span style="color:#f1fa8c">
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">      # create folder if it doesn&#39;t exist
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">      if (!(Test-Path -Path $(Build.SourcesDirectory)\{YourPath}\IAC\ARMOutput)) {
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">        New-Item -ItemType Directory -Path $(Build.SourcesDirectory)\{YourPath}\IAC\ARMOutput
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">      }
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">      write-host &#34;Build the Bicep file&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#f1fa8c">      $output = az bicep build --file $(Build.SourcesDirectory)\{YourPath}\IAC\template.azuredeploy.bicep --outdir $(Build.SourcesDirectory)\{YourPath}\IAC\ARMOutput 2&gt;&amp;1</span>      
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      write-host &#34;Process the output&#34;
</span></span><span style="display:flex;"><span>      $output | foreach-object {
</span></span><span style="display:flex;"><span>         if ($_ -match &#39;Error&#39;) {
</span></span><span style="display:flex;"><span>            Write-Host &#34;##vso[task.logissue type=error]$_&#34;
</span></span><span style="display:flex;"><span>         } 
</span></span><span style="display:flex;"><span>         if ($_ -match &#39;Warning&#39;) {
</span></span><span style="display:flex;"><span>             Write-Host &#34;##vso[task.logissue type=warning]$_&#34;
</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">task</span>: VersionJSONFile@3
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">displayName</span>: <span style="color:#f1fa8c">&#39;Version stamp ARM templates&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">inputs</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">Path</span>: <span style="color:#f1fa8c">&#39;$(Build.SourcesDirectory)\{YourPath}\IAC\ARMOutput&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">recursion</span>: <span style="color:#ff79c6">True</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">VersionNumber</span>: $(Build.BuildNumber) <span style="color:#6272a4"># an example versioning option but can also be options like gitversion</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">useBuildNumberDirectly</span>: <span style="color:#ff79c6">False</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">VersionRegex</span>: \d+\.\d+\.\d+\.\d+
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">versionForJSONFileFormat</span>: <span style="color:#f1fa8c">&#39;{1}.{2}.{3}.{4}&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">FilenamePattern</span>: <span style="color:#f1fa8c">&#39;\w+.json&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">Field</span>: <span style="color:#f1fa8c">&#39;contentVersion&#39;</span> <span style="color:#6272a4"># Versioning is applied to the templates contentVersion field</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">OutputVersion</span>: OutputedVersion
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>- <span style="color:#ff79c6">task</span>: CopyFiles@2
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">displayName</span>: <span style="color:#f1fa8c">&#39;Copy ARMOutput to Artifact Staging Directory&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">inputs</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">SourceFolder</span>: <span style="color:#f1fa8c">&#39;$(Build.SourcesDirectory)\{YourPath}\IAC\ARMOutput&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">Contents</span>: <span style="color:#f1fa8c">&#39;**/*.json&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">TargetFolder</span>: <span style="color:#f1fa8c">&#39;$(Build.ArtifactStagingDirectory)/templates&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">flattenFolders</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>- <span style="color:#ff79c6">task</span>: PublishPipelineArtifact@1
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">displayName</span>: <span style="color:#f1fa8c">&#39;Publish ARMOutput as template build artifact&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">inputs</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">targetPath</span>: <span style="color:#f1fa8c">&#39;$(Build.ArtifactStagingDirectory)/templates&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">publishLocation</span>: <span style="color:#f1fa8c">&#39;pipeline&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">artifactName</span>: <span style="color:#f1fa8c">&#39;ARMtemplates&#39;</span>
</span></span></code></pre></div><p>This setup ensures your ARM templates are built, versioned, and published as pipeline artifacts in a repeatable, traceable way. By stamping each template with a version number and making it available as an artifact, you enable binary promotion through environments and make it easy to track exactly which template version was used for each deployment. This improves auditability, supports rollback scenarios, and aligns with best practices for infrastructure as code in CI/CD pipelines.</p>
<h2 id="how-to-apply-the-template-version-as-a-tag-to-azure-resources">How to apply the template version as a tag to Azure Resources</h2>
<p>Versioning our ARM templates is one part of the transparency and traceability. But it would also be nice to be able to see which template version deployed the Azure Resources from the Azure Resources themselves. We can do this by applying a tag onto our resources and tying it back to our ARM <code>contentVersion</code> property field. We can do this by using the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-deployment#deployment"><code>deployment()</code></a> function as such <code>deployment().properties.template.contentVersion</code>.</p>
<p>On a resource it would look like the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#6272a4">// Bicep</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">AppService</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2024-11-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">appServiceName</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></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></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Applying template versioning and tagging resources with the deployed template’s version brings transparency and traceability to your Azure infrastructure. You’ll always know which version of your code and templates are running in each environment, making troubleshooting and governance much easier. These small practices help teams stay organised, reduce deployment risks, and build confidence in their automation. Happy Bicep-ing!</p>
]]></content:encoded></item><item><title>Bicep | Existing Resource Dependencies</title><link>https://andrewilson.co.uk/post/2025/03/bicep-existing-resource-dependencies/</link><pubDate>Wed, 26 Mar 2025 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2025/03/bicep-existing-resource-dependencies/</guid><description>Background The Bicep existing keyword is a powerful capability that allows us to reference a resource that wasn&amp;rsquo;t deployed as part of the current Bicep file.
One of the typical use cases that I often see is where a resource is deployed as part of a module called by the parent template, the resource that was deployed as part of the module is then required later in the parent template and therefore an existing resource definition is used.</description><content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>The Bicep <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/existing-resource">existing</a> keyword is a powerful capability that allows us to reference a resource that wasn&rsquo;t deployed as part of the current Bicep file.</p>
<p>One of the typical use cases that I often see is where a resource is deployed as part of a module called by the parent template, the resource that was deployed as part of the module is then required later in the parent template and therefore an existing resource definition is used. As part of the template configuration there would be an explicit dependency between the existing resource definition and the module reference.</p>
<p>An example diagram of this is shown below:</p>
<p>
  <img src="/images/posts/2025/03/BicepExistingDependencyDiagramBackground.png" alt="Background">

</p>
<p>For Bicep v0.34.1 and lower, there are two scenarios that can be observed when deploying the templates:</p>
<ul>
<li>Scenario 1: Successful deployment. The existing resource has been found and the explicit dependency between Existing Resource and Module Ref 1 has been honoured.</li>
<li>Scenario 2: Deployment Failure. <code>The Resource XYZ under resource group 'XXYYZZ' was not found.</code>. The existing resource has not been found and the explicit dependency between Existing Resource and Module Ref 1 has not been honoured.</li>
</ul>
<p>For most that fall into scenario 2, without much explanation of what may be going on behind the scenes, their typical solution to this particular problem may be to force the dependency chaining by extracting further of the parent template into a further module.</p>
<p>An example of this can be seen below:</p>
<p>
  <img src="/images/posts/2025/03/BicepExistingDependencyDiagramMidSolution.png" alt="MidSolution">

</p>
<p>Yes this is a valid solution, but why is there a problem in the first place?</p>
<h2 id="explanation">Explanation</h2>
<p>It all comes down to whether your template is compiled with <strong>symbolic name code generation</strong>.</p>
<p><a href="https://github.com/Azure/bicep/blob/main/docs/experimental-features.md#symbolicnamecodegen">Symbolic Name Code Generation</a> allows the ARM template layer to use a new schema to represent resources as an object dictionary rather than an array of objects. This feature improves the semantic equivalence of the Bicep and ARM templates, resulting in more reliable code generation.</p>
<p>In a symbolic name template, an existing resource can depend on other resources or modules, and this will <strong>cause the backend to delay reading the resource until those dependencies are completed</strong>. This allows you to deploy a resource in a module, then refer to it with an existing declaration in the module parent. In <strong>non-symbolic name templates</strong>, existing resources are compiled to reference(resourceId()) expressions and are all <strong>handled in the first wave of deployment jobs</strong>.</p>
<p>In a non-symbolic name compiled template the existing reference looks like this:</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">reference</span>(<span style="color:#50fa7b">resourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.xxx/yyy&#39;</span>, <span style="color:#50fa7b">parameters</span>(<span style="color:#f1fa8c">&#39;resourceName&#39;</span>))), <span style="color:#f1fa8c">&#39;2023-05-01&#39;</span>, <span style="color:#f1fa8c">&#39;full&#39;</span>)
</span></span></code></pre></div><p>In a symbolic name compiled template the existing reference and dependencies look like this:</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">reference</span>(<span style="color:#f1fa8c">&#39;existingResource&#39;</span>, <span style="color:#f1fa8c">&#39;2023-05-01&#39;</span>, <span style="color:#f1fa8c">&#39;full&#39;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&#34;<span style="color:#8be9fd;font-style:italic">dependsOn</span>&#34;: [
</span></span><span style="display:flex;"><span>  &#34;<span style="color:#8be9fd;font-style:italic">existingResource</span>&#34;,
</span></span><span style="display:flex;"><span>  &#34;<span style="color:#8be9fd;font-style:italic">ModuleRef1</span>&#34;
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>This explains why in some template deployment cases the deployment succeeds and in others it fails (the template is not setup for symbolic name code generation). But how do you enable symbolic name code generation?</p>
<h2 id="solution">Solution</h2>
<p>Symbolic name code generation is part of the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/syntax#languageversion-20">languageVersion 2.0</a> functionality and can be enabled <strong>automatically</strong> by using any of the following Bicep Features:</p>
<ul>
<li>user-defined types</li>
<li>user-defined functions</li>
<li>compile-time imports</li>
<li>experimental features</li>
</ul>
<p>For most of you up until this point like me, you will have unintentionally and thankfully enabled symbolic name code generation by using features as described above and therefore not suffered from the problem case as described.</p>
<p>Symbolic name code generation can also be <strong>explicitly</strong> enabled by adding the following to your <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-config">bicepconfig.json</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-json" data-lang="json"><span style="display:flex;"><span>	<span style="color:#f1fa8c">&#34;experimentalFeaturesEnabled&#34;</span>: {
</span></span><span style="display:flex;"><span>		<span style="color:#ff79c6">&#34;symbolicNameCodegen&#34;</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>	 }
</span></span></code></pre></div><p>Or the <strong>preferred option</strong> use <strong>Bicep <a href="https://github.com/Azure/bicep/releases/tag/v0.34.44">v0.34.44</a></strong> or higher where languageVersion2.0 is used automatically when an existing resource has an <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/resource-dependencies#explicit-dependency">explicit DependsOn dependency</a> stipulated.</p>
<p>If you are unsure as to whether your templates are compiled using symbolic name code generation, have a look at the first few lines of your compiled Bicep template. The ARM template should specify languageVersion 2.0 if enabled and missing this line if not.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;$schema&#34;</span>: <span style="color:#f1fa8c">&#34;https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;languageVersion&#34;</span>: <span style="color:#f1fa8c">&#34;2.0&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;contentVersion&#34;</span>: <span style="color:#f1fa8c">&#34;1.0.0.0&#34;</span>,
</span></span></code></pre></div><p>Hope this helps and have fun.</p>
]]></content:encoded></item><item><title>Bicep | Prevent a Nasty Refactor with Function Namespaces</title><link>https://andrewilson.co.uk/post/2024/05/bicep-function-namespaces/</link><pubDate>Mon, 27 May 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/05/bicep-function-namespaces/</guid><description>Problem Space There have been few times where I have landed into this particular predicament whereby either by my own doing or through the use of another&amp;rsquo;s code base, a deep nested or thoroughly utilised (parameter/variable/or other defined item) has been created with the same name as a Bicep function. As by Murphy&amp;rsquo;s law, its only once you have reached this point of no return that you realise that your items name conflicts.</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>There have been few times where I have landed into this particular predicament whereby either by my own doing or through the use of another&rsquo;s code base, a deep nested or thoroughly utilised (parameter/variable/or other defined item) has been created with the same name as a Bicep function. As by Murphy&rsquo;s law, its only once you have reached this point of no return that you realise that your items name conflicts.</p>
<p>Now if you are like many in your unawares, your thoughts and actions will conclude to a singular one of <em>&rsquo;that sucks&hellip; followed by a nasty refactor</em>'.</p>
<h2 id="solution---namespaces">Solution - Namespaces</h2>
<p>Namespaces are a declarative scope in which identifiers such as the names of types, functions, and variables can be declared. These namespaces are used to organise code into logical groups and to prevent name collisions such as the one you are currently experiencing.</p>
<p>Thankfully, in <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions#namespaces-for-functions">Bicep there are two namespaces</a> where all functions are split, <code>az</code> and <code>sys</code>.</p>
<ul>
<li><strong>az</strong> | Contains functions that are specific to an Azure deployment such as:
<ul>
<li>deployment</li>
<li>environment</li>
<li>resourceGroup</li>
<li>subscription</li>
</ul>
</li>
<li><strong>sys</strong> | Contains functions that are used to construct values, and decorators for parameters and resource loops. This includes but is not limited to:
<ul>
<li>[<strong>Array</strong>] concat</li>
<li>[<strong>File</strong>] loadJsonContent</li>
<li>[<strong>Lambda</strong>] filter</li>
<li>[<strong>Logical</strong>] bool</li>
<li>[<strong>Numeric</strong>] int</li>
<li>[<strong>String</strong>] contains</li>
</ul>
</li>
</ul>
<p>To make use of these namespaces, simply add the namespace identifier in front of the function. The example below shows a real world example of this issue where a parameter name &lsquo;<em>environment</em>&rsquo; has been extensively utilised in this template and many others. This particular template is being used to deploy an AuthProvider in API Management, and the author wishes to utilise the environment function for the <code>authentication.loginEndpoint</code>. Without the use of the az namespace, the environment parameter would need to be refactored both in this template and wider templates for consistency.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#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">Namespace</span> <span style="color:#8be9fd;font-style:italic">Example</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 environment to deploy the resources 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">environment</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></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">ApiManagementName</span> = <span style="color:#50fa7b">toLower</span>(<span style="color:#f1fa8c">&#39;apim-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">projectName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">environment</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">location</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:#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></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4">// Create a new Auth Provider in APIM Credential Manager</span>
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">AuthorizationProvider</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/authorizationProviders@2023-05-01-preview&#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 style="color:#8be9fd;font-style:italic">oauth2</span>: {
</span></span><span style="display:flex;"><span>      ...
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">grantTypes</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">clientCredentials</span>: {
</span></span><span style="display:flex;"><span>          <span style="color:#8be9fd;font-style:italic">loginUri</span>: <span style="color:#8be9fd;font-style:italic">az</span>.<span style="color:#50fa7b">environment</span>().<span style="color:#8be9fd;font-style:italic">authentication</span>.<span style="color:#8be9fd;font-style:italic">loginEndpoint</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>As always, have a play, and hope this helps.</p>
]]></content:encoded></item></channel></rss>