<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>langthaler.blog</title>
    <link>https://langthaler.blog/</link>
    <description>Recent content on langthaler.blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>© 2026 Jannis Langthaler</copyright>
    <lastBuildDate>Tue, 17 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://langthaler.blog/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Granular RBAC in Log Analytics</title>
      <link>https://langthaler.blog/posts/log-analytics-granular-rbac/</link>
      <pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://langthaler.blog/posts/log-analytics-granular-rbac/</guid>
      <description>&lt;p&gt;You learn something new everyday: Log Analytics supports per-table RBAC. I wasn&amp;rsquo;t aware of that but it was the perfect tool to fulfill a customer request.&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Introduction&#xA;    &lt;div id=&#34;introduction&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#introduction&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Recently I received a customer request that seemed a bit tricky at first: the application team needed specific Entra ID sign-in information that is already logged in Sentinel - but should not be able to access any other data from the SIEM. They wanted to retrieve that data via API to ingest it into another system for reporting purposes.&lt;br&gt;&#xA;With conventional resource-level RBAC you are able to grant things like read-only permissions to the whole Log Analytics Workspace. But then the assignee can read &lt;strong&gt;all&lt;/strong&gt; tables. That might not be an issue in some cases, but if Sentinel is enabled, the LAW will certainly contain data that is no one&amp;rsquo;s business but the security team&amp;rsquo;s.&lt;/p&gt;&#xA;&lt;p&gt;If we try to look for different approaches, one alternative presents itself:&#xA;Create a new LAW, save only the Entra ID sign-in logs in it using Diagnostic Settings and give the application team read-only permissions.&lt;br&gt;&#xA;Now that will work perfectly fine from a technical perspective, but the data is in Sentinel already. This means it&amp;rsquo;s already paid for. Using an additional LAW means additional costs.&#xA;Such costs do of course wildly depend on size and usage. But in our case the &lt;code&gt;SigninLogs&lt;/code&gt; table alone would have been thousands of dollars every month.&lt;br&gt;&#xA;Furthermore, this solution is - from a technical perspective - just unnecessary resource and configuration bloat.&lt;/p&gt;&#xA;&lt;p&gt;So, Sentinel it is. But how do we guarantee that only the required data is accessible? Enter per-table RBAC.&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;The Idea&#xA;    &lt;div id=&#34;the-idea&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#the-idea&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;In my research (I always find it a little amusing to call planless web searching research, but I guess that&amp;rsquo;s what it is nowadays) I found out that Log Analytics has table-level RBAC. This means that you can grant permissions on specific tables only.&lt;br&gt;&#xA;The feature actually goes deeper, apparently there is row-level RBAC as well, to restrict not only access to certain tables, but also to a set of rows. You could use this to for example anonymize logs by removing access to rows that contain PII (Personally Identifiable Information).&lt;br&gt;&#xA;For my use case, this wasn&amp;rsquo;t needed, but since it&amp;rsquo;s all in the same UI I will show it as well.&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;The Setup&#xA;    &lt;div id=&#34;the-setup&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#the-setup&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;App Registration&#xA;    &lt;div id=&#34;app-registration&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#app-registration&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Since we are sending our queries via API, we are using an App Registration.&lt;br&gt;&#xA;This is just an App Registration with a secret - using a certificate is recommended as always.&lt;br&gt;&#xA;There is no need to configure anything else here, simply create an App Registration for now.&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Role Assignment&#xA;    &lt;div id=&#34;role-assignment&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#role-assignment&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Here comes the interesting part:&lt;br&gt;&#xA;Navigate to your Log Analytics Workspace &amp;ndash;&amp;gt; &lt;em&gt;Access Control (IAM)&lt;/em&gt; &amp;ndash;&amp;gt; &lt;em&gt;Add&lt;/em&gt; &amp;ndash;&amp;gt; &lt;em&gt;Add role assignment&lt;/em&gt;&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;366&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image_hu_62932e7b1c1c4741.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image_hu_62932e7b1c1c4741.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Search for &lt;em&gt;Log Analytics Data Reader&lt;/em&gt;, select the role and continue with &lt;em&gt;Next&lt;/em&gt;.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;610&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-1_hu_16168b70976463a9.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-1_hu_16168b70976463a9.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-1.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-1.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Make sure &lt;em&gt;User, group, or service principal&lt;/em&gt; is checked.&lt;br&gt;&#xA;Select &lt;em&gt;Select members&lt;/em&gt;, search for your App Registration, select it so it shows up under &lt;em&gt;Selected members&lt;/em&gt;, choose &lt;em&gt;Select&lt;/em&gt; and confirm with Next.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;610&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-2_hu_8161bd196e718ae1.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-2_hu_8161bd196e718ae1.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-2.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-2.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Next, select &lt;em&gt;Add condition&lt;/em&gt; to create a granular filter.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;618&#34;&#xA;    height=&#34;406&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-3.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-3.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-3.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-3.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;First off, select &lt;em&gt;Add Action&lt;/em&gt; under &lt;em&gt;1. Add action&lt;/em&gt;. In the flyout menu, select &lt;em&gt;Read workspace data&lt;/em&gt; and confirm with &lt;em&gt;Select&lt;/em&gt;. This should be the only available option.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;610&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-4_hu_cf1d83f82cbbcd6.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-4_hu_cf1d83f82cbbcd6.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-4.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-4.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Afterwards, continue to &lt;em&gt;2. Build expression&lt;/em&gt;. Here, again select &lt;em&gt;Add expression&lt;/em&gt;.&#xA;Under &lt;em&gt;Attribute source&lt;/em&gt;, select &lt;em&gt;Resource&lt;/em&gt; from the dropdown.&#xA;Under &lt;em&gt;Attribute&lt;/em&gt;, select &lt;em&gt;Table Name&lt;/em&gt;.&#xA;Under &lt;em&gt;Operator&lt;/em&gt;, select &lt;em&gt;StringEquals&lt;/em&gt; and make sure &lt;em&gt;Value&lt;/em&gt; is checked.&#xA;Under &lt;em&gt;Value&lt;/em&gt;, enter the table name. In this case, enter &lt;code&gt;SigninLogs&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;admonition relative overflow-hidden rounded-lg border-l-4 my-3 px-4 py-3 shadow-sm&#34; data-type=&#34;warning&#34;&gt;&#xA;      &lt;div class=&#34;flex items-center gap-2 font-semibold text-inherit&#34;&gt;&#xA;        &lt;div class=&#34;flex shrink-0 h-5 w-5 items-center justify-center text-lg&#34;&gt;&lt;span class=&#34;relative block icon&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z&#34;/&gt;&lt;/svg&gt;&#xA;&lt;/span&gt;&lt;/div&gt;&#xA;        &lt;div class=&#34;grow&#34;&gt;&#xA;          Table name&#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&lt;div class=&#34;admonition-content mt-3 text-base leading-relaxed text-inherit&#34;&gt;&lt;p&gt;Make sure to enter the table name correctly!&lt;br&gt;&#xA;This includes case-sensitivity.&lt;br&gt;&#xA;Best copy the names from the Log Explorer, MS Learn or from this blog post.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;336&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-5_hu_7f5047738569df6d.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-5_hu_7f5047738569df6d.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-5.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-5.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;p&gt;You have some options here in addition so adding single tables like I did.&lt;br&gt;&#xA;Find all the options in the &lt;em&gt;Operator&lt;/em&gt; dropdown:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;854&#34;&#xA;    height=&#34;418&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-6_hu_a1be29314ba87c16.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-6_hu_a1be29314ba87c16.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-6.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-6.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Here you can&amp;rsquo;t just include tables but also exclude them using &lt;code&gt;StringNotEquals&lt;/code&gt;. With this you would allow read access to all tables in the LAW &lt;strong&gt;except&lt;/strong&gt; the one listed.&lt;/p&gt;&#xA;&lt;p&gt;Then you have &lt;code&gt;ForAllOfAnyValues:StringEquals&lt;/code&gt; and &lt;code&gt;ForAllOfAnyValues:StringNotEquals&lt;/code&gt;.&lt;br&gt;&#xA;These two settings are the multi-value pendants. Use this if you want to include or exclude multiple tables in your role assignment:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;2660&#34;&#xA;    height=&#34;652&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-7_hu_16978fedcb419aa7.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-7_hu_16978fedcb419aa7.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-7_hu_1d77afaaff50fdef.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-7.png&#34;&gt;&lt;/figure&gt;&#xA;&#xA;(or add two separate &lt;code&gt;StringEquals&lt;/code&gt; statements like I did, same effect. Pick what you prefer.)&lt;/p&gt;&#xA;&lt;p&gt;Next, review the completed form and confirm with &lt;em&gt;Save&lt;/em&gt;.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;948&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-8_hu_46335189ed15bb8e.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-8_hu_46335189ed15bb8e.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-8.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-8.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Review the expression displayed as code and continue with &lt;em&gt;Review + assign&lt;/em&gt;.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;508&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-9_hu_4e8d6fcbd70c16a6.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-9_hu_4e8d6fcbd70c16a6.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-9.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-9.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Last, confirm with &lt;em&gt;Review + assign&lt;/em&gt; again to save the role assignment.&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;986&#34;&#xA;    height=&#34;582&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-10_hu_25d6164967884f82.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-10_hu_25d6164967884f82.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-10.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-10.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;div class=&#34;admonition relative overflow-hidden rounded-lg border-l-4 my-3 px-4 py-3 shadow-sm&#34; data-type=&#34;success&#34;&gt;&#xA;      &lt;div class=&#34;flex items-center gap-2 font-semibold text-inherit&#34;&gt;&#xA;        &lt;div class=&#34;flex shrink-0 h-5 w-5 items-center justify-center text-lg&#34;&gt;&lt;span class=&#34;relative block icon&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M438.6 105.4C451.1 117.9 451.1 138.1 438.6 150.6L182.6 406.6C170.1 419.1 149.9 419.1 137.4 406.6L9.372 278.6C-3.124 266.1-3.124 245.9 9.372 233.4C21.87 220.9 42.13 220.9 54.63 233.4L159.1 338.7L393.4 105.4C405.9 92.88 426.1 92.88 438.6 105.4H438.6z&#34;/&gt;&lt;/svg&gt;&#xA;&lt;/span&gt;&lt;/div&gt;&#xA;        &lt;div class=&#34;grow&#34;&gt;&#xA;          And you&amp;rsquo;re done&#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&lt;div class=&#34;admonition-content mt-3 text-base leading-relaxed text-inherit&#34;&gt;&lt;p&gt;At this point, the setup is done.&lt;/p&gt;&#xA;&lt;p&gt;Microsoft notes that assignments can take up to 15 minutes to apply and trust me they do.&lt;br&gt;&#xA;Grab a coffee and drink it before starting the last step: testing&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Testing and validation&#xA;    &lt;div id=&#34;testing-and-validation&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#testing-and-validation&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s test our setup to validate my ramblings.&lt;/p&gt;&#xA;&lt;p&gt;I already got myself an MS Graph Access Token. If you need some guidance on how to do that, refer to &lt;a href=&#34;https://learn.microsoft.com/en-us/graph/auth-v2-service?tabs=http#step-3-request-an-access-token&#34;  target=&#34;_blank&#34; rel=&#34;noreferrer&#34;&gt;this MS Learn article&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;admonition relative overflow-hidden rounded-lg border-l-4 my-3 px-4 py-3 shadow-sm&#34; data-type=&#34;info&#34;&gt;&#xA;      &lt;div class=&#34;flex items-center gap-2 font-semibold text-inherit&#34;&gt;&#xA;        &lt;div class=&#34;flex shrink-0 h-5 w-5 items-center justify-center text-lg&#34;&gt;&lt;span class=&#34;relative block icon&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z&#34;/&gt;&lt;/svg&gt;&#xA;&lt;/span&gt;&lt;/div&gt;&#xA;        &lt;div class=&#34;grow&#34;&gt;&#xA;          Scope URL&#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&lt;div class=&#34;admonition-content mt-3 text-base leading-relaxed text-inherit&#34;&gt;&lt;p&gt;Make sure that you use the following URL as &lt;code&gt;scope&lt;/code&gt; in your POST request to get your access token: &lt;code&gt;https://api.loganalytics.io/.default&lt;/code&gt;&lt;br&gt;&#xA;Since Log Analytics has its own API, you need to use this URL as scope and not the general Graph API scope URL.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;So let&amp;rsquo;s &lt;code&gt;GET&lt;/code&gt; some data (&lt;em&gt;wheezes&lt;/em&gt;).&#xA;The API URL is&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://api.loganalytics.azure.com/v1/workspaces/[WORKSPACE ID]/query?query=[KQL QUERY]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Also &lt;a href=&#34;https://learn.microsoft.com/en-us/rest/api/logsquery/query/get?view=rest-logsquery-v1&amp;amp;tabs=HTTP&#34;  target=&#34;_blank&#34; rel=&#34;noreferrer&#34;&gt;here&lt;/a&gt; you can find the API reference if you want to see some details.&lt;/p&gt;&#xA;&lt;p&gt;Replace the variables with value from your tenant. For the KQL query I will simply query &lt;code&gt;SigninLogs&lt;/code&gt; since I added that table to my role assignment earlier.&lt;br&gt;&#xA;Also Add the following 2 Headers:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;Content-Type&lt;/code&gt; : &lt;code&gt;application/json&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Authorization&lt;/code&gt; : &lt;code&gt;Bearer [ACCESS TOKEN]&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;With that all ready, let&amp;rsquo;s fire our query!&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;2026&#34;&#xA;    height=&#34;1400&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-11_hu_aafc968eca45ed5.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-11_hu_aafc968eca45ed5.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-11_hu_f65323c8c45b423e.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-11.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Now you may think the response looks weird at first. The API always returns the table schema first, which is quite handy if you deal with multiple tables. This way you can use your automation logic to deal with different column names dynamically for example.&lt;/p&gt;&#xA;&lt;p&gt;Scroll down a little while and there&amp;rsquo;s your data:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;2264&#34;&#xA;    height=&#34;1706&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-12_hu_36cf753142517d3d.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-12_hu_36cf753142517d3d.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-12_hu_53241202970acb1a.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-12.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Additional Options&#xA;    &lt;div id=&#34;additional-options&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#additional-options&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;As promised in the intro, there is an additional option I didn&amp;rsquo;t use but want to show you anyway:&lt;br&gt;&#xA;The option to further restrict access to only specific columns if they contain a certain string (or strings)!&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s take a look:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;1342&#34;&#xA;    height=&#34;615&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-13_hu_238571bf1b8903e1.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-13_hu_238571bf1b8903e1.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-13_hu_c8483d06134e6b4c.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-13.png&#34;&gt;&lt;/figure&gt;&#xA;&#xA;Again, first add an expression in the role assignment wizard.&lt;br&gt;&#xA;First off after adding a new expression make sure to change the radio button from &lt;code&gt;Or&lt;/code&gt; to &lt;code&gt;And&lt;/code&gt; (2) to save you some time with troubleshooting (ask me how I know).&lt;br&gt;&#xA;In &lt;code&gt;Attribute source&lt;/code&gt; select &lt;code&gt;Resource&lt;/code&gt;.&lt;br&gt;&#xA;Then, in &lt;code&gt;Attribute&lt;/code&gt;, select &lt;code&gt; Column value (Key is the column name)&lt;/code&gt;.&lt;br&gt;&#xA;In &lt;code&gt;Key&lt;/code&gt;, enter the column name you would like to filter on.&lt;/p&gt;&#xA;&lt;div class=&#34;admonition relative overflow-hidden rounded-lg border-l-4 my-3 px-4 py-3 shadow-sm&#34; data-type=&#34;warning&#34;&gt;&#xA;      &lt;div class=&#34;flex items-center gap-2 font-semibold text-inherit&#34;&gt;&#xA;        &lt;div class=&#34;flex shrink-0 h-5 w-5 items-center justify-center text-lg&#34;&gt;&lt;span class=&#34;relative block icon&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M506.3 417l-213.3-364c-16.33-28-57.54-28-73.98 0l-213.2 364C-10.59 444.9 9.849 480 42.74 480h426.6C502.1 480 522.6 445 506.3 417zM232 168c0-13.25 10.75-24 24-24S280 154.8 280 168v128c0 13.25-10.75 24-23.1 24S232 309.3 232 296V168zM256 416c-17.36 0-31.44-14.08-31.44-31.44c0-17.36 14.07-31.44 31.44-31.44s31.44 14.08 31.44 31.44C287.4 401.9 273.4 416 256 416z&#34;/&gt;&lt;/svg&gt;&#xA;&lt;/span&gt;&lt;/div&gt;&#xA;        &lt;div class=&#34;grow&#34;&gt;&#xA;          Spelling and case-sensitivity&#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&lt;div class=&#34;admonition-content mt-3 text-base leading-relaxed text-inherit&#34;&gt;&lt;p&gt;Again, make sure to spell the table correctly, including case-sensitivity.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Next, choose an &lt;code&gt;Operator&lt;/code&gt;. There are more options to choose from than in the previous step. I chose &lt;code&gt;StringStartsWith&lt;/code&gt; for my setup.&lt;br&gt;&#xA;Last, under &lt;code&gt;Value&lt;/code&gt;, enter the value you want to filter on.&lt;/p&gt;&#xA;&lt;p&gt;So in my case, I&amp;rsquo;m applying a filter on the column &lt;code&gt;Identity&lt;/code&gt; for all entries that &lt;code&gt;start with&lt;/code&gt; &lt;code&gt;adm.jannis&lt;/code&gt;. And as you can see in the upper area of the screenshot I&amp;rsquo;m already limiting access to only the table &lt;code&gt;SigninLogs&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;After saving, it will take some time for the role assignment to take hold, about 15 minutes in my limited testing. So grab another coffee before testing.&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Testing and validation&#xA;    &lt;div id=&#34;testing-and-validation-1&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#testing-and-validation-1&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Querying the table with my user shows sign-ins from 4 users:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;526&#34;&#xA;    height=&#34;467&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-14.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-14.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-14.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-14.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;Running the same query with the App Registration that has the limiting role assignment shows only sign-ins from my user since it&amp;rsquo;s the only one where &lt;code&gt;Identity&lt;/code&gt; starts with &lt;code&gt;adm.jannis&lt;/code&gt;:&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;auto&#34;&#xA;    alt=&#34;&#34;&#xA;    width=&#34;1448&#34;&#xA;    height=&#34;672&#34;&#xA;    src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-15_hu_d0c2905d2d726a68.png&#34;&#xA;    srcset=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-15_hu_d0c2905d2d726a68.png 800w, https://langthaler.blog/posts/log-analytics-granular-rbac/image-15_hu_330bdd4f46e38336.png 1280w&#34;&#xA;    sizes=&#34;(min-width: 768px) 50vw, 65vw&#34;&#xA;    data-zoom-src=&#34;https://langthaler.blog/posts/log-analytics-granular-rbac/image-15.png&#34;&gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Outro&#xA;    &lt;div id=&#34;outro&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#outro&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;And with the tests successful we&amp;rsquo;re done!&lt;br&gt;&#xA;If you have any use cases to retrieve some data from Log Analytics, use the methods I showed you to grant least-privilege access to tables or even specific data within tables.&lt;br&gt;&#xA;The only missing feature is the ability to limit access to certain columns only, especially when we&amp;rsquo;re talking about tables containing PII. That would be nice.&lt;/p&gt;&#xA;</description>
      
    </item>
    
  </channel>
</rss>
