Securing Virtual Machine Infrastructure in Microsoft Azure

This is a summary blog post on a presentation that I hosted on the Microsoft Security User Group Norway a few weeks back (You can view the presentation here –> community/MSUGC-securing-virtual-machines-english.pptx at main · msandbu/community (

There are many security features within Microsoft Azure when it comes to securing virtual infrastructure.

1: Encrypting data and VM

When it comes to a running virtual machine, all machines are running from a set of compute and storage nodes, where the VHD file is located. The VHD file is stored on a set of physical disks which are by default encrypted using Bitlocker and this service is called SSE (Storage Service Encryption) this ensures that if someone smashes into the data center and rips out some disks, they will be unable to read the data.

However, the VHD file on top of the physical disks is not encrypted by default, this means that I’m able to download a VHD file from a VM down to my local computer and inspect the disks. This is where a second feature comes in which is called Azure Disk Encryption which encrypts the running VHD file using either Bitlocker (Windows) or DM-Crypt (Linux) in combination with Azure KeyVault.

The last part is that the actual VM with the runtime is not encrypted so everything inside of VM with memory can in theory be inspected by insiders. This is where confidential computing comes in that can encrypt all of data processing inside the actual running virtual machine, you can read more about it here –> Encrypting of Data within Microsoft Azure | Marius Sandbu (

2: Generation 1 vs Generation 2 VM’s

Then we have Generation 1 vs Generation 2 virtual machines. With Generation 2 machines we got introduced to UEFI-based boot. Generation 2 Virtual machines also provides us with VBS

This means that we can use features like Credential Guard for virtual machines and even Trusted Boot, which in Azure leverages the VM attestation service which will notify us if anything has tampered with the boot sequence of virtual machines in Azure. This of course is only available if we have Azure Defender for Cloud-enabled.

Remember that if we use Trusted Boot, there are some features like Site Recovery and Shared/Ultra disks that will not work.

3: Access Management

It is important to understand that within Microsoft Azure, access is given based upon two parts, which are either in the hierarchy structure (Management Group, Subscription, Resource Group, or Resource) and then ultimately the access to resource providers (and actions within that resource provider)

For instance, a user can be given access to a certain resource provider such as Microsoft. Compute and only the action read. Azure Access actions can be either read/write/action/delete or * (wildcard) So I can define access to only certain actions within a resource provider such as the action to restart a virtual machine within a certain resource group or subscription.

You should always strive to handle access on a least-access level, using tools like Azure AD PIM or Entitlement Management, or Cloudknox (which is coming) to provide access when needed.

For instance, when we have a virtual machine that is running in Azure it has by default an agent installed from Microsoft (you can read more about the agent here –> Azure VM Guest Agent | Marius Sandbu (

One of the features that Azure provides is something called Run commands which allows us to run Powershell scripts directly on the virtual machine, which can be extremely useful in certain scenarios. For someone to be able to run these scripts they would need to have access to this certain action

  • Microsoft.Compute/virtualMachines/runCommand/action

So, let’s say that someone from the help desk has this access in Azure and you say have a virtual domain controller running in Azure, well then, they can run this command to reset an AD account password directly from the Azure portal.

Set-ADAccountPassword -Identity user03 -NewPassword $NewPwd -Reset

There is unfortunately no way to disable this feature, so it is important to restrict access in Azure properly.

Another issue can be managed identities, while these are extremely useful since we can use this feature to give a machine an Azure AD account without the hassle of managing a service account and password it means that we also need to make sure of access that machine has.

Also it is not directly easy to see what kind of machines have a managed identity account. However, this resource graph query can be useful to see what kind of machines that have a managed account

 // SAMI = System-assigned Managed Identity
// UAMI = User-assigned Managed Identity
// Sjekker om VM eller VMSS har SAMI eller UAMI
| join kind=leftouter(
| where type=='microsoft.resources/subscriptions'
| project subscriptionName=name, subscriptionId
) on subscriptionId
| where type =~ "microsoft.compute/virtualmachines" or
type =~ "microsoft.compute/virtualMachineScaleSets"
| extend identityType = identity.type
| extend hasManagedIdentity = iff(identity == "", "No", "Yes"),
isSystemAssignedEnable = iff(identityType contains "SystemAssigned", "Yes", "No")
| project subscriptionId,

If you have control of the managed identities that’s great! just be sure to add logging of ManagedIdentitySigninLogs as part of the Azure Active Directory audit logs

4: Logging and monitoring

While I have written in great detail on how to set up Azure Monitor and Azure Sentinel in a previous blog posts, it is often something that is always overlooked. With the new Microsoft Monitoring agent, we are introduced to a new way how logs collection is handled using Data Collection Rules

And while the new agent has had some limitations it has now support for customer log files as well (In the preview you can sign up for here –> Microsoft Forms (

Now if you want to see the full picture in terms of network traffic, events, processes, and services on a virtual machine you will need to combine different services to get the overview.

Such as

* VM Insight (Dependency Agent
* Security Events (Using Microsoft Azure Sentinel)
* DeviceFileEvents (Defender for Servers or Defender for Endpoints)
* Configuration Change (Azure Automation)

Using these services and collecting the data into Log Analytics allows us to get a full overview of what is going on in a virtual machine.

One of the great things when collecting this data into a service like Azure Sentinel it means that you can easily enrich the data with external data sources to check if there is traffic matching against your virtual machines or other data sources against known “bad” IP addresses

This is an example of Kusto Query that maps IP addresses against three different Log Analytics tables and looks for a match.

let IP = (externaldata(ip:string)
| where ip matches regex "(^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)"
| distinct ip
(union isfuzzy=true
| where IpAddress in (IP)
| extend Ip = IpAddress, User = Account
| where SourceIp in (IP)
| extend Ip = SourceIp
| where LinksLive == 1
| where IPAddress in (IP)
| extend Ip = IPAddress, User = UserPrincipalName

This can of course be done for any data sources that are collected into Log Analytics, even if we have NSG Flow Logs which will collect Flow data related to all traffic going through an NSG regardless of if it is blocked or allowed.

NSG Flow logs can be collected into Log Analytics using a feature called Traffic Analysis which Microsoft will then do is collect and enrich the data set before pushing it into a Log Analytics workspace

NOTE: Private Endpoint traffic is not visible in NSG Flow logs and support of that will come later.

Well anyhow this was supposed to be a short summary of the presentation, there is more content in the PowerPoint, please reach out if there are any questions.









Leave a Reply

Scroll to Top