Wednesday 3 December 2014

FIM on Azure

While deploying your Forefront Identity Manager labs in your own local virtual environment is convenient, it does consume a lot of your precious disk drive space and there is no questioning the impact of hardware failure. So why not move your virtualization layer to the cloud and let Azure take care of the storage, networking and compute infrastructure for you? This post will go over the steps we took in order to successfully automate the deployment of our FIM lab environments on the Microsoft Azure platform.

Azure infrastructure fundamentals

In order to create domain joined environments in Azure, there are four components we need:

1. An affinity group
Having our resources deployed in the same region (data center) is a fair option, but there is no certainty these resources are also located in the same cluster within that data center. Using affinity groups, we can define a container in which all our virtual machines are physically placed close together. This improves latency, performance and thereby cost.
2. A cloud service
This component is responsible for hosting our virtual machines. It gets assigned a public IP address, making it possible for you to connect to your environment from any location using your own defined endpoints.
3. A virtual network
In a domain joined setup it is necessary your machines can talk to each other. Using a VPN, we make sure VM's are deployed in the same IP range. These VM's can be assigned a static internal IP address which makes it possible to define your domain controller as the DNS server for the virtual network.
4. A storage container
Each deployment gets its own container to host their virtual hard disks (VHD's) under a storage account which is linked to the subscription of the deployment's cloud service.

Setup process

The whole process is executed using the Azure library module for PowerShell. First we authenticate our Azure account and select the current subscription we wish to use for our setup. We then assign a valid storage account to this subscription.

Combining the infrastructure elements we can set up our Azure environment in which our lab will be deployed. We first check and create a valid cloud service name in an affinity group. Then we retrieve the xml configuration. In this configuration we insert our new VPN, and DNS server to use. The address space for this virtual network will be, with a DNS server referenced to the IP address of the domain controller. Finally we create a new storage container for this lab. And that's it, our environment is ready for deployment.

Next up we will provision our servers. We have preconfigured each server up to the point of domain joining and captured a generalized VHD of this state. These VHD's are stored as images on our storage account so we can use them over and over again as a base machine for each server. Each machine has it's own parametrised configuration consisting of the VM name, size, location of the VHD, image to use and endpoints to assign for both RDP and remote PowerShell. We assign it the correct static IP address and subnet name defined in the VPN configuration. The next step depends on the type of server, there are 2 ways of defining the provisioning configuration.

We start with the AD server, which will not include any domain parameters. We define our provisioning parameters just like we would provision a standalone machine. When the machine is booted up, we run a remote script through the PowerShell endpoint and promote it to a domain controller. And voila, we created a domain within our VPN.

Next up we provision the other type (non-AD) of servers to the domain. Sadly, it is currently not supported to send parallel requests on the same cloud service using the Azure API. Instead, and because the domain provisioning configuration is the same for all the other servers, we can create the instance for each server and send them all together in one creation bulk request. This is as close as it gets to parallel provisioning of multiple servers in the same cloud service.

After the domain provisioning step has been executed, we automate the configuration of each server using PowerShell scripts which run on the PowerShell endpoint defined for that server.

Faster deployments?

Depending on the chosen server setup, this process can take quite a while to complete (mainly the installation of software during configuration).A basic setup consists of an AD / SQL / FIM server and takes about half an hour to complete in it's most basic configuration. Available optional servers include Exchange, BHOLD, and SCSM (both management server and data warehouse) which takes the total server count up to 7 servers. A full setup takes a lot longer and for this reason, we implemented a complementary way of setting up our labs. We started from a fully working lab setup and captured the VM's as specialized images as opposed to generalized in the previous method. This way you can use these images in a new azure environment in a slightly different provisioning configuration and have your basic deployment set up in less than 6 minutes! The drawback of this, is that the lab is not completely configurable as it uses a saved state (snapshot) of a previous domain joined setup.

The lazy way

Having a PowerShell cmdlets library at our disposal is really nice, although running these commands ourselves is not really what we were after. So we made our own WPF application to create an interface which will invoke the underlying PowerShell scripts (both the Azure module locally and configuration of servers remotely) in C# using a PowerShell class. During setup, passwords for all the (service) accounts are generated and stored in an xml file which is compliant for import to KeePass. The RDP configuration is automatically generated in an RDG file which can be opened with RDCManager (

Let’s round up with some visual material!

Account setup:

Environment setup:

Redeploy a default lab with a limited set of parameters:

Fully customize your deployment parameters for each server:

Start a full installation or manually proceed with each step: