Creating Azure Virtual Networks using Powershell and XML Part 2: Powershell functions

In my previous post I talked about what was involved in creating an Azure network configuration using Powershell. In this post I’ll cover where I’ve got so so far, which is a series of functions that do the following:

  1. Contact Azure and get the current network configuration. Convert that to sensible XML and if it’s empty, create the basic structure.
  2. Create a new virtual network, checking to see if one with the same name already exists.
  3. Add a subnet to a virtual network, checking to see one with the same address prefix or name doesn’t already exist.
  4. Add a DNS reference to a virtual network, making sure the DNS is defined first.
  5. Create a DNS.
  6. Put the configuration back into Azure to be applied.

Still on my to-do list are removing networks and other elements, and modifying existing networks.

The Function Code

The end result so far is a powershell script that can be loaded to give a number of new functions:

Get-azureNetworkXml

get-azureNetworkXml runs the get-AzureVNetConfig command. It takes the XMLConfiguration from that command and puts it into a new XML object. If there is no configuration, it creates a new xml object. It then checks to see if the main XML elements are present and, if not, creates them.

Whilst this function returns an object, I need to make sure (right now) that the variable nme I use for that is $workingVnetConfig as other functions reference it. I’m not currently passing the XML object into each function. I probably should, but that tidying comes later.

function get-azureNetworkXml {  $currentVNetConfig = get-AzureVNetConfig if ($currentVNetConfig -ne $null) { [xml]$workingVnetConfig = $currentVNetConfig.XMLConfiguration } else { $workingVnetConfig = new-object xml }  $networkConfiguration = $workingVnetConfig.GetElementsByTagName("NetworkConfiguration") if ($networkConfiguration.count -eq 0) { $newNetworkConfiguration = create-newXmlNode -nodeName "NetworkConfiguration" $newNetworkConfiguration.SetAttribute("xmlns:xsd","http://www.w3.org/2001/XMLSchema") $newNetworkConfiguration.SetAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance") $networkConfiguration = $workingVnetConfig.AppendChild($newNetworkConfiguration) }  $virtualNetworkConfiguration = $networkConfiguration.GetElementsByTagName("VirtualNetworkConfiguration") if ($virtualNetworkConfiguration.count -eq 0) { $newVirtualNetworkConfiguration = create-newXmlNode -nodeName "VirtualNetworkConfiguration" $virtualNetworkConfiguration = $networkConfiguration.AppendChild($newVirtualNetworkConfiguration) }  $dns = $virtualNetworkConfiguration.GetElementsByTagName("Dns") if ($dns.count -eq 0) { $newDns = create-newXmlNode -nodeName "Dns" $dns = $virtualNetworkConfiguration.AppendChild($newDns) }  $virtualNetworkSites = $virtualNetworkConfiguration.GetElementsByTagName("VirtualNetworkSites") if ($virtualNetworkSites.count -eq 0) { $newVirtualNetworkSites = create-newXmlNode -nodeName "VirtualNetworkSites" $virtualNetworkSites = $virtualNetworkConfiguration.AppendChild($newVirtualNetworkSites) }  return $workingVnetConfig } 

Save-azureNetworkXml

Save-azureNetworkXml gets passed our XML object, writes it out to a file in the temp dir and then calls set-AzureVNetConfig to load the file and send it to Azure.

function save-azureNetworkXml($workingVnetConfig) { $tempFileName = $env:TEMP + "\azurevnetconfig.netcfg" $workingVnetConfig.save($tempFileName) notepad $tempFileName  set-AzureVNetConfig -configurationpath $tempFileName } 

Add-azureVnetNetwork

Add-azureVnetNetwork is called with three parameters: networkName, affinityGroup and addressPrefix. It will add a new VirtualNetworkSite element, with the name and affinity group as attributes. It checks to make sure the affinity group exists first. It then creates the address prefix within the network.

function add-azureVnetNetwork { param ( [string]$networkName, [string]$affinityGroup, [string]$addressPrefix )  #check if the network already exists $networkExists = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSite") | where {$_.name -eq $networkName} if ($networkExists.Count -ne 0) { 	write-Output "Network $networkName already exists" 	$newNetwork = $null 	return $newNetwork }   #check that the target affinity group exists $affinityGroupExists = get-AzureAffinityGroup | where {$_.name -eq $affinityGroup} if ($affinityGroupExists -eq $null) { 	write-Output "Affinity group $affinityGroup does not exist" 	$newNetwork = $null 	return $newNetwork }  #get the parent node $workingNode = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSites") #add the new network node $newNetwork = create-newXmlNode -nodeName "VirtualNetworkSite" $newNetwork.SetAttribute("name",$networkName) $newNetwork.SetAttribute("AffinityGroup",$affinityGroup ) $network = $workingNode.appendchild($newNetwork)  #add new address space node $newAddressSpace = create-newXmlNode -nodeName "AddressSpace" $AddressSpace = $Network.appendchild($newAddressSpace) $newAddressPrefix = create-newXmlNode -nodeName "AddressPrefix" $newAddressPrefix.InnerText=$addressPrefix  $AddressSpace.appendchild($newAddressPrefix)  #return our new network $newNetwork = $network return $newNetwork   } 

Add-azureVnetSubnet

Add-azureVnetSubnet takes three parameters: networkName, subnetName and addressPrefix. It makes sure the network exists, that the subnet doesn’t, and that the address prefix is not already used in the same network. It then adds the subnet to the network.

function add-azureVnetSubnet { param ( [string]$networkName, [string]$subnetName, [string]$addressPrefix )  #get our target network $workingNode = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSite") | where {$_.name -eq $networkName} if ($workingNode.Count -eq 0) { 	write-Output "Network $networkName does not exist" 	$newSubnet = $null 	return $newSubnet }  #check if the subnets node exists and if not, create $subnets = $workingNode.GetElementsByTagName("Subnets") if ($subnets.count -eq 0) { $newSubnets = create-newXmlNode -nodeName "Subnets" $subnets = $workingNode.appendchild($newSubnets) }  #check to make sure our subnet name doesn't exist and/or prefix isn't already there $subNetExists = $workingNode.GetElementsByTagName("Subnet") | where {$_.name -eq $subnetName} if ($subNetExists.count -ne 0) { 	write-Output "Subnet $subnetName already exists" 	$newSubnet = $null 	return $newSubnet  } $subNetExists = $workingNode.GetElementsByTagName("Subnet") | where {$_.AddressPrefix -eq $subnetName} if ($subNetExists.count -ne 0) { 	write-Output "Address prefix $addressPrefix already exists in another network" 	$newSubnet = $null 	return $newSubnet  }  #add the subnet $newSubnet = create-newXmlNode -nodeName "Subnet" $newSubnet.SetAttribute("name",$subnetName) $subnet = $subnets.appendchild($newSubnet) $newAddressPrefix = create-newXmlNode -nodeName "AddressPrefix" $newAddressPrefix.InnerText = $addressPrefix  $subnet.appendchild($newAddressPrefix)  #return our new subnet $newSubnet = $subnet return $newSubnet  } 

Add-azureVnetDns

Add-azureVnetDns takes two parameters: dnsName and dnsAddress. It then creates a new DnsServer element for that DNS.

function add-azureVnetDns { param ( [string]$dnsName, [string]$dnsAddress )  #check that the DNS does not exist $dnsExists = $workingVnetConfig.GetElementsByTagName("DnsServer") | where {$_.name -eq $dnsName} if ($dnsExists.Count -ne 0) { 	write-Output "DNS Server $dnsName already exists" 	$newDns = $null 	return $newDns } # get our working node of Dns $workingNode = $workingVnetConfig.GetElementsByTagName("Dns")  #check if the DnsServersRef node exists and if not, create $dnsServers = $workingNode.GetElementsByTagName("DnsServers") if ($dnsServers.count -eq 0) { $newDnsServers = create-newXmlNode -nodeName "DnsServers" $dnsServers = $workingNode.appendchild($newDnsServers) }  #add new dns reference $newDnsServer = create-newXmlNode -nodeName "DnsServer" $newDnsServer.SetAttribute("name",$dnsName) $newDnsServer.SetAttribute("IPAddress",$dnsAddress) $newDns = $dnsServers.appendchild($newDnsServer)  #return our new dnsRef return $newDns   } 

Add-azureVnetDnsRef

Add-azureVnetDnsRef takes two parameters; networkName and dnsName. It makes sure the network exists and that the DNS exists before adding a DnsServerRef element for the DNS to the network.

function add-azureVnetDnsRef { param ( [string]$networkName, [string]$dnsName )  #get our target network $workingNode = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSite") | where {$_.name -eq $networkName} if ($workingNode.count -eq 0) { 	write-Output "Network $networkName does not exist" 	$newSubnet = $null 	return $newSubnet }  #check if the DnsServersRef node exists and if not, create $dnsServersRef = $workingNode.GetElementsByTagName("DnsServersRef") if ($dnsServersRef.count -eq 0) { $newDnsServersRef = create-newXmlNode -nodeName "DnsServersRef" $dnsServersRef = $workingNode.appendchild($newDnsServersRef) }  #check that the DNS we want to reference is defined already $dnsExists = $workingVnetConfig.GetElementsByTagName("DnsServer") | where {$_.name -eq $dnsName} if ($dnsExists.Count -eq 0) { 	write-Output "DNS Server $dnsName does not exist so cannot be referenced" 	$newDnsRef = $null 	return $newDnsRef }  #check that the dns reference isn't already there $dnsRefExists = $workingNode.GetElementsByTagName("DnsServerRef") | where {$_.name -eq $dnsName} if ($dnsRefExists.count -ne 0) { 	write-Output "DNS reference $dnsName already exists" 	$newDnsRef = $null 	return $newDnsRef }  #add new dns reference $newDnsServerRef = create-newXmlNode -nodeName "DnsServerRef" $newDnsServerRef.SetAttribute("name",$dnsName) $newDnsRef = $dnsServersRef.appendchild($newDnsServerRef)  #return our new dnsRef return $newDnsRef   } 

Create-newXmlNode

Create-newXmlNode is called by all the other functions. It creates a new node in the XML object then hands it back to the calling function for modification and appending it to the relevant parent node.

function create-newXmlNode { param ( [string]$nodeName )  $newNode = $workingVnetConfig.CreateElement($nodeName,"http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration") return $newNode } 

Using the functions

Assuming all our functions are in a powershell file called Create-AzureNetwork.ps1, using the new functions is pretty straightforward. We load the functions from file (there is a space between the first . and the .\ in the first line. We can then call the functions.

Note that I use a variable called $workingVnetConfig here – that’s important, as we don’t pass the XML into each function, but rather use the way powershell handles variables which means that having defined it here, it’s available to all the functions when called.

. .\Create-AzureNetwork.ps1  $workingVnetConfig = get-azurenetworkxml  add-azureVnetNetwork -networkName "Mynetwork" -affinityGroup "MyAzureAffinity" -addressPrefix "10.0.0.0/8"  add-azureVnetSubnet -networkName "Mynetwork" -subnetName "subnet-1" -addressPrefix "10.0.0.0/11"  add-azureVNetDns -dnsName "test1" -dnsAddress "10.0.0.1"  add-azureVnetDnsRef -networkName "Mynetwork" -dnsName "test1"  save-azurenetworkxml($workingVnetConfig) 

It’s not the most elegant of code, I’ll admit, but it does what it says on the tin. All I have to do now is add functions to remove items from our network configuration, then add functions to modify existing items.

Creating Azure Virtual Networks using Powershell and XML

I’ll be honest, I expected this task to be easier than it is. What I’m working on is some powershell that we might use as part of automated build processes that will create a new Virtual Network in an Azure subscription. What I’m after is to add a new network to the existing configuration.

There aren’t many powershell commands for Azure virtual networks. The two we need to use are get-azureVnetConfig and set-azureVnetConfig.

Get-azureVnetConfig when run generates xml that details the configuration of all virtual networks within the current Azure subscriptions. Set-azureVnetConfig takes an xml configuration and modifies the entire virtual networking configuration to match that described in the file.

My original plan of simple powershell to add a new virtual network went quickly out of the window, then. My second thought was to grab the xml configuration, manipulate it using powershell, then stuff it back into Azure. That plan was hindered by the fact that the set-azureVnetConfig command insists on reading the configuration from a file on disk, so I can’t just hand it my XML object, created by manipulating the output of get-azureVnetConfig.

I’m still working on this – I now have a script with some tidy functions to do repetitive tasks. This post is simply going to outline the first bit of heavy lifting I’ve had to do in order to solve enough problems that I can get a config, add stuff to it and reload it into Azure.

The steps below don’t create all the configuration we will want, but it creates all the configuration we need to add a new network.

1. Get the current Azure Config

This bit is easy:

$currentVNetConfig = get-AzureVNetConfig

That gives us an object which contains the XML configuration. We need to get just the XML out, so:

[xml]$workingVnetConfig = $currentVNetConfig.XMLConfiguration

2. Find the VirtualNetworkSites element

The networks I want to create are all held in the VirtualNetworkSites element, each one in a VirtualNetworkSite element. I can create new VirtualNetworkSite elements, but I need to grab the element in which to create them first:

$virtNetCfg = $workingVnetConfig.GetElementsByTagName("VirtualNetworkSites")

3. Add a new Virtual Network

To add a new network we need to add a new VirtualNetworkSite element. I hit a snag with this, in that I kept getting a spurious xmlns attribute on the element that caused set-azureVnetConfig to spit out the file as invalid. It turns out that in order to avoid this, we have to specify the XML namespace URI when we create the new element. That’s the second parameter on the CreateElement method, below.

Creating the element itself is a two-stage process: First we create a new element inside our XML object, then we put that element in the right place by calling appendchild on the intended parent element. In addition, we need to add a couple of attributes to that element, specifying the name of the network and the affinity group it will sit in:

$newNetwork = $workingVnetConfig.CreateElement("VirtualNetworkSite","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $newNetwork.SetAttribute("name","myVirtualNetwork")  $newNetwork.SetAttribute("AffinityGroup","MyAffinityGroup")  $Network = $virtNetCfg.appendchild($newNetwork) 

4. Add an address space

This is a similar process. I need an AddressSpace element and within that sits an AddressPrefix element. That element needs text that tells Azure the IP address space to use, and that’s added by setting the innerText property.

$newAddressSpace = $workingVnetConfig.CreateElement("AddressSpace","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $AddressSpace = $Network.appendchild($newAddressSpace)  $newAddressPrefix = $workingVnetConfig.CreateElement("AddressPrefix","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $newAddressPrefix.InnerText="10.0.0.0/8"  $AddressSpace.appendchild($newAddressPrefix) 

5. Add a subnet

Virtual networks need subnets. There is a Subnets element that contains multiple Subnet elements, each of which has an AddressPrefix element.

$newSubnets = $workingVnetConfig.CreateElement("Subnets","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $Subnets = $Network.appendchild($newSubnets)  $newSubnet = $workingVnetConfig.CreateElement("Subnet","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $newSubnet.SetAttribute("name","Subnet-1")  $Subnet = $Subnets.appendchild($newSubnet)  $newAddressPrefix = $workingVnetConfig.CreateElement("AddressPrefix","http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration")  $newAddressPrefix.InnerText="10.0.0.0/11"  $Subnet.appendchild($newAddressPrefix) 

6. Write out to a file and then use that file

$tempFileName = $env:TEMP + "\azurevnetconfig.netcfg"  $workingVnetConfig.save($tempFileName)   set-AzureVNetConfig -configurationpath $tempFileName 

Next Steps

If you don’t have any Azure networks defined then get-azureVnetConfig will give you nothing. That means that more XML needs to be generated for a new network configuration. I’m working on a more expansive script right now and I’ll post that when I get something meaningful to show.

Dealing with AD sync issues in an Azure hybrid deployment

I’ve been building demo environments for Tech.Days Online for the past few days. I had been blogging as I built, but then I hit problems and time pressure meant I had to pause my series on building the hybrid network. I will pick up the remainder of those posts in the near future but in the meantime, I want to give you all the heads up on one of my problems.

When I came to install the directory synchronisation tool on my azure-hosted dirsync server I couldn’t get the configuration wizard to run. It kept telling me that the domain admin user I entered (the domain administrator!) was not a valid domain account. I tried removing the machine from the domain and re-adding it first to no avail, and then started looking at domain replication.

There were no errors in the event log, save for one solitary warning on each DC about time. DCDIAG spat out huge lists of errors on both servers. Repadmin refused to admit that the domain controllers knew about each other.

So, for ref, I was seeing:

  • RPC errors when trying to talk between domain controllers.
  • DNS servers were not synchronising.
  • DCDIAG on one server threw up range of errors:
    • EventID: 0x80000B46 related to kerberos.
    • EventID: 0x00001695 relating to failed registration of DNS addresses in the domain.
    • EventID: 0x00001695 relating to failed registration of DNS addresses in the ForestDNSZones subdomain.
    • EventID: 0x00001695relating to failed registration of DNS addresses in the DomainDNSZones subdomain.
    • EventID: 0x0000168E relating to failed registration of the DNS record _ldap._tcp.ForestDnsZones.<domain>
    • EventID: 0x0000271A relating to a failed DCOM registration.

The solution was to fix time on the domain. I ran through a number of articles on the subject, and at the back of mind was a recollection that time can drift when running in a VM.

In the end I followed the settings in this TechNet article. I set both domain controllers to sync time with an NTP source (time.windows.com) and ten left the whole thing to settle for an hour or so while we went for food. When I came back the domain had settled.

Sadly, my dirsync box was a casualty of the conundrum. Because I removed it from the domain while AD sync was not working I had a broken trust relationship. I removed it for the domain again, rejoined it and everything worked just fine.

As always, hopefully this will save somebody some time and grief when doing the same thing as I was.

Building an Azure IaaS and on-premise hybrid environment Part 2: DC and servers in the cloud

This is part 2 of a series of posts bout building a hybrid network connecting Windows Azure and on-premise. For more background on what the goals are, and for information on how to create the Azure Network and connect the VPN tunnel between on-premise and cloud see part 1.

Creating a DC on our Azure Network

I’m going to create a new VM on Azure using the VM gallery. One important point when doing this is that you should add a second drive to the VM for domain controllers. This is down to how read/write caching works on the primary drive (it’s enabled)  which means there is a risk that a write operation may make it to the cache but not to the drive in the event of a failure. This would cause problems with AD synchronisation and for that reason we add a seond drive and disable caching on it so we can use it to host the AD database.

Before we create the new machine it’s a good idea to create a storage account. If we leave Azure to do it the account gets the usual random name. I prefer order and convention in these things, so I’ll create one myself.

storage 1

When you create a storage account, Azure now creates a container within it named vhds and it uses that to hold the virtual hard disks for your VMs.

We can now create a virtual machine using the VM Gallery.

new vm 1

The Virtual Machine creation wizard will appear and show the numerous VM templates we can start from. I want a Server 2012 R2 DC so I’m going to choose Windows Server 2012 R2 Datacenter from the list.

new vm 2

The next screen allows us to set the VM name. This is also used for the Azure Endpoint and must be unique within Azure. We can also choose a size for the VM from the available Azure VMs. This is a lab so I’m happy with a small VM. In production you would size the VM according to your AD.

We also need to provide a username and password that Azure will configure when it deploys the VM. We’ll use that to connect to the machine in order to join it to the domain.

new vm 3

The next screen asks for a whole bunch of information about where the new VM will be placed and what networks it will be connected to. The wizard does a pretty good job of selecting the right defaults for most settings.

I created two subnets in my virtual network so I could have an internal and external subnets. The DC shouldn’t have connections from outside our network so it’s going on subnet-1.

new vm 4

The final screen allows us to configure the ports that will be available through the Azure endpoints. If we remove these then we will only be able to connect to the new VM via our internal network. That’s exactly what I want, so I will click the big X at the right hand side of each endpoint to remove it.

new vm 5

When we click the final button Azure will show us that our new VM is provisioning.

new vm 6

Once the VM is running you can click on it to view the dashboard. You will see from mine that the new VM has no public IP address and that it has been give an internal IP address of 172.16.1.4 – on the Azure network I created earlier. The first server that you connect to a virtual network subnet in Azure will always get .4 as it’s address; the second gets .5, etc. An important point to note here is that if a virtual machine is deallocated (when you shut it down from the Azure portal it will do this) the DHCP-given IP address is released and another server could get that address. It’s important to be careful about the order you start machines in for this reason.

vm dash

 

I haven’t added a second hard disk to the VM, so that’s our next step. At the bottom of the dashboard there is an Attach button that allows us to add an empty disk to the VM.

attach disk 1

In the screen that appears we can give our new disk a name and size and, importantly, set the type of caching we want on the disk. As I mentioned, everything I have read and heard tells me that caching on the disk holding the AD database should be turned off.

new disk 1

Now we’ve got the second disk attached, the next step is to make an RDP connection to our new server. We can do that from one of the machines on our on-premise network just by entering the ip address of the Azure-hosted server into the Remote Connection dialog.

Remember to use the credentials you set when you created the VM: e.g. azureucdc\builduser

rdp connection 1

The first thing we need to do is bring the additional disk online, create a volume and assign a drive letter. I’ve used S for sysvol.

dc add disk

Next, we need to join the server to our AD domain, which will need a reboot. After that we can add the Active Directory Domain Services role in order to promote the server to be a domain controller. It’s important when doing this to set the paths for the AD databases to the second drive (S in my case)

azure dcpromo

Once we’ve got our new DC and DNS up and running, we should configure our Azure network so it knows the IP address of our new DNS and hands it to other servers in our network.

To do that we register the DNS with Azure first.

azure dns 2

Next we modify the configuration of our Azure virtual network to add the new DNS. The DNS addresses are handed out in the order they are specified in the Azure network, so I’ve removed the on-premise DNS then added first the one hosted in Azure and then the on-premise one.

azure dns 3

We now have a functioning Azure network with services that will support any other machines we host there even if the VPN link goes down.

We’ll need some more VMs for our other services to support our connected Azure ADFS. We’ll deal with those in part 3.

Building an Azure IaaS and on-premise hybrid environment Part 1: The plan and Azure Network Connection

I’ve been meaning to build a test lab to kick the tyres of Windows Azure Networks for a while. Two things combined together to make me get it done, however: First was the need to build exactly that for a customer as part of proof-of-concepts; the second was an invitation to present at Tech.Days Online on the subject.

I’ve built and rebuilt said lab a few times now. I am about to build it again in order to have a demo environment for Tech.Days and I though it would be a good opportunity to blog the steps involved.

I had planned this as one blog post, but it’s going to end up as a series of posts just because of sheer length. In this post I’m going to describe the environment and walk through creating the Azure network and connecting it to my on-premise network.

Constraints

Let’s get the big problem out of the way first: In order to do this you need a static, world-routable IP address. You have to have something at your end that will act as one end of a site-to-site VPN tunnel and that will only work if you have an IP that doesn’t randomly change.

The second issue is the bit of equipment you need to get that VPN working. The easiest is a Windows Server 2012 or 2012 R2 machine, or equipment from Juniper or Cisco which means you should be able to use one of the configuration scripts provided by Microsoft. After that, you’re on your own. I’ve already blogged about getting the connection working with a SonicWall. In theory, anything that supports IKEv2 connections can probably be made to work, but you’ll need to have a good understanding of the technology.

The third issue revolves around whether you are using trial subscriptions of things like Windows Azure and Office 365. I have an MSDN subscription to Azure, so it’s not going to vanish quickly, although I can burn through my MSDN credit quite quickly with this lab. If you are using a trial you need to be aware that you might hit problems. In this post I’m not going to touch Office 365, although I am going to get single sign-on working with Azure AD. The reason for that is I don’t want to connect my Azure AD to an Office 365 trial subscription that will vanish in a few short weeks.

What are we building?

I wanted to build a meaningful test of what Azure Networks could do for me. I turns out that it’s also something that interests a good many of my customers and colleagues in the industry:

  1. Create a Windows Azure virtual network and connect that to my on-premise network.
  2. Place a domain controller into the Azure network.
  3. Build a server in the Azure network to run Dirsync and push my domain users into Azure AD (step one of single sign-on for Office 365 as well)
  4. Build an ADFS server in the Azure network and connect it to Azure AD (step two of single-sign on for Office 365)
  5. Build an ADFS Proxy (or a Server 2012 Web Proxy) for internet-access to the federated sign-on mechanism (also needed for Office 365)

What aren’t we doing?

We’re not going to look at Azure Backup in this post. We already use Azure for backup at Black Marble as part of our DPM configuration. There is also a simpler backup client for Windows Server. I’ll  blog on those separately.

Why would we want to do this?

I have had many conversations about the practicality of moving virtualised servers from an on-premise environment into Azure. For many organisations this can work out cheaper that running their own tin. A hybird approach allows those VMs to me moved across over time and is important to enable testing.

Description of my rig

I am lucky in that I have a small number of static IP addresses through the internet provision at Black Marble. For my previous builds of this lab I added a USB network adapter to my laptop to connect to the outside world. For this build I am using a server hosted at Black Marble. Why? I need both ends of the lab to be running for my Tech.Days talks and it’s very hard to get a static world-routable IP at the event.

Very importantly, however, none of this lab will be connected to my main networks. I will create an internal Hyper-V network for the on-premise end of the lab and a second Hyper-V network that will connect to the outside world. The Hyper-V host will not be connected to any of these networks.

On my laptop I have Windows 8.1 and built all the VMs as Generation 2 virtual machines. My server, however, runs Server 2012 so the VMs are Generation 1. Does this matter? Not a bit, but I like the simplicity of the generation 2 virtual machines more than generation 1.

On-Premise VMs

For my on-premise network I have two virtual machines:

PremUCDC

Role: Domain Controller, DNS
OS: Windows Server 2012 R2
CPU: 2 core
RAM: Dynamic, min 512MB, max 2048MB
Disk: 120Gb Dynamic
Network: I adapter on internal network

Once the OS has been installed I will add the Active Directory Domain Services role and promote the server to be a domain controller.

For this lab I am using an internet-registered domain and I will use that as the AD domain suffix. This is an important point: If you create an AD forest with a .local suffix then you will have to jump through some more hoops to get single sign-on with Azure AD working.

PremUCRRAS

Role: Remote Access/VPN
OS: Windows Server 2012
CPU: 2 core
RAM: Dynamic, min 512MB, max 2048MB.
Networking: I adapter on internal network; I adapter on internet-facing network

I’ve tried Server 2012 R2 for the RRAS server a couple of times and I have not yet managed to get the VPN connection working, so this lab will use Server 2012.

I won’t add any roles to this server. Once I’ve configured my Azure network I will use the configuration script from Microsoft to add the necessary roles and configure the VPN link.

My on-premise network will use the 192.168.0.0 non-routable address space. I will then use 172.16.0.0 for my Azure network address space.

Azure Network

We need to create a new network in Azure to hold our VMs and we need to tell Azure what our on-premise network looks like, and what DNS servers we already have.

We start by creating a new Local Network in Windows Azure:

new internal network

We will be asked what to call the new network and we are also asked to provide the IP address of the machine at the on-premise end of the VPN tunnel.

internal network 1

Next, we are asked to specify what address spaces we have on our on-premise network. This is important as it will be used for routing traffic between Azure and our on-premise networks.

As I said earlier, my on-premise network uses the 192.168 address space. I configure the Azure local network as 192.168.0.0/16. I can still subnet that network down on-premise (and I will).

internal network 2

Now we’ve defined what our on-premise network looks like we need to register our DNS servers. We need to do this so that Azure can hand them out via DHCP and machines on the Azure network will then be able to communicate with our on-premise network systems.

new dns

Our on-premise network has a single DNS – PremUCDC, 192.168.1.1

new dns 2

Now we can define our Azure network

new internal network

First we give it a name, and we need to associate it with an affinity group.

azure network 1

Next, we associate the new network with the DNS server we added earlier

azure network 2

We know we want to connect our on premise network so next we select the Configure site-to-site VPN option. Azure will helpfully add the local network we configured earlier.

azure network 3

The next step is to define our address range and subnets on Azure. I’ve chosen to create 172.16.0.0/24 so I can subnet that down. I want two subnets – 172.16.1.0/24 and 172.16.2.0/24. I’ll add the gateway subnet in a moment.

azure network 4

The gateway subnet is that one that has the internal IP address of the VPN endpoint in Azure. I want that to be 172.16.254.0/24.

azure network 5

The network will take a little while to create. Once it’s done we need to create a Gateway that will provide our VPN connection.

The dashboard for the new network will look something like the image below and we can click the button at the bottom to create our gateway. There are two options for the gateway – static or dynamic routing. Four the lab I’m using dynamic routing.

gateway 1

Creating a gateway can take up to fifteen minutes so this is a good time for a coffee break.

Once the gateway is provisioned your dashboard will update to show you the IP address of the Azure end of the VPN and metrics for data in and out. I’ve removed the last two octets of my gateway address in the screenshot.

gateway 2

To bring up the connection to on-premise we need to configure our RRAS server. Conveniently, we can click the Download VPN Device Script link to grab some powershell to do that for us.

The VPN scripts are also available for a range of Cisco and Juniper devices. Simply select the appropriate options in the menus and download the script you need. You will need to edit the scripts to set a number of parameters before running them.

gateway 3

Before we make those script changes we need to know the shared secret that is used in the VPN handshaking. To find that, click the Manage Key button at the bottom of the dashboard.

The shared key will be displayed. Copy it to clipboard and save it somewhere.

gateway 4

Next, we need to edit the powershell script to add the parameters.

As a side note, why the guys at Microsoft didn’t put a variable block at the top of the script to make this easier I don’t know. Search and replace it is, then…

vpnscript 1

There are a number of edits we need to make:

  1. Replace <SP_AzureGatewayIpAddress> with the large IP address that’s on the Azure network dashboard. This applies to lines 75, 80, 81 and 87.
  2. Replace <SP_AzureVnetNetworkCIDR> with the Azure network address range (172.16.0.0/16 in my lab)
  3. Replace <SP_PresharedKey> with the key we access through Manage Key.

I usually leave line 87 commented out and run the command manually after the configuration is complete.

Copy that script onto the VM that’s going to be the RRAS server. I’m assuming that you’ve already joined it to the domain and configured the network adapters for internal and internet connections.

In order to run the script we will need to modify the execution policy on the server to allow unsigned scripts.

The command for this is set-executionpolicy unrestricted

Now run the powershell script to configure the VPN connection. The script will add the necessary roles to the server and configure the vpn connection.

vpnscript 2

Once the script is run, assuming you don’t need to restart the server it’s time to bring up the connection.

We need to enable the Azure gateway first by clicking the Connect button on the dashboard. Once that’s done, execute the last line of the powershell script (connect-s2svpninterface …).

We should be able to see the state of the connection from both the RRAS server and the Azure dashboard. On the RRAS server, open the Routing and Remote Access console.

The VPN is listed in Network Interfaces and the connection status should be Connected.

vpn state 1

The Azure Network dashboard should also show that the connection has been made.

vpn state 2

 

 

Next steps…

Now we’ve got our VPN connected the next step is to create a new VM on Azure, join it to our domain and promote it to be a DC and DNS server.

Once that’s done there are more VMs to create in order to configure single sign-on with Azure AD, which also needs to be configured to use the internet-registered DNS domain.

With the VMs in place we can configure directory synchronisation and then configure ADFS for single-sign on.

Each of these will be covered in later articles in this series.

Connecting Azure Network Site-Site VPN to a SonicWall Appliance

I am with a customer this week, building a test Azure Network+IaaS/Azure AD/Office 365 environment. We struggled to get the site-site VPN connection up for a while and there wasn’t a great deal on the greater internet to help, save for a couple of posts in a discussion forum by the marvellous Marcus Robinson. We finally got it working when we found a tech note from SonicWall, published just a few days ago on the 7th October.

It turns out that we had created a gateway on Azure that used dynamic routing (I had a working lab environment using Server 2012 RRAS done that way). In SonicWall terms, that is not a site-site VPN and as we had configured appliance for one of those were completely adrift. When we deleted the Azure gateway and created a static routing one everything worked.

For anyone embarking down this road with a SonicWall device I can report that when we followed the instructions everything appeared to connect just fine. The tech note is available on the SonicWall site for all to enjoy.

Speaking at UK Tech.Days Online 2013

I’ve been supporting the great team of evangelists at Microsoft with their UK Tech.Days events for some time now. I am chuffed to bits that they have asked me to contribute to the fantastic UK Tech.Days Online event. If you haven’t heard about it, go look at the agenda right now! Three days of great content on the latest technologies covering client, server, cloud and dev. The whole thing will be streamed live thanks to the wonder of the internet and includes a live interview with Steve Ballmer.

I am doing a session with the marvellous Steve Plank on the technologies that enable you to move your on-premises VMs into Azure and then a solo session on Windows Azure Backup – something we use already at BM as part of our DPM configuration. Sandwiched between those will be one where Steve covers the kind of automation you can achieve with PowerShell for Windows Azure.

Robert is also involved – I believe he is speaking during the very first session of day 1, on Windows 8.1.

It’s a privilege to be involved in Tech.Days Online and I’m really looking forward to it. Go register and I look forward to answering all your great questions on the day!