Home / Azure

Azure Virtual Desktop | Security Give Aways – Part II

Azure Virtual Desktop | Security Give Aways – Part II


In Part I I argued that a sessionhost is a third kind of machine – not a server, not a laptop – and I walked the six-step chain an attacker follows through an AVD estate. Credential, token, host, elevation, data, lateral movement.

This post breaks the first four steps.

Identity and the operating system are where the leverage is. Get these two layers right and the network controls in Part III become a second line of defence rather than the only one. Get them wrong and nothing downstream saves you, because the attacker is already a legitimate, authenticated, locally privileged user of your environment.

Every control below is written the same way: what it stops, what it costs you, and how you verify it is actually on. That third one is the part everybody skips and it is the only part that survives contact with an audit.

Layer one – Identity

RBAC is the load-bearing wall

Start here, because if this is wrong nothing else matters.

To sign in to an Entra-joined sessionhost, the user needs a role assignment on the virtual machines. There are two candidates and the difference between them is the difference between a secured environment and an open one.

Virtual Machine User Login grants an interactive logon as a standard user. That is what an AVD user needs. Virtual Machine Administrator Login grants an interactive logon as a local administrator. That is what an AVD user almost never needs, and what a surprising number of environments have assigned to their entire user group.

Why does it matter so much? Because local administrator on a multi-session host cuts step four of the chain out entirely. An attacker who lands in a session with local admin does not need a privilege escalation exploit. They can disable the endpoint agent, read other users’ processes, dump credentials from memory, install persistence, and modify the very controls you are about to deploy. Every operating system hardening measure in the second half of this post assumes the user is not an administrator. Take that assumption away and you are configuring suggestions.

The cost of getting this right is real, and it is where the pressure comes from. Somebody’s application needs elevation to run. Somebody’s developer wants to install a tool. That pressure is exactly why the administrator role gets granted “temporarily” and then never removed. The answer is not to grant it – it is application packaging, MSIX app attach, or a separate, small, tightly scoped host pool for the handful of people who genuinely need it, with its own policies and its own monitoring.

Assign at the resource group that holds the sessionhost virtual machines rather than at the subscription. Subscription-level assignment means every future virtual machine in that subscription, AVD or not, inherits the logon right. That is a much larger blast radius than anybody intends.

How to verify

List the role assignments on the sessionhost resource group and confirm that no group containing standard users holds Virtual Machine Administrator Login. Do this as a recurring check, not a one-off, because this is a setting that drifts. It gets granted during a troubleshooting session at 4pm on a Friday and it is still there two years later.

Conditional Access, done specifically

“Enable MFA” is not a design. Azure Virtual Desktop authenticates in more than one place, and a Conditional Access policy scoped to only one of them leaves a usable gap.

There are two distinct moments to think about. First, the user retrieves their feed and their published resources. Second, the user actually connects to a sessionhost. These are different applications and a policy targeting one does not automatically cover the other. An environment where MFA is enforced on the feed but not on the connection is not an environment with MFA.

Two service principals sit at the centre of the RDP authentication path, and their application IDs are identical in every tenant:

Application nameApplication ID
Azure Virtual Desktop9cdead84-a844-4324-93f2-b2e6bb768d07
Windows Cloud Login270efc09-cd0d-444b-a71f-39af4910ec45

Windows Cloud Login is the one that gets missed. It has progressively taken over the RDP authentication path from Microsoft Remote Desktop, and a policy written a few years ago that only names Microsoft Remote Desktop will quietly stop covering what you thought it covered. Target both. I have been writing about this before https://www.gettothe.cloud/azure-secure-azure-virtual-desktop-with-mfa-update/

Sign-in frequency is the setting that will make you unpopular if you get it wrong. On a normal desktop, a short sign-in frequency is a mild annoyance. In AVD, where a user may reconnect to a session several times a day across devices, an aggressive value produces a stream of prompts and a stream of tickets. Pick a value you can defend and then make single sign-on work properly, which is the next section.

Device filters are where the real strength is, and they are underused. If your users connect from managed, compliant devices, requiring device compliance on the AVD applications is a much stronger control than another MFA prompt, because it defeats token replay from an attacker’s machine. Where you cannot require compliance – contractors, personal devices – that is precisely the population that should be getting the stricter session controls in Part III.

Break-glass, and I mean it

A Conditional Access misconfiguration can lock every user out of the virtual desktop environment they use to do their job, which in a full-VDI organisation means it locks everybody out of everything. Maintain excluded emergency access accounts, protect them with strong phishing-resistant authentication rather than exclusion from all controls, monitor their use, and write down the recovery procedure somewhere that is not itself inside AVD.

How to verify

Use the Conditional Access what-if tool against a real user account for both applications, and read the sign-in logs filtered by those two application IDs. The sign-in log is the truth. The policy list is the intention.

Single sign-on is a security control

This one gets filed under user experience and that is a mistake.

On Entra-joined sessionhosts without single sign-on configured, users get a credential prompt and a consent prompt on connection. It is irritating, the consent is only remembered for a limited period, and every time you redeploy hosts from an updated golden image the prompts come back – which is a direct disincentive to rebuilding your images regularly, and rebuilding images regularly is one of the strongest controls in this entire series.

That is the first security argument:

SSO removes the friction that makes people stop doing the safe thing.

The second is better. With Entra ID authentication for RDP enabled, the connection to the sessionhost becomes an Entra-authenticated event. That means Conditional Access can evaluate it, the sign-in logs record it, and risk-based policies apply to it. Without it, the connection authenticates on a legacy path that your policy engine cannot see and your detection cannot reason about. You are not just removing a prompt – you are moving the connection under the control plane that enforces everything else.

Enabling it is a switch on those two service principals, and then a scoping of which device groups the configuration applies to. Use a dynamic device group for your sessionhosts rather than a static one, so that newly deployed hosts are covered automatically – a static group plus an autoscaling host pool is a gap that opens itself. Note the caveats honestly: dynamic groups usually populate within five to ten minutes but large tenants can take considerably longer, and dynamic membership requires Entra ID P1.

For the exact PowerShell, I wrote it out step by step in the SSO post on this site. It uses the Microsoft Graph PowerShell module, it checks the current state before it changes anything, and it is safe to run repeatedly.

How to verify

Connect from a clean profile and confirm no consent prompt appears. Then check the sign-in logs for an interactive sign-in against the sessionhost – if the connection is not producing a log entry, single sign-on is not doing what you think it is.

Layer two – The sessionhost

Trusted Launch, and why you decide it now

Trusted Launch gives the virtual machine Secure Boot, a virtual TPM and boot integrity monitoring. In plain terms it means the machine will not boot a tampered bootloader or an unsigned kernel-mode rootkit, and it can attest to that state.

What it stops is persistence at the very bottom of the stack – the class of compromise that survives everything else you do, including a Defender scan, because it loads before Defender does. It is also a prerequisite for a number of adjacent capabilities you are likely to want later.

Here is the cost, and it is the whole reason this is a takeaway rather than a footnote: Trusted Launch is decided when the virtual machine is created. It is a security type on the VM, and it requires the image generation to match. You cannot flip it on across an existing host pool from a policy blade. Retrofitting means rebuilding every sessionhost from a compatible image, and “rebuild every sessionhost” is a project, not a change request.

So decide it at the image pipeline, before the estate exists. If you are building a new host pool this month, this is the cheapest security decision available to you and it becomes one of the most expensive ones if you defer it.

How to verify

Check the security profile on the virtual machines themselves – security type, Secure Boot enabled, vTPM enabled – and enforce it going forward with an Azure Policy assignment so a manually deployed host cannot quietly join the pool without it.

No standing local administrators

I am going to be blunt about this, because it is where most environments fail in practice even after they fix the RBAC assignment.

No user has standing local administrator rights on a sessionhost. Not the power users, not the developers, not the person who owns the line-of-business application. Standing means permanent and always-on, and it is the thing to eliminate.

The objection is always the same: an application needs it. Usually that application needs write access to a folder, or a registry key, or it needs to install a driver once. Those are packaging problems and they have packaging answers – MSIX app attach, application repackaging, or a per-user install that does not touch the machine. Where the application genuinely cannot be made to work, isolate it. A small dedicated host pool with a known population, its own network path and its own alerting is a far better outcome than granting elevation across the estate.

The built-in local administrator account still exists on every host and it still has a password. Windows LAPS manages that password, rotates it, stores it in the directory and controls who can retrieve it. Without it, every host built from the same image shares the same local administrator credential, which converts one compromised host into all of them. Enable it, and audit who has the permission to read the passwords.

How to verify

Query the local administrators group across the fleet and confirm it contains only the accounts you intend. This is a good candidate for a scheduled query rather than a manual check, precisely because it is a group that grows quietly.

Defender for Endpoint and attack surface reduction

Onboarding sessionhosts to Defender for Endpoint is not optional in a serious environment, and multi-session hosts have a couple of characteristics worth knowing about before you start.

The onboarding configuration belongs in the golden image, not applied by hand afterwards. A host built from an image without it is a host that is silently unmonitored for its entire lifetime, and in an autoscaling pool nobody will notice. Where the image contains onboarding information, be aware of the machine identity problem: images captured after onboarding can produce hosts that report as the same device. Follow the documented image preparation steps so that each deployed host registers as its own device, then verify the device count in the portal matches the number of hosts you actually have.

Attack surface reduction rules are where you get real value, and also where you get your support tickets. Some are close to free on a virtual desktop. Blocking credential stealing from the Windows local security authority subsystem directly attacks step four and five of the chain, and it rarely breaks anything legitimate. Blocking Office applications from creating child processes and blocking executable content from email and webmail cut off two of the most common initial execution routes, and they occasionally break a genuine business macro.

Deploy in audit mode first. Run it for a defined period – two to four weeks across a full business cycle, so that month-end processing is included – review what would have been blocked, then enforce rule by rule. Enforcing everything on day one on a shared desktop where hundreds of people work is how attack surface reduction gets rolled back permanently after a bad Monday.

How to verify

Confirm device onboarding status and health in the Defender portal, check that the device count matches the host count, and query the ASR events to confirm rules are in the mode you believe they are in rather than the mode they were left in during testing.

Baselines, and the settings that will bite you

A security baseline is a large set of operating system settings applied as a package. There is an AVD-specific baseline, there are general Windows baselines, and there is the option of building your own.

Use the AVD-specific baseline as your starting point. It has been adjusted for the reality of a shared, non-persistent, remotely accessed desktop, which the general server and workstation baselines have not. Then expect to relax a small number of settings, and document why each one was relaxed, because an undocumented exception is indistinguishable from a mistake six months later.

The classic collision is with FSLogix. Hardening settings that touch user rights assignments, network access restrictions, or the handling of removable and network storage can prevent profile containers from mounting cleanly. The symptom is not a security alert – it is users getting temporary profiles, losing their settings, and calling the service desk. When that happens the pressure to remove the whole baseline is enormous, which is why you should apply it to a pilot host pool first with a representative group of real users, not to production on a Friday.

The second collision is with the applications themselves. Application control and script restrictions are excellent controls and they will find every unsigned utility your business quietly depends on. That is the point, but it needs a discovery phase.

How to verify

Run a configuration analysis against the baseline rather than trusting that the profile deployed successfully, and check for policy conflicts where more than one source is setting the same thing. Two management systems fighting over the same setting produces a host that is compliant in the portal and unhardened in reality.

The image pipeline is a security control

This is the one that ties the whole layer together, and if you already run an image pipeline you are most of the way there.

If sessionhosts are built from a versioned image and rebuilt on a schedule, three things become true. Patch level stops being an operational hope and becomes a property of the build. Configuration drift has a hard expiry date. And attacker persistence on the host – scheduled tasks, services, registry run keys, dropped binaries – becomes almost worthless, because the host it lives on will not exist next month.

That last point is worth dwelling on. In a persistent estate, an attacker who establishes a foothold keeps it until you find it. In an ephemeral estate, they keep it until the next rebuild. You have changed the economics of the attack without deploying a single security product.

Build the security configuration into the image rather than applying it after deployment: the endpoint agent onboarding, the baseline, the Trusted Launch-compatible generation, the removal of anything that does not belong. Store the image in a compute gallery, version it, and treat a promotion to production as a change. Then automate the rebuild cadence so that “we will redeploy the hosts soon” stops being a sentence anybody has to say.

Two practical notes. First, make sure single sign-on is configured before you adopt a frequent rebuild cadence, or every rebuild generates a wave of consent prompts and users will start asking you to stop rebuilding. Second, an image is a supply chain – whatever you install into it, you inherit. Pin your sources, and know what is in there.

How to verify

Compare the image version currently referenced by the host pool against the latest version in the gallery, and check the build date of your running sessionhosts. If the answer is measured in months, the pipeline exists on paper.

Where this leaves you

Working through this post cuts four of the six steps in the chain. The credential and the token are constrained by Conditional Access, device filters and Entra-authenticated RDP. The host is hardened at boot by Trusted Launch and at runtime by the baseline and the endpoint agent. Elevation is closed off by removing standing local administrators and managing the built-in account.

Two steps remain: the data in the profile, and the movement out of the sessionhost into everything else. Both of those are network and session problems, and they are Part III.

To see all this live in action, i have created some bicep files and scripts to setup a demo environment. This way you can check for yourself what it is and what is does. Check https://github.com/GetToThe-Cloud/avd-security-demo

Share and Enjoy !

Shares

Designer (23)

Stay close to the action—follow GetToThe.Cloud across social!
Deep dives and hands‑on how‑tos on Azure Local, hybrid cloud, automation, PowerShell/Bicep, AVD + FSLogix, image pipelines, monitoring, networking, and resilient design when the internet/Azure is down.

🔗 Our channels
▶️ YouTube: https://www.youtube.com/channel/UCa33PgGdXt-Dr4w3Ub9hrdQ
💼 LinkedIn Group: https://www.linkedin.com/groups/9181126/
✖️ X (Twitter): https://x.com/Gettothecloud
🎵 TikTok: https://www.tiktok.com/@gettothecloud
🐙 GitHub: https://github.com/GetToThe-Cloud/Website
💬 Slack: DM us for an invite
📲 WhatsApp: DM for the community link

We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners. View more
Cookies settings
Accept
Privacy & Cookie policy
Privacy & Cookies policy
Cookie name Active

Who we are

Our website address is: https://www.gettothe.cloud

Comments

When visitors leave comments on the site we collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection. An anonymized string created from your email address (also called a hash) may be provided to the Gravatar service to see if you are using it. The Gravatar service privacy policy is available here: https://automattic.com/privacy/. After approval of your comment, your profile picture is visible to the public in the context of your comment.

Media

If you upload images to the website, you should avoid uploading images with embedded location data (EXIF GPS) included. Visitors to the website can download and extract any location data from images on the website.

Cookies

If you leave a comment on our site you may opt-in to saving your name, email address and website in cookies. These are for your convenience so that you do not have to fill in your details again when you leave another comment. These cookies will last for one year. If you visit our login page, we will set a temporary cookie to determine if your browser accepts cookies. This cookie contains no personal data and is discarded when you close your browser. When you log in, we will also set up several cookies to save your login information and your screen display choices. Login cookies last for two days, and screen options cookies last for a year. If you select "Remember Me", your login will persist for two weeks. If you log out of your account, the login cookies will be removed. If you edit or publish an article, an additional cookie will be saved in your browser. This cookie includes no personal data and simply indicates the post ID of the article you just edited. It expires after 1 day.

Embedded content from other websites

Articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website. These websites may collect data about you, use cookies, embed additional third-party tracking, and monitor your interaction with that embedded content, including tracking your interaction with the embedded content if you have an account and are logged in to that website.

Who we share your data with

If you request a password reset, your IP address will be included in the reset email.

How long we retain your data

If you leave a comment, the comment and its metadata are retained indefinitely. This is so we can recognize and approve any follow-up comments automatically instead of holding them in a moderation queue. For users that register on our website (if any), we also store the personal information they provide in their user profile. All users can see, edit, or delete their personal information at any time (except they cannot change their username). Website administrators can also see and edit that information.

What rights you have over your data

If you have an account on this site, or have left comments, you can request to receive an exported file of the personal data we hold about you, including any data you have provided to us. You can also request that we erase any personal data we hold about you. This does not include any data we are obliged to keep for administrative, legal, or security purposes.

Where we send your data

Visitor comments may be checked through an automated spam detection service.
Save settings
Cookies settings