Graph Visualization of External Teams Collaborations in Azure Sentinel

This post has been republished via RSS; it originally appeared at: Azure Sentinel articles.



In the recently published Remote Work Trend Report, Microsoft provided some interesting insights into how the shift into full-time remote work and learning has impacted the way we collaborate and remain productive with internal and external stakeholders. On the flip side, cybersecurity teams now have a mammoth task of securing virtual meetings, ensuring the right policies and permissions are being implemented, and monitoring guest access to meetings and data.


Expanded View.png

The Rationale


By using graphs, we can visualize interactions between:

  • Internal users  (light blue nodes)

Making it easier to visually identify outliers and smaller clusters that diverge from typical enterprise behavior.

  • Large clusters imply that many enterprise users are interacting with the external domain 
  • Small clusters imply few or stray enterprise user interactions with the external domain.
  • Size of the edge (ie. thickness of the arrow) represents the frequency of interaction between an individual enterprise user and the external domain. So a thicker arrow would imply more frequent interactions between a specific user and the external domain.





Implementation Guide



  • [link] Setup Azure Sentinel
  • [link] Enable Office365 Audit Logging (Teams activity is a subset)

Leveraging the good work of other contributors (in the links above) we can dive straight into creating the graph visualization in Azure Sentinel workbooks.


Workbooks and Graph Visualization

Once in Azure Sentinel, navigate to workbooks, and add a query module. You will be prompted to enter a KQL query, and a visualization drop down list will allow you to toggle how the query results will be presented - in this case we will be selecting Graph.



Preparing the KQL Query

:warning: Note: Since Teams data is being retrieved through Logic Apps [link] if you did not define the table as TeamsData, just replace any mention of TeamsData in the following section to the table name you defined.


1. Teams data preparation

In the initial data datatable, the Members string which are user emails (internal and external) gets parsed to split the domain from the username. Internal organization domains then get filtered out (since we are only concerned about external domains in this scenario). A RequestId is then formed by stringing the external domain together with the requester (internal user).




let CallerOrg = (TeamsData | extend InternalOrg = tostring(split(UserId, "@")[1]) | distinct InternalOrg); let data = (TeamsData | extend UPN = tostring(parse_json(Members)[0].UPN) | extend Organization = tostring(split(UPN, "@")[1]) | where isnotempty(Organization) | summarize Calls = count() by ExtDomain = Organization, Request = UserId, Dependency = UPN | where ExtDomain !in (CallerOrg) | extend RequestId = strcat(ExtDomain, '::', Request));





2. Building a list of the links

The links datatable then groups the number of unique calls/interactions between the internal user and an external domain, and we append the type of interaction in the “Kind” column. 




let links = data | summarize Calls = sum(Calls) by ExtDomain, RequestId | project SourceId = ExtDomain, TargetId = RequestId, Calls, Kind = 'ExtDomain -> Request';





3. Building a list of nodes

The nodes datatable counts and groups the total number of calls/interactions being made to each external domain, and again we append the type of interaction in the “Kind” column. We also union and combine the number of calls/interactions being initiated by internal users and append the type “Request”.




let nodes = data | summarize Calls = sum(Calls) by ExtDomain | project Id = ExtDomain, Name = ExtDomain, Calls, Kind = 'ExtDomain' | union (data | summarize Calls = sum(Calls) by RequestId, Request | project Id = RequestId, Name = Request, Calls, Kind = 'Request');





4. Putting it all together - combining the nodes and links

The final step is combining the nodes and links datatables into a single datatable.




nodes | union (links) | extend HEXColour = iif(Kind == "Request", "cad8e6", "28496b")





5. Optional

In graphs you can specify the color you would like the nodes to appear in. Just append the desired HEX color in a separate column — in this example I made internal users appear light blue, and external domains appear dark blue. If you would like, you could also add additional layers of color coding to enrich the visualization. Eg. assigning different colors to different internal user groups (HR could be yellow, Finance could be red, etc.)


Graph Layout Settings

Clicking into Graph Settings, a small pop-out window will appear on the right. The layout settings are where you define what each node will represent. Do note this is highly dependent on how you have structured the KQL query above, in this example by using:

  • Node ID = Id

This will give you a view where the central node is the external domain and the surrounding nodes are the internal users.



Save the query and the workbook and start to explore the different clusters and interactions.




REMEMBER: these articles are REPUBLISHED. Your best bet to get a reply is to follow the link at the top of the post to the ORIGINAL post! BUT you're more than welcome to start discussions here:

This site uses Akismet to reduce spam. Learn how your comment data is processed.