Restricting Managed Disk Export

One of the big benefits of Managed Disks in Azure is that a VM’s VHD(s) are stored in a storage account which is managed by Azure and no longer has a public endpoint like page blobs did in the unmanaged disk model. One potential downside to this old approach was that anyone with the primary or secondary access key to the storage account where the VM’s VHDs were stored could simply connect to the storage account and download the VHD. Without encryption technologies like ADE or DMCrypt, this meant that person had a working copy of your VM’s disks and full access to the data on them.

With Managed Disks, VHDs no longer have a public blob endpoint but the console does provide the ability to export the managed disk which creates a temporary SAS URI and the ability to connect to the blob and download via your browser or via the Azure Storage REST API.


The concern that some might have is that any administrator with access to the Managed Disk resource(s) can simply export the VHDs and run off with the data. First, you should be always auditing actions such as these via the Activity Log. Second, you can block the ability to do this in the first place by using RBAC in Azure. Here is the full list of Azure Role-Based Access Control operators. The two operations specific to Managed Disk export are:

  • Microsoft.Compute/disks/beginGetAccess/action (Get Disk SAS URI)
  • Microsoft.Compute/disks/endGetAccess/action (Revoke Disk SAS URI)

To block these operations, you need to add them to the NotActions for a custom role and then assign that custom role to your administrators. For example, this is the JSON definition for a custom role that is equivalent to a contributor but blocks managed disk export and snapshot operations specifically. Full documentation for creating custom roles here:


Here’s a simple PowerShell script which will list all of the RBAC roles in the current selected subscription and identify whether or not these operations are listed either in the Action or NotAction. You can run this against a specific subscription to see if there’s a role defined to block these operations and then look at that role in the Web Portal to see who is assigned that role.



Azure Application Gateway SSL Policies

A client recently ran Qualys SSL Server Test against their web applications published through the Azure Application Gateway. The test graded the SSL security on the site as a “B” mainly because the server supported weak Diffie-Hellman (DH) key exchange parameters.

Diffie-Hellman key exchange is a popular cryptographic algorithm that allows Internet protocols to agree on a shared key and negotiate a secure connection. SSL sites that support export cipher suites and don’t use 2048-bit or stronger Diffie-Hellman groups with “safe” primes are susceptible to attacks like LogJam. Luckily, a feature known as SSL Policy in the Azure Application Gateway allows you to reduce the potential for these types of attacks.

The SSL handling in Azure Application Gateway (used for things such as SSL offloading and centralized SSL handling) allows you to specify a central SSL policy that’s suited to your organizational security requirements. The SSL policy includes control of the SSL protocol version as well as the cipher suites and the order in which ciphers are used during an SSL handshake. Application Gateway offers two mechanisms for controlling SSL policy: either a predefined policy or a custom policy. Here’s a link to the documentation for SSL policy with Azure Application Gateway. Changing the SSL policy for a new Application Gateway deployment can be accomplished using PowerShell and changing an existing deployment’s SSL policy is also easily done via the cmdlets. Below is an example of how to do this with a few lines of PowerShell.

One “gotcha” is that the predefined SSL policy which disables the weaker cipher suites also sets a minimum TLS version of v1.2 and breaks most older browsers. If that’s not a concern, use the latest predefined SSL policy – otherwise you’ll have to use a custom policy and specify a lower minimum TLS version to support older IE browsers running on Windows 7, for example.

# Get Configuration of AppGW
$appgw = Get-AzureRmApplicationGateway -Name $GWName -ResourceGroupName $GWResourceGroupName
# Set SSL Policy on AppGW to Custom Policy based on Most Recent Security Policy w/TLSv1.0 Support. FYI: Will work on any version of IE > 8.0 running on Windows 7. No Windows XP support!
# Set SSL Policy on AppGW to Most Recent Policy w/TLSv1.2 Minimum Support. FYI: Becuase TLS v1.0 is not supported, this will break any browser earlier that IE 11!
Set-AzureRmApplicationGatewaySslPolicy -ApplicationGateway $appgw -PolicyType Predefined -PolicyName “AppGwSslPolicy20170401S”
# Update the gateway with validated SSL policy
Set-AzureRmApplicationGateway -ApplicationGateway $appgw

PowerShell Language Modes

Language Modes in Windows PowerShell essentially define which elements of the PowerShell language can be used in a PowerShell session. As you’ve already discovered, the different language modes are documented publicly here. Language modes are intended to be specified as part of a session configuration file when a new PowerShell session is launched on a system.

Another way of setting the language mode for a PowerShell session would be to use either DeviceGuard or AppLocker in enforced mode with PowerShell 5+ and WMF 5+ or (more easily) to simply make use of a system environment variable called “__PSLockDownPolicy” to configure it. The system environment variable could be controlled on managed PCs in a variety of ways including via Group Policy.

There are two things to keep in mind regarding the use of language modes and the “__PSLockDownPolicy” system variable.

The first is that both the restricted language mode and constrained language mode could very likely have an impact on any SCCM scripts that use PowerShell or with any remote PowerShell management that you may be performing against systems. If scripts contain any scripting elements or code elements from other languages, they will most likely be prevented from running as expected. At its most restrictive setting (restricted and no language), script blocks aren’t allowed and/or the only thing that can be executed are cmdlets without any language elements at all.

The second thing is that when setting the language mode via the system variable, it will apply to all sessions started on that system and can’t be easily overridden on a user-by-user basis or a session-by-session basis. This means that it will affect built-in security principals as well as local users and would certainly have an effect on not only SCCM scripts and remote PowerShell management but other things like setting task scheduler to run as System and kick off a script at a pre-defined time.

The moral of the story is that while enforcing the PowerShell language mode on systems in an environment can reduce the potential for PowerShell to be used as an attack vector in malware or other exploits, it can have a pretty big impact on managing those systems via PowerShell for the purposes of good, not evil.

Azure VM Recreation Script

There are many tasks associated with virtual machines in Azure which can only be performed by deleting the VM configuration while preserving the underlying virtual hard disks and then recreating the VM configuration with the proper settings. Some of the things that come to mind are:

  • Renaming a VM resource
  • Moving a VM from one VNET to another
  • Moving a VM from one Azure region to another
  • Moving a VM into or out of an availability set
  • Changing a single NIC VM to a multi NIC VM and vice versa

There are likely others, I’m sure. However, these are actually pretty basic needs for most folks and it’s a shame it isn’t easier to do it. I’ve gotten these types of requests so many times that I finally decided to build a script as a basis for enabling them in a semi-automated fashion. Attached is sample script which includes the methodology and was designed to move a VM in one region to another region assuming that someone copied the underlying VHDs to the destination using either AzCopy or Start-AzureStorageBlobCopy.

At a high-level, here’s what the script does:

  1. Authenticates to the specified Azure subscription if necessary
  2. Reads a list of disk names and VHD URIs for the underlying disks
  3. Gets the source VM definition using Get-AzureRmVM
  4. Creates a new VM definition in the destination location
  5. Adds OS Disks and Data Disks using the provided disk mappings
  6. Creates NIC(s) for destination VM – prompts for new IPs for static addresses
  7. Deploys new VM

It goes without saying that the source VM should be stopped when the VHDs are copied and the script is run. There’s no need to delete the source VM until the new one is successfully built. This handles availability sets if the original VM was in one and works for VMs with either managed disks or unmanaged disks. There are some limitations as of now:

  • Doesn’t work with VMs encrypted using Azure Disk Encryption (ADE)
  • Doesn’t move Public IP resources
  • Doesn’t move NSGs if those were assigned to the VM’s NIC(s) directly
  • Will only move the first IP configuration for each NIC
  • Doesn’t recreate any tags associated with the source VM
  • Doesn’t redeploy any extensions present on the source VM

The real idea behind this was that it would serve as a starting point. This same script could easily be used to migrate a VM from standard to premium storage with a few tweaks or to redeploy a VM to a different VNET or availability set if desired. Hopefully folks find it useful as a starting point for their own adventures.

Create VM from VHD v3 (PowerShell script)