F5 – KCD – AAD – B2B
In my last post I gave you a script that allows the automatic creation of B2B users in your local AD to enable you to publish (on-premises) Kerberos applications using Constraint Delegation. In this post, we will enable an F5 to use this setup to actually publish the application, in case you don’t want to use the Azure AD App Proxy.
Architecture/setup
So to give an overview, the architecture first:
We have a single forest/domain, FORESTROOT.local. To create the connection to the Azure AD tenant, an Azure AD Connect server copies the corporate users OU to AAD. Another server runs the B2B creation script (but this can also be the Microsoft supported MIM implementation). The B2B users are created in another OU called external users (which is excluded from Azure AD Connect).
Next, the infrastructure setup with regards to F5:
F5 publishes the backend AP02.forestroot.net website. The website is running on a webserver that has an SPN registered in AD on the computer object (or Service Account). Internal users should be able to login to the website (https://ap02.forestroot.net) using Kerberos automatically.
The F5 is configured with an External IDP and a local SP. Both are based on the information in Azure AD on the created application in there.
In Active Directory there are 3 types of users, first there is the corporate user that uses a UPN from the forest (in my case azureinfra.com) and a regular sAMAccountName in the format FORESTROOT\user.
The B2B user is created by the earlier mentioned script, and uses guest_domain#EXT#@forestroot.onmicrosoft.com as the UPN (which is derived from the AAD object UPN) and the script automatically generates a sAMAccountName.
Finally, an F5 apm user is added for the F5 integration to allow the unit to perform Kerberos Impersonation, as well as LDAP lookups. To enable Impersonation, the delegation for this account is set to “specific services – HTTP/ap02.forestroot.net – using any protocol”
The configuration in AAD
Prior to configuring F5, we need to know what the F5 logic
needs to do. For this we need to find out how we will authenticate / find the
users. The “easy” way to authenticate corporate users, is to send the sAMAccountName
in the claim from AAD which is represented in the attribute:
user.onpremisessamaccountname
However, the B2B users do not have this attribute, as their accounts aren’t synchronized to AAD. So, while the default F5/AAD guide recommends using this attribute (in combination with user.netbiosname), we cannot use this attribute in this scenario.
So, we are back to my previous F5 configuration, where we take the UPN for the user, convert it into the sAMAccountName and perform the Impersonation (authentication) based on that. Ideally we would use the user.UserPrincipalName attribute, however when a B2B user logs in, this attribute will actually reflect the actual UPN of the user (like user@otherdomain.com) , not the UPN stored in your AAD (user_otherdomain#EXT#@yourAAD.onmicrosoft.com) in order to grab that one, we will need to use the following attribute: user.localuserprincipalname To do this, we will add another claim into the Application in AAD, in my example I called it ActualUPN, but a value like localuserprincipalname would probably be better:
The user.localuserprincipalname attribute will be set to the actual UPN for your users, and the B2B specific UPN for B2B users. Next, we need to also send the NETBIOS/DNS domain name for users trying to authenticate. In the earlier F5 guides I wrote, I fixed the value in the App Policy but it’s better to have it as a variable coming from the claim, as this allows multiple forests/domains to make use of this setup. I called it the ReferralDomain
And set multiple conditions to the value of this attribute:
For this we use claim conditions in the AAD app. By adding the Any – attribute – user.dnsdomainname first, it will try to add the user.dnsdomainname to users getting their claim. Given B2B users do not have this setting we can add a fixed value for the AAD Guests. As the script will copy all B2B guests to only 1 domain (and OU), this setting now supports multiple domains for users and a single domain for all B2B guests accounts. If you only have 1 domain, obviously you could set it as a static value for all.
F5 Logic
So, now that in F5 we receive the localuserprincipalname (as ActualUPN) as well as the ReferralDomain we can kick in our logic. Given F5 doesn’t allow you to run a UPN authentication against a single forest (how would it be able to find yourAADdomain.onmicrosoft.com anyway?), we need to convert the UPN to a sAMAccountName in AD to be used for the Kerberos SSO.
In multi-domain scenario’s the LDAP lookup needs to be against a DC of each domain, the Access Policy therefore needs to be able to make choices based on the ReferralDomain and have multiple lookups available – this would have to be an iRule implementation.
So, in our access policy we first perform the SAML authentication and after authentication we will have the ActualUPN and ReferralDomain attributes in the following variables:
session.saml.last.attr.name.ActualUPN
session.saml.last.attr.name.ReferralDomain
Using these variables, we can perform an AD Lookup (userPrincipalName=%{session.saml.last.attr.name.ActualUPN}) – retrieving sAMAccountName is enough for us:
After that lookup has been done, the session variable session.ad.last.attr.sAMAccountName and session.saml.last.attr.name.ReferralDomain is all we need in the Kerberos configuration.