Setting up ADFS 2016

This is a guide I have put together to hopefully save others the amount of time I have put into getting this working after two iterations. The goal is rather simple, which is to get a highly available ADFS environment online with Server 2016. There is quite a lot of documentation already out there, but certain aspects of the design choices in this implementation were not well covered so this is to help bridge those gaps. I’ve converted much of this process to Powershell, so that it will work on Server 2016 core/nano, but it’s not 100% there. I plan to finish those pieces soon and provide an update when I have those finished.

Prerequisites

  • Active Directory: At least one domain controller running on Server 2012 or higher. Ideally all DC’s should be 2012 or higher.
  • ADFS: Minimum of 4 servers running Server 2016 ( 2 node ADFS Farm + 2 WAP nodes)
  • Domain Name: Decide on subdomain for ADFS. In the examples I will be using fs.jameysteinmann.com
  • SSL Certificate: An ssl certificate valid for the domain you will be using for ADFS as well as the certauth subdomain of that. for this example we’re using fs.jameysteinmann.com and certauth.fs.jameysteinmann.com. If you’re not using workplace-join, the certauth subdomain is not needed
  • Load Balancers: one to balance requests between the nodes in the adfs farm and another to balance requests to the WAP servers
  • DNS
    • Split DNS zone if ADFS is being exposed externally. The external DNS zone entries will point to the Load Balancer responsible for the WAP Servers and the internal DNS zone entries will point to the Load Balancer responsible for the ADFS Farm nodes.
    • DNS entries for your ADFS subdomain (fs.jameysteinmann.com as used in this article) and one for WorkPlace-Join with is certauth added to the subdomain you choose (certauth.fs.jameysteinmann.com)

Design

  • ADFS Farm: 2 Servers running Server 2016 utilizing the Windows Internal Database and joined to the domain
  • WAPs: 2 Servers that can either be left in a workgroup or joined to the domain, but if they are joined, just please be aware of the implications.
  • Group Managed Service Account for ADFS (This will be created when the first node of the ADFS farm is created)

Preparing For Setup

  1. Make sure all servers are up to date with the latest windows updates
  2. Install your SSL certificate on all ADFS and WAP servers
  3. Ensure, at a minimum, that the ADFS servers are joined to the domain
  4. Prepare AD for using gMSA
    1
    2
    3
    #Check if a KDS Root Key exists. If one does, then no need to run the step after this
    Get-KDSRootKey
    Add-KDSRootKey -EffectiveImmediately

    If you had to add a KDS Root Key, then it may take up to 10 hours in order to go into effect. If it is not replicated and ready, then creating any gMSA accounts will fail until it has completed.

  5. For DNS you’ll want to provision subdomains for the ADFS url you’re choosing. In the walkthrough below we’re using fs.jameysteinmann.com so you’ll want DNS records for both js.jameysteinmann.com and certauth.fs.jameysteinmann.com. If you’re not planning on using workplace-join then you can skip the certauth entry and it will just generate a warning when configuring ADFS.

Installing ADFS

Install The ADFS Feature

Run the following on each server that will act as an ADFS server.

1
Install-WindowsFeature adfs-federation –IncludeManagementTools

Configure The First ADFS Node

With the SSL certificate installed on all ADFS servers, retrieve the thumbprint of the certificate

1
Get-ChildItem –path Cert:\LocalMachine\My\ | Where-Object { $_.Subject -like "*jameysteinmann.com*" }| fl

This step will create the first node in the farm. The -OverwriteConfiguration is not necessary if this is done in a fresh environment, but I like to include it nonetheless. Since we’re using -GroupServiceAccountIdentifier, it will create the specified gMSA account in the Managed Service Accounts OU of the Active Directory Server and use it for running the service. You can replace the JAD\ADFSgmsa$ with anything you’d like so long as it has the $ attached at the end and references your AD domain name.

1
Install-AdfsFarm -GroupServiceAccountIdentifier JAD\ADFSgmsa$ -CertificateThumbprint B3CACC95FAF0D72111E092B53E890EC1C212BA47 –OverwriteConfiguration -FederationServiceName "fs.jameysteinmann.com" -FederationServiceDisplayName "My Organization"

After the node has been successfully created, we will move on to changing the default configuration before moving on to adding the other nodes. This is to avoid having to restart the ADFS services on each node once the changes have been made.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Add user agents to support Chrome/Firefox.
Set-AdfsProperties -WIASupportedUserAgents @("MSAuthHost/1.0/In-Domain","MSIE 6.0","MSIE 7.0","MSIE 8.0","MSIE 9.0","MSIE 10.0","Trident/7.0","MSIPC","Windows Rights Management Client","MS_WorkFoldersClient","=~Windows\s*NT.*Edge","Mozilla/5.0")
#Set Privacy Policy and Main website links in the ADFS login portal
Set-AdfsGlobalWebContent -PrivacyLink https://www.jameysteinmann.com/privacy-policy/ -PrivacyLinkText 'Privacy Policy'
Set-AdfsGlobalWebContent -HomeLink https://www.jameysteinmann.com -HomeLinkText Home
#Set the logo to be used.
Set-AdfsWebTheme -TargetName default -Logo @{path="C:\logos\My Logo 350x260.png"}
#These two lines allow password changes to be done via the ADFS, this is not for Password Resets as that is unsupported
Enable-AdfsEndpoint "/adfs/portal/updatepassword/"
Set-AdfsEndpoint "/adfs/portal/updatepassword/" -Proxy:$true
#Enable WS-Trust 1.3 which is supported in Office 2013/2016/365
Enable-AdfsEndpoint -TargetAddressPath "/adfs/services/trust/13/windowstransport"
#Set ADFS lockouth threshold to match or be slightly more restrictive than AD lockout policy to prevent the AD accounts from being locked out via ADFS
Set-AdfsProperties -EnableExtranetLockout:$true -ExtranetLockoutThreshold 5 -ExtranetObservationWindow (New-TimeSpan -Minutes 30) -ExtranetLockoutRequirePDC $false
Restart-Service AdfsSrv –Force

Fixing the gMSA

This was a huge pain point for me in the ADFS setup. For whatever reason, the first node you create is happy with how the gMSA account is setup, but it can cause adding any other nodes to fail since it doesn’t seem to add the correct permissions for accessing the gMSA’s managed password. I received many errors depending on if you did the setup of the second node via GUI or Powershell. The former ran through all prerequisite test cases and generated many errors, while powershell only ran one and failed there. None of the errors about “username or password incorrect” or “There were no SPNs set on the following service account…” pointed me in the right direction. If this is the case for you, here is how we validate the issue.

First let’s verify all the required SPNs were created when we installed the first node.

1
2
3
4
PS C:\Windows\system32> setspn -L ADFSgmsa
Registered ServicePrincipalNames for CN=ADFSgmsa,CN=Managed Service Accounts,DC=local,DC=jameysteinmann,DC=com:
HTTP/fs.jameysteinmann.com
host/fs.jameysteinmann.com

Next we want to make sure The ADFS servers and the user account you’re using to install the subsequent nodes have permission to use the gMSA account and retrieve it’s password. This was the cause of the dreaded issues above in that the user account I was using to install the additional nodes was not allowed to retrieve the password.

Let’s see who is authorized currently:

1
2
3
4
PS C:\Windows\system32> Get-ADServiceAccount ADFSgMSA -Properties * | Select-Object Name,PrincipalsAllowedToRetrieveManagedPassword|fl

Name : ADFSAdmin
PrincipalsAllowedToRetrieveManagedPassword : {CN=ADFS01,OU=Servers,DC=local,DC=jameysteinmann,DC=com}

Now let’s add the missing accounts

1
2
3
4
5
6
7
8
9
10
11
12
13
#get existing Principals
$adfsgmsa = Get-ADServiceAccount ADFSgMSA -Properties PrincipalsAllowedToRetrieveManagedPassword
#get DNs for other principals we're adding to the gMSA
$principals = @(
((Get-ADUser MyAdminUser).DistinguishedName),
((Get-ADComputer ADFS02).DistinguishedName)
)
#add new the two arrays
$principals+=$adfsgmsa.PrincipalsAllowedToRetrieveManagedPassword
#set the ad service account to use all principals
Set-ADServiceAccount -Identity 'adfsgmsa' -PrincipalsAllowedToRetrieveManagedPassword $principals
#verify the changes (this might take a while to go into effect)
Get-ADServiceAccount ADFSgMSA -Properties PrincipalsAllowedToRetrieveManagedPassword

This may take some time to replicate, but once it’s in place we should have no issues adding the second node.

Configure the Second ADFS Node

Before we configure the second node on the farm, let’s run one last test to verify everything should go smoothly

1
2
3
4
5
6
7
8
9
Test-AdfsFarmInstallation -GroupServiceAccountIdentifier JAD\adfsgmsa$ -FederationServiceName fs.jameysteinmann.com

Message                                                                                                                                                            Context                  Status
-------                                                                                                                                                                 -------                     ------
Successfully verified the target computer is joined to a domain.                                                         PreCheckTest       Success
Successfully validated the port settings.                                                                                                    PrerequisiteTest  Success
Successfully verified the user is a member of Domain Admins of the target machine's domain. PrerequisiteTest  Success
KDS key requirements were validated.                                                                                                      PrerequisiteTest  Success
group Managed Service Account was validated.                                                                                      PrerequisiteTest  Success

With all the tests passing, like installing the first node, adding the second node is a straight forward single command.

1
Add-AdfsFarmNode -PrimaryComputerName "adfs01.local.jameysteinmann.com" -GroupServiceAccountIdentifier JAD\ADFSgMSA$ -CertificateThumbprint B3CACC95FAF0D72111E092B53E890EC1C212BA47 -OverwriteConfiguration

At this point we have a 2 node ADFS farm up and running. We can test the sign in functionality via the IdpInitiatedSignon page. This is disabled by default but is rather simply turned on.

1
2
Set-AdfsProperties -EnableIdPInitiatedSignonPage $true
Get-AdfsProperties | Select-Object EnableIdpInitiatedSignonpage

Once it is enabled, visit your ADFS IdpInitiatedSignonpage: https://fs.jameysteinmann.com/adfs/ls/idpinitiatedsignon.aspx and you should be able to sign in and out.

Wrapping up with WAPs

For the ADFS Proxy servers, two steps are all that’s needed since the SSL certificate should already be installed on the server.

1
2
3
4
#Install the WAP feature
Install-WindowsFeature Web-Application-Proxy
#Configure the WAP for the ADFS Farm
Install-WebApplicationProxy -CertificateThumbprint 'B3CACC95FAF0D72111E092B53E890EC1C212BA47' -FederationServiceName fs.jameysteinmann.com

That’s it. At this point you should be able to access the ADFS internally via the Load Balancer for the ADFS farm and externally via the Load Balancer for the WAPs.

Leave a Reply

Your email address will not be published. Required fields are marked *