Part 2: Using Azure to remove to HQ dependency for AD

Part 1: The Sceanario

Part 2: The Azure Solution

Part 3: Virtual Networks (coming soon)

Proposed Solution

After sitting down and scoping the needs and requirements.  The below is the design that is now being built. In following posts I will discuss how to create those changes and why we used the options that we did.

In comparison to the initial image, you can see that we have moved key services (ADFS and ADFS Proxies (WAP) away from Azure Classic and into Azure Resource Manager. These are not rebuilds but instead we used MigAz to move the boxes from the old environment to ARM with minimal downtime.

A new subnet within our production vNet will host the Domain Controllers and the ADFS servers, the ADFS servers will sit behind a internal load balancer. WAP boxes will sit within the DMZ behind a External Load Balancer.

Both vNets are protected via Network Security Groups (NSG) and the VM’s themselves will also have individual NSG’s assigned to the network cards. This will limit the attack vector should someone breach another machine within the same Subnet.

vNet peering is enabled between the Azure Service Manager environment and Resource Manager. This keeps the traffic within the Azure data plane and means that we are not relaying through the HQ.

S2S VPN tunnels will be created from remote sites directly to Azure. Using Site costs within Active Directory Sites and Services, we will be able to force the majority of the traffic back to HQ, using Azure as the fall back for authentication traffic.

DNS servers currently point to HQ. This will remain the same, however tertiary and quaternary DNS servers will be added to DHCP scopes and statically assigned servers, meaning they will round robin between all 4.

 

 

 

Part 1: Using Azure to remove to HQ dependency for AD

Scenario

Currently HQ is a single point of failure, this is the only site within the network to host Domain Controllers. These are responsible for authentication to Office 365, external applications that are served via Azure AD, and all of the Users and Computers within the company. This has been highlighted twice in the past few months, during which time HQ experience an internet outage, and a separate incident where the ASM VPN went down.

During these times, users are unable to authenticate with cloud apps, including Outlook, Onedrive and Sharepoint. Users in the remote offices also connect back across Site to Site VPNs for authentication to file shares and applications. The network grounded to an halt.

Current Setup

From the diagram below, the red line indicates the way end points connect back to HQ to authenticate. As you can see from the image, all traffic heads back to HQ from both Azure VPN environments. ADFS servers currently site in ASM and are dependent on the ASM VPN tunnel remaining up.

The network sits in a Hub/Spoke topology where all traffic between remote sites will traverse through the HQ. MPLS and ultimately ExpressRoute was deemed too expensive.

To Note: The Azure portal also uses ADFS for authentication so could lose our login ability to Azure aswell.

Find when VM was created in Azure Resource Manager

Recently I was asked how to confirm when a particular ARM Virtual machine was created. I thought this would be a relatively easy thing to accomplish. However searching through powershell I could not find any Datecreated on either the VM or the VHD.

in the end I resorted to going into the Windows VM (this will not work on Linux). And checking the location: C:\Windows\panther\

In here you should find a number of files but the ones we are interested in are: WaSetup.log and WaSetup.xml – The dates modified of these files will be from during the provisioning of the Image / VHD.

This was the closest I could find to given a true Date and time.

 

Find Stale AD Computers

Active directory can often be neglected and orphaned computer objects can get out of control. The below script will query your domain (remember to provide your FQDN in the variable at the top) for computers that have not spoken on the domain for 90 days.

By default, Active directory looks to change computer object passwords every 30 days. If you have a large mobile workforce that may not be connecting into the network for a long period of time, you may way to extend this. I find that 90 days works well for us.

NOTE: Be careful when using this on environments that have clusters. SQL Clusters for example, have a AD joined computer object for the name of the cluster. This does not update its lastlogonstamp and therefore gets caught by this script.

import-module activedirectory  
$domain = "domain.local"  
$DaysInactive = 90  
$time = (Get-Date).Adddays(-($DaysInactive)) 
  
# Get all AD computers with lastLogonTimestamp less than our time 
Get-ADComputer -Filter {LastLogonTimeStamp -lt $time} -Properties LastLogonTimeStamp | 
  
# Output hostname and lastLogonTimestamp into CSV 
select-object Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} | export-csv c:\source\OLD_Computer.csv -notypeinformation

 

Active Directory Sites – Powershell Site Links

My current client has asked me to look at tidying up their Active Directory, they have 3 environments that all should look identical but as with everything, time permits and changes can skip a environment.

Due to their sector, sites are constantly opening and closing, at any one time they can have over 70 sites. The previous fix to this was to push all the subnets into a single AD replication site and this connect back to the head office (where their domain controllers sit). After having Microsoft in for the day to go over a number of things, Microsoft advised that all sites should be separated as per best practice terms..

Our SCCM boundaries are also based off these Sites, so removing them is not a option.

I spoke to the networks team and got a list of all the subnets and their corresponding sites and started to build each site/subnet/AD site link. It wasn’t long before I wanted to pull my hair out! So i scrapped the manual creation and put together the script below. I have also included the part where I can pull out the information to a CSV that I can then take to the next environment and run to build. This way, i build the environment once in a offline area. and the import across the other environments.

# Run this on server to pull out records - then remove all quotations from CSV
# Get-ADReplicationSiteLink -filter * | Select Name | export-csv C:\source\ADsites.csv -notypeinformation

$Sites = get-content C:\source\Input\ADsites.csv
Foreach ($Site in $Sites) {
New-ADReplicationSite -Name $site -Description "Imported via Script"
}
$sitelinks = Get-ADReplicationSite -filter * 
ForEach ($sitelink in $sitelinks) {
New-ADReplicationSiteLink -Name $sitelink.Name -SitesIncluded $sitelink,10-Eaton-Court -Cost 100 -ReplicationFrequencyInMinutes 30 -InterSiteTransportProtocol IP
}

# Run this on server to pull out all Subnets and sites - then clean down CN= information either side of the site name
# Be careful of subnets specfic to Dev/UAT environment
# Get-ADReplicationSubnet -filter * | Select Name, Site | export-csv C:\source\ADSubnets.csv -notypeinformation

Import-csv C:\Source\Input\ADSubnets.csv | ForEach-Object{New-ADReplicationSubnet -Site $_.Site -Name $_.Subnet}

Find and Disable Empty GPO Sections

The below script can be used to go query your GPO’s and find empty sections (computer or user), and disable them. This improves the speed of processing GPOs as machines will not look to disabled sections.

This was a recommendation from Microsoft during a recent RAP as a service that I consulted on.

Get-gpo -all | foreach {


    [xml]$GPOAsXML = Get-GPOReport -Guid (Get-GPO -Name $_.DisplayName).Id -ReportType Xml

    If(($GPOAsXML.DocumentElement.Computer.Enabled -eq $true) -and ($GPOAsXML.DocumentElement.Computer.InnerText.Length -eq 6))
    {
        (Get-GPO -Name $_.DisplayName).gpostatus = "ComputerSettingsDisabled"
        $_.DisplayName.ToString().PadRight(60) + " Computer section now disabled!"
        
    }
   
    If(($GPOAsXML.DocumentElement.User.Enabled -eq $true) -and ($GPOAsXML.DocumentElement.User.InnerText.Length -eq 6))
    {
        (Get-GPO -Name $_.DisplayName).gpostatus = "UserSettingsDisabled"
        $_.DisplayName.ToString().PadRight(60) + " User section now disabled!"
    }
   
}

Find unlinked GPO and remove via Powershell

Working on RAP as a service in the past few weeks I have worked with Microsoft to clean up Group Polices. Below are a few of the scripts that were used and their purpose.

Find Unlinked GPOs and export to a CSV:

Import-Module GroupPolicy
function IsNotLinked($xmldata){ 
    If ($xmldata.GPO.LinksTo -eq $null) { 
        Return $true 
    } 
     
    Return $false 
} 
 
$unlinkedGPOs = @() 
 
Get-GPO -All | ForEach { $gpo = $_ ; $_ | Get-GPOReport -ReportType xml | ForEach { If(IsNotLinked([xml]$_)){$unlinkedGPOs += $gpo} }} 
 
If ($unlinkedGPOs.Count -eq 0) { 
    "No Unlinked GPO's Found" 
} 
Else{ 
    $unlinkedGPOs | Select DisplayName,ID | export-csv c:\Source\output\unlinked.csv -NoTypeInformation
}

I like to export to a CSV to clarify exactly what I am removing. Now to remove:

Import-csv C:\Source\Output\unlinked.csv | ForEach-Object {Remove-GPO -guid $_.id}