Tuesday, October 25, 2016

Azure Resource Manager and JSON templates to deploy RDS in Azure IaaS – Part 6 RD Gateway

This is 6th edition in a series of articles on this blog related to the automatic deployment of RDS on Azure IaaS using ARM and JSON. This edition is related to the further configuration of the RD Gateway role and is based on what was covered here before. I won’t go into detail here again on what was covered in previous articles but for completeness, here are the links of those previous 5 articles. PART1, PART2, PART3, PART4, PART5.

So, now that we have an entire RDS deployment which is HA, with SSL certificates configured, based on a custom template image I thought it would be a good idea to add additional configuration for the RD Gateway role. When installing the RD Gateway as part of a RDS deployment starting from Windows Server 2012, two default configurations rules are added to the RD Gateway that help to directly start using the RD Gateway role. With Windows Server 2016 one of these default rules has been expanded as well. For more details on that, also see: New default RD Gateway Resource Authorization Policies in Windows Server 2016.

So what is created by default?

- A default Connection Authorization Policy (CAP) is added that simply allows access to the RD Gateway for the group Domain Users. This is to make sure that you can start using RD Gateway immediately, however in production environments I advise to modify this CAP to only allow access by a specific (Active Directory) group of users. This is not changed with Windows Server 2016.

- A default Resource Authorization Policy (RAP) is added that allows access through RD Gateway towards all computer objects of the domain (via the Domain Computers group). Again, this is added to allow easy setup and in production environments I advise to modify this RAP to only allow access to specific resources of your RDS deployment. With Windows Server 2016 a RAP is also added to allow access the RD Connection Broker DNS name (when in HA) and RD Connection Broker servers.

To summarize, by default the RD Gateway will allow all domain users to access all domain computers via the RD Gateway. While this does not necessary have to be a security issue, I would always advise to remove or disable these default rules and add new rules that specify explicitly the group of users that is allowed to access a specific group of resources. This is exactly what this addition to the ARM / JSON template will add.

A couple of new parameters have been added to the ARM template to allows us to specify the properties of the rules to be created inside the RD Gateway role.

Specifies the name of the RD Gateway Resource Authorization Policy (RAP) that will be created

Specifies the name of the RD Gateway Connection Authorization Policy (CAP) that will be created

Specifies the group of users in Active Directory that you want to allow access through RD Gateway

Specifies the name of the RD Gateway Managed Group of resources that will be created. This Gateway Managed Group will be populated with the necessary destinations to allow access the RDS environment.

The RD Gateway configuration we are aiming to perform is based on PowerShell. In order to run an automated PowerShell script as part of ARM we leverage the CustomScriptExtension and specify the PowerShell script that contains the CmdLets. The parameters specified above will be passed on to this PowerShell script using the commandToExecute property.

The PowerShell script itself imports the RemoteDesktopServices module to be able to use the New-item and Remove-Item Cmdlets to modify the RD Gateway polices. For more information on this topic also see: https://blogs.technet.microsoft.com/ptsblog/2011/12/09/extend...

As a first step the existing RD CAP and RD RAP rules will need to be removed. Again, we do this because the combination of these two rules allows all domain users to access all domain computers via the RD Gateway.

The name of the default RD CAP (in Windows Server 2016) is RDG_CAP_AllUsers. The CmdLets below will take care of the removal of this RD CAP.


In Windows Server 2016, based on a HA environment of the RD Connection Broker role, 3 default RD RAP rules are created. These will allow access to the RD Connection Broker servers (for the initial connection), the RD Connection Broker DNS name (because it is in HA) and AD group Domain Computers. The CmdLets below will take care of the removal of these RD CAP’s.

Now that we have a clean sheet we can start to create our own custom RD CAP and RD RAP rules based on the parameters passed via the ARM template.

The creation of the RD CAP rule is performed by a single CmdLet. Using this CmdLet a new RD CAP is created that is configured to allow members of the specified group access to the RDS environment.

Before creating the RD RAP, we need to create the RD Gateway Managed Group that contains a list of destination resources that we explicitly allow access to. This is performed by the following CmdLets.

After that the New-Item CmdLet can be used to add the necessary resources to this RD Gateway Managed Group. Based on the HA environment we are creating we need to add the following resources:

- The RD Connection Broker DNS name
- The RD Connection Broker servers
- All of the individual RD Session Host servers

Because the ARM template has created each of the objects above it is already aware of these names and is able to pass them as parameters to the PowerShell script.

The final step is to create the RD RAP based on the same AD group of users and specifying the RD Gateway Managed Group we created previously.

Let’s take a look at the results in the RD Gateway Manager.

The default RD CAP rule is removed and a new RD CAP rule is added with the name that was specified in the ARM template and allowing access to members of the group as specified in the ARM template.

The 3 default RD RAP’s have been removed and a new RD RAP is created with the name that was specified in the ARM template and providing access to the new RD Gateway Managed group containing the resources we specified above.

When logging on to the RDS environment as a test user, we can confirm that the new RD CAP and RD RAP policies are working and are allowing access for our testuser which is a member of the authorized group.

The RD Gateway monitor also confirms the active session through the RD Gateway with the new RD CAP and RD RAP in place.

To summarize, in this blog post we have covered additional configuration of the RD Gateway role by removing the default policies and creating new custom policies. This allows us to make sure the RD Gateway is only used by authorized users based on an Active Directory group and that these authorized users can only access authorized resources via the RD Gateway.

Wednesday, October 19, 2016

Azure Resource Manager and JSON templates to deploy RDS in Azure IaaS – Part 5

This is part 5 in a series of articles on using Azure Resource Manager (ARM) and JSON templates to create a full Remote Desktop Services environment in Azure IaaS.

Let’s briefly reiterate what was previously covered on this subject. It all started with a first RDS deployment on Azure IaaS covered in the article Full HA RDS 2016 deployment in Azure IaaS in < 30 minutes, Azure Resource Manager FTW! Although this first template already creates a high available RDS environment on Azure, many improvements and features have been added after that. In a second article called RDS on Azure IaaS using ARM & JSON part 2 I covered adding SSL certificate management, the creation of Session Collections, and setting session time out settings. To help visualize what is going on during the automated creation of the environment I created a third article in which I published 2 short videos’ which were also shown at Microsoft Ignite 2016. Up until now the automated RDS deployment was based on the default Windows Server 2016 TP5 image in Azure for the RD Session Host role. Last week after Windows Server 2016 became GA, I updated the deployment to support that version. For demo or PoC environments the default image is ideal, however is most scenarios your, for example, finance department would not be using calculator as their primary published application. In a forth article I covered adding a Custom Template Image for the RD Session Host servers to be able to publish custom applications. This article also briefly touched on RD Licensing configurations, and basic RD Web Access customizations.

So, back to part 5 of the series. We’ll take everything covered in the previous articles as a starting point and are building on top of that. What features are we adding in this version?

- Configurable Active Directory OU locations
- Securing our Custom scripts in Azure blob
- Load Balancing the RD Connection Broker role
- Restricting access to only allow specific groups

Active Directory OU location
In previous versions of the ARM template all servers containing RDS roles created by the JSON template ended up in the default Organizational Unit (OU) in Active Directory. While it’s relatively easy to move these computer objects to a designated OU structure after the domain join process, it’s a good common practice to create computers objects in the designated OU directly during the domain join. Not only does this save time in the process, in some scenario’s where the default OU might have been changed, unwanted Group Policy Objects could be applied to these new servers. Let’s take the following OU structure as an example.

To accommodate the creation of the RD servers inside a custom OU structure, I have added the following parameters to the environment.

As part of this change I decided to also move away from using Desired State Configuration (DSC) for the domain join process. Instead of DSC I moved to using an extension directly in ARM. There is a good example available on this extension as part of Microsoft’s Azure Quick Start Templates: 201-vm-domain-join.

Below you can see the extension in action. The type needs to be configured as “JsonADDomainExtension”. And as part of the settings, the OUPath can be provided.clip_image006

As a result, the server objects are created in the designated OU’s as part of the domain join process.

Securing the Custom scripts
As discussed in previous blog posts, I use the CustomScriptExtension in ARM to be able to launch a PowerShell script to perform the actual deployment of the RDS roles and further configuration. The idea behind the CustomScriptExtension is that you provide a download location where the VM can download the script and execute it. There are various options to store these files. In some cases, you might want to share your scripts with others, in those cases GitHub is ideal. This is also the location where Microsoft provides many examples as part of the Azure Quickstart Templates they provide. In some cases, you might not want to use GitHub to store the scripts publically. You might have developed a custom script that you only want to use inside your organization. In those cases, its’ very convenient to place those files in a container in Azure in the same subscription where you also deploy the RDS environment. As I’ll discuss later on in this chapter, you can also use this method to secure your custom scripts and prevent others from downloading them. Let’s take a look at how to configure this.

First of all, you need a location (storage account) in the Azure Subscription you want to use. Inside this storage account we create a new container.

We can now use this container to upload our custom scripts. Although you can do this using the Azure Portal or using PowerShell, I prefer to use the Microsoft Azure Storage Explorer. This is a small tool you can download and install on macOS, Linux, and Windows. Get the download here: http://storageexplorer.com/

Using the Azure Storage Explorer, you can easily manage the files inside the blob storage.

Inside our ARM deployment we can now refer to this location in Azure as our custom scripts location to download the script, we provide this URL inside a parameter.

Although the scripts are now stored inside our Azure Subscription, they are still publically accessible. Anyone that would know the location could browse to the scripts and download them. Again, in some scenarios that might not be an issue if the files don’t contain any sensitive data. But in some scenario’s you will want to prevent public access to the scripts.

In order to create a secure location, the access type of the container needs to be changed to Private.

Setting the Access type to Private ensures that there is no anonymous access. Because of this ,the data inside the container cannot be accessed without providing the access key of the storage account.

Now that the container is set to private, how do we access the scripts from within our ARM deployment? Using the same CustomScriptExtension as before we provide the location (URL) of the script as part of the fileUris settings. To be allowed to access the script from within our ARM deployment, we provide both the storageaccountname as well as the storageaccountkey. To make sure these are encrypted we place them inside the ProtectedSettings section of the CustomScriptExtension.

And to make things fully secure we obviously don’t store the storageaccountkey in plain text in our scripts, but rather store the storageaccountkey as a secret inAzure Keyvault.

Using a KeyVault reference we can safely access the storageaccountkey in our ARM deployment

Using this method, we have now created a secure location to store scripts and other files that can be leveraged by our ARM deployment.

Load balancing initial connection RD Connection Broker
In previous versions of the ARM deployment I’ve setup a load balancer to provide high availability and load balancing for the RD Web Access and RD Gateway role. This load balancer, also created by ARM, is equipped with a public IP address to be able to access the environment from the outside. But what about load balancing of the RD Connection Broker role? As you might know, since Windows Server 2012, the RD Connection Broker always handles the initial connection of any user connecting to the environment. Although this process is transparent to the end user, any incoming session will be connecting to the RD Connection Broker first via RDP (3389). The RD Connection Broker then redirects the session, resulting in another connection toward the final destination, one of the RD Session Host servers. This process is explained in more detail here. So in a scenario where we have multiple RD Connection Brokers configured in a High Available scenario, we ideally also make sure we load balance this initial connection. Although this can also be performed by using DNS Round Robin, DNS RR is not aware of RD Connection Broker servers that unreachable and the workload will not be divided equally in most scenario’s. Instead of DNS RR, lets leverage the same type of Azure load balancer we used for the RD Web Access and RD Gateway role, this time load balancing an internal connection.

Since I didn’t cover the load balancer in much detail in previous articles, let’s take a closer look at how this is configured. Inside our ARM deployment we create a new Load Balancer resource as specified below. We place it in the same subnet as the RDS environment and provide a static internal IP Address.

Inside the RD Connection Broker resources in the ARM template, we specify the load Balancer Backend Address Pools property referring back to the pool we also specified above. This is to make sure both RD Connection Broker servers will become members of the pool, and thus become the to be load balanced servers.

Next, we define the load balancing rules. For this scenario we specify will want to load balance TCP port 3389 and set additional parameters for setting like FloatingIP, Idle Time out etc.

Lastly, we configure the probes. By configuring a probe, we tell the load balancer which ports to probe on the destination servers to determine if one of the servers is down.

As an end result we have a new Load Balancer in Azure

And the Load Balancer holds a Back End Pool containing our 2 RD Connection Broker servers.

Now that we have an internal load balancer with our 2 RD Connection Broker servers, we need to take one final step to make sure we can start using it. As you can see the RD Connection Broker Load Balancer was configured with the internal IP Address So we now need to make sure that the RDS deployment points to this IP address to start serving incoming connections. The ARM deployment is already configured to create a HA configuration for the RD Connection Broker role.

As also explained in previous articles, this is configured by a PowerShell script inside an ARM CustomScriptExtension. One of the parameters that is passed to the script is the RD Connection Broker DNS name (RD Connection Broker Client Access Name)

It’s this DNS name that is used by clients connecting to the RDS deployment so we need to make sure this DNS name resolves into the internal IP Address of the load balancer. Since we are using the RD Gateway in this deployment as well, more specifically we need to make sure the RD Gateway role can resolve the DNS name. To accomplish this, we create an A record in DNS matching the Connection Broker Client Access Name and pointing to the IP Address of the load balancer.

And that’s it. Incoming connections through the RD Gateway are now send to one of the two RD Connection Brokers load balanced by the Azure Load Balancer.

Restricting access to only allow specific groups
By default a Session Collection provides access to the Domain Users group in Active Directory. In most cases however you want to restrict access to a specific group of users. To accommodate this I added a new parameter to the ARM deployment.

This parameter is added to the Custom Script extension we’ve mentioned several times before. This scripts adds the AD group provided in the parameter and removes the default Domain Users group. Taking a look at the Server Manager console we can confirm that the RDS deployment is now only accessible for members of the specified AD group. This is a permission on the Session Collection itself, in an upcoming article in this series, I’ll also cover applying specific groups to access the RD Gateway components.

Tuesday, October 18, 2016

Fix available for User Profile Disk unmount issue causing temporary profiles

A fix is now available for the User Profile Disk issue where a UPD does not correctly unmount at logoff causing temporarily profiles!

"...Addressed issue where the user profile disk (UPD) does not get unmounted when a user logs off. Therefore, users get temporary profiles and are not able to work with their own profiles during their next logon. The Event ID 20491 with a description of “Remote Desktop Services could not disconnect a user disk for the user account with a SID of <SID>. The error code is 0xAA.93” will be logged..."

Source: https://support.microsoft.com/en-gb/help/24717/windows-8-1-windows-server-2012-r2-update-history

The update is part of the October 2016 Preview of Monthly Quality Rollup for Windows 8.1 and Windows Server 2012 R2


Wednesday, October 12, 2016

Windows Server 2016 GA available in Azure! – used it to deploy RDS on Azure IaaS!

Window Server 2016 DataCenter (14393.321) is now available as an image in Azure IaaS.
I decided to use it to roll out as part of my existing ARM Deployment of RDS on Azure IaaS using JSON. One of the awesome things about the ARM/JSON approach is that it all it took was adding a single parameter option into the azuredeploy.parameters.json file to complete this!

This is where I added the new SKU inside the template parameters file a newly allowed value.

And before launching the ARM deployment, the SKU can be selected from a dropdown box, now with the default being Windows Server 2016 Datacenter.

The entire deployment is now fully performed on Windows Server 2016, RD Web Access now shows the Windows Server 2016, where Technical Preview 5 (TP5) did not.

This version is not available on MSDN yet, so Cloud First, Mobile First!

Tuesday, October 11, 2016

Added new features to RDS on Azure IaaS using ARM and JSON (licensing, Custom RDSH Templates, branding)

If you have been following this blog over the past couple of weeks, you might have read about my previous articles on deploying RDS on Azure IaaS using ARM and JSON templates. To quickly reiterate those previous articles;

[clip_image018%255B4%255D.jpg]In a first article called “Full HA RDS 2016 deployment in Azure IaaS in < 30 minutes, Azure Resource Manager FTW!” I explained the differences between deployment mechanisms in the classic Azure Portal and the new Azure Portal and gave a brief introduction on what JSON is and how to use Visual Studio to build and deploy directly to Azure, based on JSON templates. I showed the end result of this deployment, a high available RDS deployment on Azure IaaS.

[clip_image002%255B5%255D.jpg]In a second article called “
RDS on Azure IaaS using ARM & JSON part 2 – demo at Microsoft Ignite!” I showed some of the enhancements I had built on top the JSON templates. In this article I showed the ability to add publicly trusted SSL certificates, 2 Session Collections with a few sample RemoteApps, configurable Session Timeout settings and the use of 2 storage accounts. This article also contains a link to a session at Microsoft Ignite 2016 where the deployment of this JSON template was shown.

clip_image001[6]Last week I also separately published the 2 short video’s that show the deployment and the end result in action in an article called Video of Ignite session showing RDS on Azure IaaS deployment using ARM/JSON now online!



In this article I want share some of the additions that I have been adding to the ARM deployment.

Configure Licensing method
The previous version of the ARM deployment already added 2 RD Licensing servers to the deployment which are needed to install RDS CAL’s. What’s now also added is the ability to select the desired RDS Licensing method (per user or per device).
When the deployment is started, the desired licensing method can be selected from a dropdown list.

And after completion of the ARM deployment, the selected licensing method is successfully configured in Server Manager.

For setting the RD Licensing method I’m using a PowerShell command by expanding the already existing PowerShell Extension. In the first article I already briefly mentioned the PowerShell Extension option in ARM. It allows you to specify a PowerShell Script to perform actions within a Virtual Machine once it’s deployed. The screenshot below shows how to call a PowerShell Extension. For more information on how to set these up, also see: Windows VM Custom Script extensions with Azure Resource Manager templates

Add Custom RDSH Image
Previous ARM deployments have all been based on a standard Windows Server 2016 image for the RD Session Host Role. In most scenarios however, you would obviously want to deploy your own applications. To accommodate this, I added functionality to select a custom RD Session Host template image to be used for the RD Session Host servers. This allows you to preconfigure a RD Session Host template with custom applications and settings and provide that as a parameter to the ARM deployment.

As part of the previous ARM deployments I also created the necessary storage accounts prior to creating the Virtual Machines. However, if you want to deploy a virtual machine in ARM based on a custom image, that custom image needs to reside in the same storage account as the to be created virtual machine. Because of this (current) limitation we run into a Chicken and Egg problem. How can we make sure that the Custom Template Image is available in the storage account if that storage account is not created yet? There are basically 2 ways to solve this.

The first option is to copy the custom template image as during the ARM deployment. So, after creating the storage account and before creating the RD Session Host servers. The copy action can be performed using Azure PowerShell, so in order to be able to kick of that PowerShell command as part of ARM we need a “dummy” Virtual Machine and create a Custom PowerShell Extension on that. A good example how to perform this is can be found here: Create VM from a custom image in new storage account. Instead of the “dummy” server you can of course also “abuse” another virtual machine that you are also deploying as part of your ARM deployment and configure the Custom PowerShell Extension on that virtual machine. Also be aware that the copy job can add a significant amount of time to the ARM deployment. In my testing a Windows Server 2016 template with Office 2016 installed took about 15 minutes to complete.

The second option is a different and maybe less complex approach. Since we are creating a RD Session Host template, a storage account to host that template is already in place. Why not reuse that storage account to also host the deployed RD Session Host servers? In that case the custom template does not have to be copied and the ARM deployment only needs to be provided with the storage account name and the template name so it can reuse that storage account and deploy the RD Session Host servers in there.

For my ARM template I chose the second option. As part of the parameters the storage account name and the RD Session Host Custom Image can now be provided.

Using the image property of the Virtual Machine we can instruct ARM to use our Custom Template Image.

In this example I used a Custom Template Image based on Windows Server 2016 with Office 2016, Notepad++ and Paint.NET installed as the sample custom applications.

To be able to immediately publish the custom applications I added the following parameters to the ARM deployment. Again, the deployment uses the existing Custom extensions and leverages PowerShell to publish these applications during the ARM deployment

The end result for the end user is that the custom applications are available and accessible in for example RD Web Access as shown below.

Perform basic RD Web Access Branding & customization
To be able to add some very basic RD Web Access branding I added 2 parameters to the ARM deployment that allow you to specify the Workspace name and change the default logo in RD Web Access.

Again using the existing Custom PowerShell extension, these settings are now changed suing PowerShell Cmdlets and the changes are visible to the end user. Obviously these 2 items are not rocket science, but you can image we could extend this to brand the entire Web Access page if we wanted to including colors, fonts etc.

To summarize this article, using ARM and JSON we are now able to;
- Configure the desired Licensing method (User or Device CAL’s)
- Use a Custom Template Image for the RDSH role
- Publish Custom Applications
- Perform basic RD Web Access branding

If you have questions on how certain parts of this deployment have been performed, feel free to reach out to me! Stay tuned for more updates on this RDS deployment in Azure IaaS using ARM!