This post is part of a series, for the series contents see:
For the code listed in this post please see:
Breaking down the high-level diagram and eating the elephant in small bites I’ll build up the hub first of all:
The red crosses indicate pieces of the build that will be picked up later:
- Logs Storage Account – I’ll implement this when setting up diagnostics.
- Backups Storage Account – Surprisingly, this will be sorted out when I setup backups.
- UDR – I’ll setup user defined routing once I have implemented vnet peering and a firewall.
- NSG – I’ll probably tackle network security groups last to mop up any security holes that remain.
On top of the omissions above I’ve already found my first mistake in the high-level design. My point-to-site VPN client address pool stupidly overlaps with the hub vnet range, when it needs to be separate, so I’ve changed that to be 10.3.1.0/28.
First up I’ll build up the resource group and the network:
#Login to Azure and resource manager Add-AzureAccount Login-AzureRmAccount #Just in case you have multiple subscriptions check which one you're working in Get-AzureSubscription #If you need to select your test subscription use: #Set-AzureSubscription -SubscriptionName <name> #Build up the hub #First the resource group $RGName = "hub-rg" $Location = "North Europe" New-AzureRmResourceGroup -Name $RGName -Location $Location #Now the hub network New-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name hub-vnet ` -AddressPrefix 10.1.0.0/16 -Location $Location $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name hub-vnet Add-AzureRmVirtualNetworkSubnetConfig -Name mgmt-subnet ` -VirtualNetwork $vnet -AddressPrefix 10.1.1.0/24 #Annoyling the gateway subnet has to be called GatewaySubnet, ruining my naming convention! Add-AzureRmVirtualNetworkSubnetConfig -Name GatewaySubnet ` -VirtualNetwork $vnet -AddressPrefix 10.1.2.0/28 Set-AzureRmVirtualNetwork -VirtualNetwork $vnet
Next I’ll setup a point-to-site VPN which, as I’m not exposing any of the VMs with a public IP, will be how I manage everything from my machine.
Because I’m cheap the VPN will be setup using self-signed certs which I’ll create following these useful steps from Microsoft.
#Create Point-to-Site VPN #Set basic variables for our VPN gateway $GWName = "hub-gw" $GWIPName = "hub-gw-pip" $GWIPconfName = "hub-gw-conf" $VPNClientAddressPool = "10.3.1.0/28" #Get the VPN gateway subnet details. First you need to get the recently set vnet details again $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name hub-vnet $GWsubnet = Get-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet #Public IP for the VPN gateway $GWPIP = New-AzureRmPublicIpAddress -Name $GWIPName -ResourceGroupName $RGName -Location $Location -AllocationMethod Dynamic #Create the VPN gateway config $GWIPConfig = New-AzureRmVirtualNetworkGatewayIpConfig -Name $GWIPconfName -SubnetId $GWsubnet.Id -PublicIpAddressId $GWPIP.Id #Finally create the VPN Gateway #This takes ages to run! $GW = New-AzureRmVirtualNetworkGateway -Location $Location -Name $GWName -ResourceGroupName $RGName ` -GatewayType Vpn -IpConfigurations $GWIPConfig -VpnType RouteBased ` -EnableBgp $false -GatewaySku Standard #Now set extra VPN gateway settings Set-AzureRmVirtualNetworkGatewayVpnClientConfig -VirtualNetworkGateway $GW -VpnClientAddressPool $VPNClientAddressPool #Create the self-signed root and client cert using the guide below: #https://azure.microsoft.com/en-gb/documentation/articles/vpn-gateway-certificates-point-to-site/ #Get the cert imported into Azure (substitute your own path/name) $P2SRootCertName = "AzureLabP2SRootCert.cer" $FilePathForCert = "C:\SSL\AzureLabP2SRootCert.cer" $Cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2($FilePathForCert) $CertBase64 = [system.convert]::ToBase64String($Cert.RawData) $P2SRootCert = Add-AzureRmVpnClientRootCertificate -VpnClientRootCertificateName $P2SRootCertName -PublicCertData $CertBase64 -VirtualNetworkGatewayName $GW.Name -ResourceGroupName $RGName #Finally get URL for VPN client $PackageUrl = Get-AzureRmVpnClientPackage -ResourceGroupName $RGName -VirtualNetworkGatewayName $GW.Name -ProcessorArchitecture Amd64 #Display the URL path and download the .exe from here $PackageUrl
Finally, I want to build up my management VM which will be a Windows Server 2016 box, for no better reason than it’s new and I want to play around with it 🙂
Since I’ll be building up a few VMs for this lab it’s a good opportunity to use Azure Key Vault to store a default password for provisioning.
#Create an Azure Key Vault New-AzureRmKeyVault -VaultName lab-vault -ResourceGroupName $RGName -Location $Location #Add a secret (password) to that vault #The secret (password) has to be in a secure string format so you'll need to covert it first #Convert to secure string $Password = ConvertTo-SecureString -String '<your_password>' -AsPlainText -Force #Add the password as a secret Set-AzureKeyVaultSecret -VaultName 'lab-vault' -Name 'ProvisionPassword' -SecretValue $Password
It’s all very well that I’ve setup my Azure Key Vault and stored a password there for VM provisioning, but how do I access it?
Digging around the various blog posts and Microsoft docs on using Key Vault I found that nearly everything was geared towards two use cases:
- ARM Templates
- App passwords for Azure Applications
Neither of those was any use to me so I should probably take the hint that those are the correct use cases, but I indulged myself and got the value out of the vault and into a PSCredential object with:
#First setup default credentials to use in provisioning by retrieving and decrypting our Key Vault password $Username = "adminuser" $SecurePwd = Get-AzureKeyVaultSecret -VaultName 'lab-vault' -Name 'ProvisionPassword' $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePwd.SecretValue
It was as simple as getting the secret and then accessing the .SecretValue parameter which, conveniently, is in the secure string format that a PSCredential password needs. Admittedly, I did stumble at first by getting the .SecretValueText parameter instead!
That means we have everything needed to build up my management VM:
#Create a hub storage account which we'll use for VM storage New-AzureRmStorageAccount -ResourceGroupName $RGName -AccountName "hubvmstr" -Location $Location -Type "Standard_LRS" #Define Management VM basics $VMName = "mgmt-vm" $VMSize = "Standard_A1" $OSDiskName = $VMName + "OSDisk" $StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -Name hubvmstr $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name hub-vnet #Define Management VM network details #This will statically assign an IP to the VM. 10.1.1.4 is the next IP available as .0-3 are reserved by Azure $NIC1 = New-AzureRmNetworkInterface -Name "mgmt-vm-eth0" -ResourceGroupName $RGName -Location $Location -SubnetId $vnet.Subnets.Id -PrivateIpAddress 10.1.1.4 Set-AzureRmNetworkInterface -NetworkInterface $NIC1 #Define the Management VM config $VirtualMachine = New-AzureRmVMConfig -VMName $VMName -VMSize $VMSize $VirtualMachine = Set-AzureRmVMOperatingSystem -VM $VirtualMachine -ComputerName $VMName -Windows -Credential $Credential $VirtualMachine = Set-AzureRmVMSourceImage -VM $VirtualMachine -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Skus "Windows-Server-Technical-Preview" -Version "latest" $VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $NIC1.Id $OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd" $VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage #Create the Management VM New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VirtualMachine