<?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>Roles on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/tags/roles/</link><description>Recent content in Roles on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 22 Nov 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/tags/roles/index.xml" rel="self" type="application/rss+xml"/><item><title>Azure RBAC Key Vault | Role Assignment for Specific Secret</title><link>https://andrewilson.co.uk/post/2023/11/rbac-key-vault-specific-secret/</link><pubDate>Wed, 22 Nov 2023 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2023/11/rbac-key-vault-specific-secret/</guid><description>Background Azure role-based access control (Azure RBAC) provides fine grained control over access to Azure resources. Azure RBAC is founded on top of the Azure Resource Manager which allows us to provide access authorisation at differing scope levels ranging from the Management Group through to individual resources.
With RBAC enabled key vaults we can manage access to the resource and data stored in the vault. We can also manage access for individual keys, secrets, and certificates.</description><content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>Azure role-based access control (Azure RBAC) provides fine grained control over access to Azure resources. Azure RBAC is founded on top of the Azure Resource Manager which allows us to provide access authorisation at differing scope levels ranging from the Management Group through to individual resources.</p>
<p>With RBAC enabled key vaults we can manage access to the resource and data stored in the vault. We can also manage access for individual keys, secrets, and certificates.</p>
<h2 id="scenario">Scenario</h2>
<p>
  <img src="/images/posts/2023/11/KVScenario.png" alt="Key Vault RBAC Scenario">

</p>
<p>In this scenario we have an application that has stored all its secrets in its own application specific key vault. Part of this application makes use of an Azure Function that we would like to place into Azure API Management (APIM).</p>
<blockquote>
<p>An Application can be a single or group of related services.</p>
</blockquote>
<p>When deploying the Azure Function we are placing the Function Authorisation Key into the Application Specific Key Vault. As part of the APIM API Backend we would like to add the Function Authorisation Key as a header and obtain this key from the application specific key vault.</p>
<p>If we provide APIM access to the entire application key vault we would be compromising our security boundary.</p>
<blockquote>
<p><strong><a href="https://learn.microsoft.com/en-us/azure/key-vault/general/best-practices">Best Practice</a></strong></p>
<p>Security Boundary - We do not want to provide complete access to the application Key Vault. If there is a breach of security we do not want to compromise the application and widen the blast radius.</p>
</blockquote>
<p>To mitigate this, we can specify granular access to the specific secret in the key vault that APIM requires. In this case, if there were to be a security breach, we have limited the reach and access to which damage could spread.</p>
<h2 id="solution">Solution</h2>
<p>To setup the RBAC permission between APIM and the application specific Key Vault, we will need to have the following configured:</p>
<ol>
<li>For a deployment principle to add role assignments, you must have Microsoft.Authorization/roleAssignments/write and Microsoft.Authorization/roleAssignments/delete permissions setup, such as one of the following:
<ul>
<li><a href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#key-vault-data-access-administrator-preview">Key Vault Data Access Administrator (preview)</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#user-access-administrator">User Access Administrator</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner">Owner</a></li>
</ul>
</li>
<li>Make sure your Application Key Vault is RBAC Enabled.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">symbolicname</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2022-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;string&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#f1fa8c">&#39;string&#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">enableRbacAuthorization</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="3">
<li>Azure API Management is setup to use <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity">System Assigned Managed Identity</a>.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">symbolicname</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service@2023-03-01-preview&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">location</span>: <span style="color:#f1fa8c">&#39;string&#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></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">identity</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">type</span>: <span style="color:#f1fa8c">&#39;SystemAssigned&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    ...
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="4">
<li>The Azure Function Auth Key added into Key Vault as a secret.</li>
</ol>
<blockquote>
<p>Note: The function default host key is created and only accessible after the function code is provisioned. The following IaC would need to be conducted as a secondary deployment.</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:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the Application Key Vault instance to store secrets&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">keyVault</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults@2023-07-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">keyVaultName</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Retrieve the Function App for linking as a backend&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">functionApp</span> <span style="color:#f1fa8c">&#39;Microsoft.Web/sites@2022-09-01&#39;</span> <span style="color:#8be9fd;font-style:italic">existing</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">functionName</span>
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Vault the Function App Key as a secret&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">vaultFunctionAppKey</span> <span style="color:#f1fa8c">&#39;Microsoft.KeyVault/vaults/secrets@2023-07-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;functionAppKey&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">keyVault</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">contentType</span>: <span style="color:#f1fa8c">&#39;string&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">value</span>: <span style="color:#50fa7b">listkeys</span>(<span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">functionApp</span>.<span style="color:#8be9fd;font-style:italic">id</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/host/default/&#39;</span>, <span style="color:#f1fa8c">&#39;2021-02-01&#39;</span>).<span style="color:#8be9fd;font-style:italic">functionkeys</span>.<span style="color:#8be9fd;font-style:italic">default</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="5">
<li>Grant APIM Identity Role permissions to access the Key Vault Secret
<ul>
<li>Granting <a href="https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide?tabs=azure-cli#azure-built-in-roles-for-key-vault-data-plane-operations">Key Vault Reader</a> Role.</li>
<li>Property Scope is pointing at the Key Vault Secret so access is confined to only that secret.</li>
</ul>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;APIM Instance&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">apimInstance</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apimInstanceName</span>
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Grant APIM Key Vault Reader for the function API key secret&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">grantAPIMPermissionsToSecret</span> <span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleAssignments@2022-04-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#50fa7b">guid</span>(<span style="color:#8be9fd;font-style:italic">keyVault</span>.<span style="color:#8be9fd;font-style:italic">id</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">scope</span>: <span style="color:#8be9fd;font-style:italic">vaultFunctionAppKey</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">roleDefinitionId</span>: <span style="color:#50fa7b">subscriptionResourceId</span>(<span style="color:#f1fa8c">&#39;Microsoft.Authorization/roleDefinitions&#39;</span>, <span style="color:#f1fa8c">&#39;4633458b-17de-408a-b874-0445c86b69e6&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalId</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>.<span style="color:#8be9fd;font-style:italic">identity</span>.<span style="color:#8be9fd;font-style:italic">principalId</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">principalType</span>: <span style="color:#f1fa8c">&#39;ServicePrincipal&#39;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ol start="6">
<li>Setup a APIM Backend with a Named Value to make use of the Key Vault Secret</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bicep" data-lang="Bicep"><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the backend for the Function API&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">functionBackend</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/backends@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#8be9fd;font-style:italic">apiName</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">protocol</span>: <span style="color:#f1fa8c">&#39;http&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">url</span>: <span style="color:#f1fa8c">&#39;https://</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">functionApp</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">defaultHostName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">/api&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">resourceId</span>: <span style="color:#f1fa8c">&#39;https://management.azure.com</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">functionApp</span>.<span style="color:#8be9fd;font-style:italic">id</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">tls</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">validateCertificateChain</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">validateCertificateName</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">credentials</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">header</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f1fa8c">&#39;x-functions-key&#39;</span>: [
</span></span><span style="display:flex;"><span>          <span style="color:#f1fa8c">&#39;{{</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key}}&#39;</span>
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dependsOn</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">functionBackendNamedValues</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@<span style="color:#50fa7b">description</span>(<span style="color:#f1fa8c">&#39;Create the named value for the function API backend&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">resource</span> <span style="color:#8be9fd;font-style:italic">functionBackendNamedValues</span> <span style="color:#f1fa8c">&#39;Microsoft.ApiManagement/service/namedValues@2022-08-01&#39;</span> = {
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">name</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#39;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">parent</span>: <span style="color:#8be9fd;font-style:italic">apimInstance</span>
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">properties</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">displayName</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">apiName</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">-key&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">tags</span>: [
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;key&#39;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f1fa8c">&#39;function&#39;</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">secret</span>: <span style="color:#ff79c6">true</span>
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">keyVault</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">identityClientId</span>: <span style="color:#ff79c6">null</span>
</span></span><span style="display:flex;"><span>      <span style="color:#8be9fd;font-style:italic">secretIdentifier</span>: <span style="color:#f1fa8c">&#39;</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">keyVault</span>.<span style="color:#8be9fd;font-style:italic">properties</span>.<span style="color:#8be9fd;font-style:italic">vaultUri</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">secrets/</span><span style="color:#f1fa8c">${</span><span style="color:#8be9fd;font-style:italic">vaultFunctionAppKey</span>.<span style="color:#8be9fd;font-style:italic">name</span><span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#8be9fd;font-style:italic">dependsOn</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#8be9fd;font-style:italic">grantAPIMPermissionsToSecret</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="summary">Summary</h2>
<p>And there we have it, APIM now has granular access to the secrets it requires without compromising our security boundaries that have been put in place to protect the backing application.</p>
<p>Have a play and have fun.</p>
]]></content:encoded></item><item><title>Azure Role Assignment</title><link>https://andrewilson.co.uk/post/2022/09/azure-assign-role/</link><pubDate>Fri, 02 Sep 2022 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2022/09/azure-assign-role/</guid><description>Problem Space: I recently came into some issues with assigning Azure roles through a Bicep template and pipeline deployment. I was looking to assign &amp;lsquo;Storage Blob Data Reader&amp;rsquo; to a service principal, and refine their access to only the container of the storage account. The three main issues that I ran into were:
What are Role Assignment Conditions and how can I use them in my template? I am trying to assign a built in role, what is the roleDefinitionId that I should be using?</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space:</h2>
<p>I recently came into some issues with assigning Azure roles through a Bicep template and pipeline deployment. I was looking to assign &lsquo;<em>Storage Blob Data Reader</em>&rsquo; to a service principal, and refine their access to only the container of the storage account. The three main issues that I ran into were:</p>
<ol>
<li>What are <a href="#role-assignment-conditions">Role Assignment Conditions</a> and how can I use them in my template?</li>
<li>I am trying to assign a built in role, what is the <a href="#identifying-the-role-definition-id">roleDefinitionId</a> that I should be using?</li>
<li>I am trying to assign the role to a <a href="#referencing-a-service-principal-id">service principal user</a>, what id should I be referencing in the template?</li>
</ol>
<p>For reference, the Bicep template for role assignment<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> that I am using is shown below:</p>
<pre tabindex="0"><code>resource symbolicname &#39;Microsoft.Authorization/roleAssignments@2022-04-01&#39; = {
  name: &#39;string&#39;
  scope: resourceSymbolicName or tenant()
  properties: {
    condition: &#39;string&#39;
    conditionVersion: &#39;string&#39;
    delegatedManagedIdentityResourceId: &#39;string&#39;
    description: &#39;string&#39;
    principalId: &#39;string&#39;
    principalType: &#39;string&#39;
    roleDefinitionId: &#39;string&#39;
  }
}
</code></pre><p>Just in case you are new to this and require a bit more information on role assignments, Azure role assignments are used to provide a security principal access to Azure resources. Assignments are built up of three main components<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> :</p>
<ol>
<li><strong>Security Principal</strong> - this is the user, group, service principal, or managed identity that the role is going to be assigned to.</li>
<li><strong>Role Definition</strong> - this is the built in or custom defined collection of permissions that is to be assigned to the security principal.</li>
<li><strong>Scope</strong> - this is the set of resources that the permissions apply to. You can assign roles at four different scope levels:
<ul>
<li>Management Group
<ul>
<li>Subscription
<ul>
<li>Resource group
<ul>
<li>Resource</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>With that in mind, lets look into the problems I was having.</p>
<h3 id="role-assignment-conditions">Role Assignment Conditions</h3>
<p>As per <a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format">Microsoft Documentation</a>, &lsquo;<em>a condition is an additional check that you can optionally add to your role assignment to provide more fine-grained access control. For example, you can add a condition that requires an object to have a specific tag to read the object.</em>&rsquo; Or in my case, as mentioned above, I would like to refine my service principals access to a specific container on the storage account.</p>
<p>The Bicep template takes your defined condition as a string, so lets look at the syntax and format of the condition that makes up this string.</p>
<h4 id="syntax-of-a-simple-condition">Syntax of a simple condition</h4>
<p>Conditions are made up of a mixture of actions and expressions.</p>
<ul>
<li>An action is an operation that a user can perform on a resource type.</li>
<li>An expression is a statement that evaluates to true or false, which determines whether the action is allowed to be performed.</li>
</ul>
<h5 id="action-condition">Action Condition</h5>
<p>Syntax for an action condition:</p>
<pre tabindex="0"><code>(
  (
    ActionMatches{&#39;&lt;action&gt;&#39;}
  )
)
</code></pre><p>The value that you replace &lsquo;<em><code>&lt;action&gt;</code></em>&rsquo; with is the action namespace such as &lsquo;<em>Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read</em>&rsquo;. For a storage account, you can find a list of these defined actions and examples <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-abac-attributes">here</a>.</p>
<h5 id="expression-condition">Expression Condition</h5>
<p>Syntax for an expression condition:</p>
<pre tabindex="0"><code>(
  (
    &lt;attribute&gt; &lt;operator&gt; &lt;value&gt;
  )
)
</code></pre><p>The values that you replace &lsquo;<em><code>&lt;attribute&gt;</code></em>&rsquo; with can be one of the following:</p>
<ul>
<li>Resource - <em>Indicates that the attribute is on the resource, such as a container name.</em>
<ul>
<li>Example <em><code>@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name]</code></em></li>
</ul>
</li>
<li>Request - <em>Indicates that the attribute is part of the action request, such as setting the blob index tag.</em>
<ul>
<li>Example <em><code>@Request[Microsoft.Storage/storageAccounts/blobServices/containers/blobs:snapshot]</code></em></li>
</ul>
</li>
<li>Principal - <em>Indicates that the attribute is an Azure AD custom security attribute on the principal, such as a user, enterprise application (service principal), or managed identity.</em>
<ul>
<li>Example <em><code>@Principal[Microsoft.Directory/CustomSecurityAttributes/Id:Engineering_Project]</code></em></li>
</ul>
</li>
</ul>
<h5 id="operators">Operators</h5>
<p>The values that you replace &lsquo;<em><code>&lt;operator&gt;</code></em>&rsquo; indicate how the attribute is to be evaluated. These are split between:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#function-operators">Function Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#logical-operators">Logical Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#boolean-comparison-operators">Boolean Comparison Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#string-comparison-operators">String Comparison Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#numeric-comparison-operators">Numeric Comparison Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#datetime-comparison-operators">DateTime Comparison Operators</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format#cross-product-comparison-operators">Cross Product Comparison Operators</a></li>
</ul>
<p>Lastly &lsquo;<em><code>&lt;value&gt;</code></em>&rsquo; will be replaced with what you are expecting the attribute to equate to.</p>
<h5 id="identifying-my-condition">Identifying My Condition</h5>
<p>These action and attribute conditions can be combined to create simple and far more complex conditions to suit your needs, see <a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/conditions-format">documentation</a> for more.</p>
<p>In my case, I would like a simple condition that will only allow my service principal access to read blobs within a specific storage account container. Therefore, using the syntax above, my condition will look like the following:</p>
<pre tabindex="0"><code>( &lt;-- Condition
  @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] &lt;-- Attribute
  StringEqualsIgnoreCase &lt;-- Operation
  &#39;nameOfContainer&#39; &lt;-- Value
)
</code></pre><p>To place this within a Bicep template, make sure to escape your single quotes around the value, such as:</p>
<pre tabindex="0"><code>&#39;(@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] StringEqualsIgnoreCase \&#39;nameOfContainer\&#39;)&#39;
</code></pre><h3 id="identifying-the-role-definition-id">Identifying the Role Definition Id</h3>
<p>The role definition id is what is used to identify the role that is to be applied to your security principal. Whether you create a custom role definition or use a standard built-in role definition, each one will have an id, and finding them is exactly the same.</p>
<p>Methods to find your Definition Id:</p>
<ol>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions-list#azure-portal">Azure Portal</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions-list#azure-powershell">Azure PowerShell</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions-list#azure-cli">Azure CLI</a></li>
<li><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions-list#rest-api">REST API</a></li>
</ol>
<p>Whichever method you choose, retrieve the Id of the role. The role definition id (<em>guid</em>) by itself cannot be utilised to reference the role definition in your template. To reference the Id correctly, you will need to reference the role definition as a resource. Such as:</p>
<pre tabindex="0"><code>roleDefinitionId: &#39;/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/{Guid role definition Id}&#39;
</code></pre><p>In my case, I would like to reference the &lsquo;<em>Storage Blob Data Reader</em>&rsquo; built-in role definition.</p>
<p>Using Azure PowerShell:</p>
<ol>
<li>Using <em><code>Connect-AzAccount</code></em> to Login</li>
<li>Then using this command to get the Role Definition <em><code>Get-AzRoleDefinition 'Storage Blob Data Reader'</code></em></li>
<li>From the output, I have identified the Id which is <code>2a2b9908-6ea1-4ae2-8e65-a410df84e7d1</code></li>
</ol>
<p>Therefore the Bicep template property will appear as follows:</p>
<pre tabindex="0"><code>roleDefinitionId: &#39;/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/2a2b9908-6ea1-4ae2-8e65-a410df84e7d1&#39;
</code></pre><h3 id="referencing-a-service-principal-id">Referencing a Service Principal Id</h3>
<p>If you are like me, and you followed standard practice for creating a Service Principal user, you followed these steps:</p>
<ol>
<li>Create an App Registration for your Service Principal.</li>
<li>Create a Secret on the App Registration.</li>
<li>Make note of the secret, and the Client Id.</li>
</ol>
<p>In previous API versions of the role assignment template, you were able to reference the <code>Client Id</code> as the Principal Id. However, in the <code>2022-04-01</code> template API version, this does not work.</p>
<p>When you create an App Registration for your service principal, you also get a linked Enterprise Application.</p>
<p>From what appears to be an act of decoupling, role assignments now use the <code>ObjectId</code> of the Enterprise Application of which then references your App Registration. You can obtain the Enterprise Application <code>ObjectId</code> using Azure PowerShell:</p>
<ol>
<li>Using <em><code>Connect-AzAccount</code></em> to Login</li>
<li>Then using this command to get the Enterprise Application details <em><code>Get-AzADServicePrincipal -DisplayName '{Name Of App Reg}' | fl</code></em></li>
<li>From the output, identify the Id - this is the <code>ObjectId</code></li>
</ol>
<p>The method of authentication, if using the App Registration Client Id and Secret will certainly stay the same.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Microsoft Authorization roleAssignments | <a href="https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?pivots=deployment-language-bicep">https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?pivots=deployment-language-bicep</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>More on what is Azure role-based access | <a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/overview">https://docs.microsoft.com/en-us/azure/role-based-access-control/overview</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item></channel></rss>