Cross Domain Trust between IDM and AD

Cross Domain Trust between IDM and AD
IDM and AD happily coexisting

It could be simply because I have many more years managing Active Directory than I do working with RHIDM (Red Hat ID Management, our equivalent product), but I find that AD is a lot easier to set up and use than IDM. However, an increasingly common deployment scheme I'm seeing with my customers is using IDM with a cross domain trust to AD. Common enough that I finally decided to bite the bullet and learn how to set it up and use in my lab. Maybe I'm just a glutton for punishment...

Theoretically, setting up a cross domain trust between two domains shouldn't be too complicated (famous last words). At the end of the day, any "domain" solution is going to be a combination of LDAP (Lightweight Domain Authentication Protocol) and Kerberos. Both of which have dependencies on DNS (It's always DNS). Me personally? I prefer to have a single authoritative DNS source for my entire network, in my case it's dnsmasq running on my OPNsense server which creates some additional "fun".

The Basics

Up until now, I've been happily using Active Directory as the only authentication source in my lab with a single domain - *.cudanet.org, with the NETBIOS name CUDANET. Thus, accounts would log in to Windows servers as eg; cudanet\rcuda or assuming I've set the default domain, just rcuda. Simple, easy to manage and not overly complicated. This should be a no-brainer, but figuring out the root domains for my tandem AD and IDM environments was the first major hurdle I ran into. The two domains can exist side by side, but at a minimum they must not share any common names, eg; they cannot both control *.cudanet.org so the first thing I had to do was decide what to call my two domains. I settled on the two

ad.cudanet.org
idm.cudanet.org

Now, when you set up your domains, they cannot share a common NETBIOS name either, which immediately caused me some heartburn. It's really not a huge deal since this value is arbitrary, but considering the fact that I have been using cudanet\rcuda to log in to my servers for years, this change immediately broke a lot of things for me, not the least of which being the Remote Desktop Client.

I set up the two new domains with the NETBIOS names idm and ad respectively. Thankfully, on Linux servers this doesn't matter. You either authenticate with your uid or your kerberosPrincipal (eg; rcuda or rcuda@id.cudanet.org) depending on how the given client is configured. I'm lazy, so I prefer just using my uid and setting the default domain so account FQDN is not required.

Deploying Active Directory

I don't intend to make this an exhaustive tutorial on how to deploy an AD domain, but there are essentially two methods for spinning up a couple of domain controllers. My domain controllers are Windows Serve 2022. As a "best practice" (keeping in mind that this is a home lab), I always deploy my auth source with a primary and a secondary and I make sure that they run on separate hosts so that in theory, there's always at least one domain controller up ensuring continuity unless the power goes out, but then I have bigger problems. The same goes for my IDM servers, but we'll dive into that in a bit.

The two methods for deploying a domain controller both consist of first, installing the Active Directory Domain Services role to the server, and then configuring the server as a domain controller. If you're using Server Core (no GUI) you'll be working with Powershell. If you're using Server Desktop Experience, you'll use the Server Manager app (click-ops).

Regardless of whether you're using Server Core or Desktop, Active directory requires a static IP address and for your primary DC, your primary DNS server should be set to 127.0.0.1 (localhost). For any replica DCs, the primary DNS server would be set to the static IP of your primary DC.

It goes without saying, but your domain controllers need unique hostnames (duh). For servers, whether physical or virtual, I go with a four letter and two digit naming convetion, eg; ADDC01 (active directory domain controller 1), etc. You can use whatever you like. I've seen people use names of characters shows, ship names from Sci Fi movies, whatever works. Just make sure you know how to identify which server is which and they all have unique names.

Also, time MUST be synced between all of your domain controllers. Regardless of whether you're using Core or Desktop, I find it's easiest to configure most of these settings using the SCONFIG.EXE command. For the non-Windows oriented people out there, SCONFIG (server configuration) is a one stop shop for most of the things you'll need to do to set up a basic Windows server. It's a text based UI for managing servers.

Powershell Method

After doing the basic configuration on your soon to be domain controller, log in as a local administrator and from a powershell prompt (not CMD.EXE) run the following commands to install the Active Directory Domain Services role

Install-WindowsFeature -name AD-Domain-Services -IncludeManagementTools

Then create an answer.txt file with the necessary values for your new domain, eg;

[DCINSTALL]
InstallDNS=yes
NewDomain=forest
NewDomainDNSName=ad.cudanet.org
DomainNetBiosName=ad
SiteName=Default-First-Site-Name
ReplicaOrNewDomain=domain
ForestLevel=3
DomainLevel=3
DatabasePath=%systemroot%\NTDS
LogPath=%systemroot%\NTDS
RebootOnCompletion=yes
SYSVOLPath=%systemroot%\SYSVOL
SafeModeAdminPassword=<your-super-secret-password>

then run the command

dcpromo /answer:answer.txt

Your server will reboot after a few minutes and you will have a functioning new Active Directory domain.

Now let's set up a secondary DC. The process is more or less the same as setting up the primary, but again - there are a few requirements:

  • the primary DNS server of your secondary must be set to the primary DC
  • you must have a static IP address
  • you must have a unique hostname
  • time must be synced between the two DCs
  • you must domain join the secondary DC to the new domain

Domain joining can be done using option 1 in sconfig.

Once you've configured your secondary domain controller candidate, install the AD role to the server using Powershell just like you did on the primary and then run dcpromo using an answer.txt file like this

[DCINSTALL]
UserName=administrator
UserDomain=AD
Password=<your-super-secret-password>
SiteName=Default-First-Site-Name
ReplicaOrNewDomain=replica
ReplicaDomainDNSName=ad.cudanet.org
DatabasePath=%systemroom%\NTDS
LogPath=%systemroot%\NTDS
SYSVOLPath=%systemroot%\SYSVOL
InstallDNS=yes
ConfirmGC=yes
SafeModeAdminPassword=<your-super-secret-password>
RebootOnCompletion=yes

eg;

dcpromo /answer:answer.txt

The server will reboot and you will have a functioning secondary domain controller.

Click-Ops Method

On a Windows Desktop Experience server, or a domain joined Windows client with RSAT and the Server Manager app installed, you can promote a domain controller like this.

First, open the server app and go to 'add roles or features'

click through the prompts until you get to the 'Roles' menu and check the 'Active Directory Domain Servers' and click next

Click through the rest of the prompts and the AD role will be installed to your server. After which point you will be prompted to promote the server to a domain controller.

for the primary domain controller, select 'Add a new forest'. For a secondary DC, select 'add domain controller to existing forest'. Specify you root domain, eg;

Specify a password here. This is required if you ever need to recover your domain controller(s)

Specify a NETBIOS name

Then just click through the prompts until the 'Install' button is no longer grayed out. Just click install, your new DC will reboot and you will have a functioning domain controller.

Creating AD Users

You can either create and manage AD Users from Powershell, or you can do it using the Active Directory Users and Computers management console. Here's my quick and dirty example of creating my user account on AD, giving myself Domain Admin rights and disabling password expiration (it's my lab... I don't want to deal with the headache of password rotation).

Powershell

New-ADUser -Name "Ryan Cuda" -GivenName "Ryan" -Surname "Cuda" -SamAccountName "rcuda" -UserPrincipalName "rcuda@ad.cudanet.org" -Path "CN=Users,DC=AD,DC=CUDANET,DC=ORG" -AccountPassword(Read-Host -AsSecureString "Input Password") -Enabled $true

Set-ADUser rcuda -PasswordNeverExpires $TRUE

Add-ADGroupMember -Identity "Domain Admins" -Members rcuda
💡
You definitely do not want to create accounts with the same name in both AD and IDM, so plan ahead. My rcuda account actually resides in IDM, I just used it as an example.

ADUC

Open Active Directory Users and Computers. In the 'Users' folder (or whatever folder/OU you want to put your account in) right click and select 'Create new user'. Just fill out the fields as you'd like

Depending on your security requirements, configure the user password accordingly. For things like service accounts, you'll want to make sure that the account is not locked, they're not required to change their password on first log-on and the password does not expire.

Then you can assign group membership my right clicking your new user and selecting 'Add to a group...'

Search for the group name you want to add your user to and click 'OK'

Keep in mind, you'll probably want to create groups with specific permissions, especially for things like service accounts that should have very limited scope as to what they can be used for. But I'm not trying to write a thesis on best practices for role based access control here, I'm just showing you how to get up and running with AD as quickly as possible.

Deploying IDM

Like any good Red Hat product, IDM is opinionated. It's based on the upstream FreeIPA, and in general IDM provides the same services as Active Directory - LDAP, Kerberos, and optionally, DNS and/or SSL. On Active Directory, the CA piece is a separate role. In my testing, I found that accepting the defaults (SSL and CA deployed) is more or less expected. You can certainly use IDM without either DNS or the CA enabled, but it definitely makes things go smoother if you just accept the defaults.

My RHIDM servers are deployed on the latest version of RHEL (9.4 at the time of writing). Just like Active Directory, the requirements for deploying an IDM server are largely the same:

  • must have a static IP address
  • must have unique hostnames
  • time must be synchronized between hosts
  • primary IDM server's DNS should be set to itself
  • secondary IDM server's DNS should be set to the primary
  • secondary IDM server should be registered to the domain

Unlike Active Directory, IPV6 must be enabled on your IDM servers, even if the subnet they reside on has IPV6 disabled.

A far more in depth set of instructions on how to set up IDM can be found here https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html-single/installing_identity_management/index

I would HIGHLY recommend reading through this doc as it covers a lot of things I don't.

Configuring your first server for IDM

Let's make sure that time is synchronized. We do this using chrony.

dnf -y install chrony
systemctl enable --now chronyd

Next, let's configure our firewall to allow the necessary ports

firewall-cmd --permanent --add-port={80/tcp,443/tcp,389/tcp,636/tcp,88/tcp,88/udp,464/tcp,464/udp,53/tcp,53/udp}
firewall-cmd --permanent --add-service={freeipa-4,dns}
firewall-cmd --reload

Then let's install the necessary packages. Keeping in mind that ultimately we're going to be setting this up with a cross domain trust and internal DNS so we need to install a few additional packages

dnf -y install ipa-server ipa-server-dns ipa-server-trust-ad samba-client

Then we need to set the umask for the root user so the installer creates files with the appropriate permissions

umask 0022

Then just run the ipa-server-install command. Follow the prompts. In my lab, I'm using my OPNsense router as my primary DNS. If you wish to do so, you'll need to configure your DNS server as a forwarder. Personally, the idea of trying to use IDM (or Windows DNS for that matter) as my authoritative DNS sounds like a nightmare.

Just follow the prompts. I've abridged the output and just included the questions you need to answer with the values I put in for my IDM server

[root@test01 ~]# ipa-server-install 
...
Do you want to configure integrated DNS (BIND)? [no]: yes
...
Server host name [test01]: test01.idm.cudanet.org
...
Please confirm the domain name [idm.cudanet.org]: 
...
Please provide a realm name [IDM.CUDANET.ORG]: 
...
Directory Manager password: 
Password (confirm): 
...
IPA admin password: 
Password (confirm): 
...
Do you want to configure these servers as DNS forwarders? [yes]: 
...
DNS forwarders: 192.168.1.1
...
Do you want to search for missing reverse zones? [yes]: 
...
Do you want to create reverse zone for IP 10.0.0.76 [yes]: 
Please specify the reverse zone name [0.0.10.in-addr.arpa.]: 
...
NetBIOS domain name [IDM]: 
...
Do you want to configure chrony with NTP server or pool address? [no]: 
...
Continue to configure the system with these values? [no]: yes

which will then kick off the install for you. After the install completes, reboot your IDM server.

Configuring an IDM Replica

To install an IDM replica, I'd highly recommend reviewing the documentation here https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/installing_identity_management/installing-an-ipa-replica_installing-identity-management.

The requirements for an IDM replica are more or less identical to setting up your primary server, but with two major differences

  • the primary DNS server should be set to the IP address of your Primary server
  • the secondary must be registered as an IDM client of the domain
dnf -y install ipa-client ipa-server ipa-server-dns ipa-server-trust-ad samba-client

Then join the secondary server to the domain

[root@ridm02~]# ipa-client-install 
This program will set up IPA client.
Version 4.11.0

DNS discovery failed to determine your DNS domain
Provide the domain name of your IPA server (ex: example.com): idm.cudanet.org
Discovery was successful!
Do you want to configure chrony with NTP server or pool address? [no]: 
Client hostname: ridm02.idm.cudanet.org
Realm: IDM.CUDANET.ORG
DNS Domain: idm.cudanet.org
IPA Server: ridm01.idm.cudanet.org
BaseDN: dc=idm,dc=cudanet,dc=org

Continue to configure the system with these values? [no]: yes
Synchronizing time
No SRV records of NTP servers found and no NTP server or pool address was provided.
Using default chrony configuration.
Attempting to sync time with chronyc.
Time synchronization was successful.
User authorized to enroll computers: admin
Password for admin@IDM.CUDANET.ORG: 
Successfully retrieved CA cert
    Subject:     CN=Certificate Authority,O=IDM.CUDANET.ORG
    Issuer:      CN=Certificate Authority,O=IDM.CUDANET.ORG
    Valid From:  2024-09-15 21:58:31+00:00
    Valid Until: 2044-09-15 21:58:31+00:00

Enrolled in IPA realm IDM.CUDANET.ORG
Created /etc/ipa/default.conf
Configured /etc/sssd/sssd.conf
Systemwide CA database updated.
Hostname (ridm02.idm.cudanet.org) does not have A/AAAA record.
Failed to update DNS records.
Missing A/AAAA record(s) for host ridm02.idm.cudanet.org: 10.0.0.3.
Missing reverse record(s) for address(es): 10.0.0.3.
Adding SSH public key from /etc/ssh/ssh_host_rsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ecdsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ed25519_key.pub
Could not update DNS SSHFP records.
SSSD enabled
Configured /etc/openldap/ldap.conf
Configured /etc/ssh/ssh_config
Configured /etc/ssh/sshd_config.d/04-ipa.conf
Configuring idm.cudanet.org as NIS domain.
Configured /etc/krb5.conf for IPA realm IDM.CUDANET.ORG
Client configuration complete.
The ipa-client-install command was successful

Then get a kerberos ticket for your domain admin

kinit admin

Then deploy your IDM replica

ipa-replica-install --setup-dns --setup-ca --forwarder 192.168.1.1

Once the install completes, you should reboot the server and you should have a functional IDM replica

Set up external DNS

Although I did enable the DNS server on IDM, and it gets deployed automatically as part of deploying Active Directory, I use neither and just rely on OPNsense as my only DNS source. I suppose if I really wanted to, I could set up some conditional forwards for the separate domains so that requests to ad.cudanet.org go to AD and requests to idm.cudanet.org go to IDM, but in my experience, even in my small lab, that can create some DNS performance issues so as a rule, I've avoided using multiple DNS servers as much as possible.

On the Windows side, you're going to need to gather a list of all your Active Directory DNS records. One one of your domain controllers run the following command

gwmi -Namespace root/microsoftdns -q "select * from MicrosoftDNS_SRvtype" -ComputerName addc01 | ?{($_.domainname -imatch "cudanet") -or ($_.srvdomainname -imatch "cudanet")} | ft OwnerName,srvdomainname,port -auto

which is going to give you an output like this, which is pretty close to the format you'll need to turn these into dnsmasq entries. On active directory, these records all happen to be SRV records. There will also be A records for you domain controllers (just two).

💡
You can pipe this out to a txt file by adding > output.txt to the end of the command

A SRV record entry for dnsmasq looks like this:

srv-host=_gc._tcp.Default-First-Site-Name._sites.cudanet.org,addc01.cudanet.org,3268

You can clean up this file and convert it to a dnsmasq.conf however you like, but I usually just do it in one shot on a Linux machine, eg;

cat ad.conf | awk -F " " '{print "srv-host=" $1 "," $2 "," $3}' | sed 's/.,/,/g'

which will output something like this

srv-host=_ldap._tcp.ForestDnsZones.ad.cudanet.or,addc02.ad.cudanet.org,389
srv-host=_ldap._tcp.ForestDnsZones.ad.cudanet.or,addc01.ad.cudanet.org,389
...

Save the dnsmasq.conf file.

If you happen to use BIND/Unbound, the format for your SRV records looks like this

local-data: "_kerberos._udp.cudanet.org IN SRV 0 100 88 addc01.cudanet.org"

so you could create the necessary unbound.conf file like this

cat ad.conf | awk -F " " '{print "local-data:  \"" $1 " IN SRV 0 100 " $3 " " $2 "\""}' | sed 's/."/"/g'

which would give you output like this

local-data: "_ldap._tcp.dc._msdcs.ad.cudanet.org IN SRV 0 100 389 addc02.ad.cudanet.org"
local-data: "_ldap._tcp.dc._msdcs.ad.cudanet.org IN SRV 0 100 389 addc01.ad.cudanet.org"

Save this file, as we'll need it later to configure DNS on OPNsense.

Now let's turn our attention to IDM. Log in to one of your IDM servers and perform the following

kinit admin

followed by the command

ipa dns-update-system-records --dry-run > dnsmasq.conf

which will generate a text file with the necessary entries for a BIND/Unbound server, eg

  IPA DNS records:
    _kerberos-master._tcp.idm.cudanet.org. 3600 IN SRV 0 100 88 ridm01.idm.cudanet.org.
    _kerberos-master._tcp.idm.cudanet.org. 3600 IN SRV 0 100 88 ridm02.idm.cudanet.org.
    _kerberos-master._udp.idm.cudanet.org. 3600 IN SRV 0 100 88 ridm01.idm.cudanet.org.
...

In order to convert this to unbound you're going to need to do a little extra work. Unlike AD which only uses SRV records, IDM uses SRV records, TXT records and URI records, which are not something that dnsmasq handles out of the box. So let's deal with these records in order, starting with the SRV records. Run a command like this

cat dnsmasq.conf | grep SRV | awk -F " " '{print "srv-host=" $1 "," $8 "," $7}' | sed 's/.,/,/g' > srv.txt

which will give you output like this

srv-host=_ldap._tcp.idm.cudanet.org,ridm01.idm.cudanet.org,389
srv-host=_ldap._tcp.idm.cudanet.org,ridm02.idm.cudanet.org,389
...

Now let's deal with the TXT records

cat dnsmasq.conf | grep SRV | awk -F " " '{print "srv-host=" $1 "," $8 "," $7}' | sed 's/.,/,/g' > srv.txt

which will give you output like this

txt-record=_kerberos.idm.cudanet.org,"IDM.CUDANET.ORG"

Now comes the fun part. Dnsmaq does not inherently support the URI records the way that BIND/Unbound does. Fortunately I found this handy python script here which can convert them for you

cat <<EOF > convert-uri.py
import binascii
import struct
record_name = b'_kerberos.idm.cudanet.org'
record_type = b'256'  # Assigned type number for URI records
priority = 10
weight = 5
value = b'krb5srv:m:tcp:ridm01.idm.cudanet.org'
print(b','.join((
    b'dns-rr=' + record_name,
    record_type,
    # The ! here uses network byte order, followed by two 'H's for unsigned 2-byte values.
    binascii.hexlify(struct.pack('!HH', priority, weight))
    + binascii.hexlify(value)
)).decode())
EOF

which when run will give you the output

dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30312e69646d2e637564616e65742e6f7267

To be completely honest, I did not feel inclined to diving into python coding to figure out how to variableize the record URLs and values, so I ended up resorting to just manually editing the script for each URI record I needed to generate. I'm sure it wouldn't be too hard to figure out which python module to import to accept a couple arguments and then blast them out into the script and run it through a loop.... but we're literally only talking about 8 records.

Grab the URI records you need to convert

cat dnsmasq.conf | grep URI

copy the values in field $1 and $7, dropping off quotes and the trailing . at the end of each and paste them into the fields for record_name and value respectively. Run the python script for each URI record, eg;

python convert-uri.py >> uri.txt

You should end up with a file like this

dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30322e69646d2e637564616e65742e6f7267

then bundle them all up together into one file, eg;

cat srv.txt txt.txt uri.txt >> idm.conf

which will give you a file with contents like this

srv-host=_kerberos-master._tcp.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos-master._tcp.idm.cudanet.org,ridm02.idm.cudanet.org,88
srv-host=_kerberos-master._udp.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos-master._udp.idm.cudanet.org,ridm02.idm.cudanet.org,88
srv-host=_kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._tcp.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._tcp.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._tcp.idm.cudanet.org,ridm02.idm.cudanet.org,88
srv-host=_kerberos._udp.Default-First-Site-Name._sites.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._udp.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._udp.idm.cudanet.org,ridm01.idm.cudanet.org,88
srv-host=_kerberos._udp.idm.cudanet.org,ridm02.idm.cudanet.org,88
srv-host=_kpasswd._tcp.idm.cudanet.org,ridm01.idm.cudanet.org,464
srv-host=_kpasswd._tcp.idm.cudanet.org,ridm02.idm.cudanet.org,464
srv-host=_kpasswd._udp.idm.cudanet.org,ridm01.idm.cudanet.org,464
srv-host=_kpasswd._udp.idm.cudanet.org,ridm02.idm.cudanet.org,464
srv-host=_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,389
srv-host=_ldap._tcp.dc._msdcs.idm.cudanet.org,ridm01.idm.cudanet.org,389
srv-host=_ldap._tcp.idm.cudanet.org,ridm01.idm.cudanet.org,389
srv-host=_ldap._tcp.idm.cudanet.org,ridm02.idm.cudanet.org,389
txt-record=_kerberos.idm.cudanet.org,"IDM.CUDANET.ORG"
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kerberos.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7463703a7269646d30322e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30312e69646d2e637564616e65742e6f7267
dns-rr=_kpasswd.idm.cudanet.org,256,000a00056b7262357372763a6d3a7564703a7269646d30322e69646d2e637564616e65742e6f7267

Configure dnsmasq on OPNsense

If you're an OPNsense user, you'll be dismayed to find that there is no mechanism in the web UI for adding records of any type other than A records and CNAMEs. In order to actually use the SRV records and such that we just generated for AD and IDM, you need to upload those two *.conf files to OPNsense via scp.

You need to add the config files in the directory /usr/local/etc/dnsmasq.conf.d/ and then bounce the service. Also, while you're at it, don't forget to create the A records for your IDM and AD servers if you haven't already done so.

💡
If there are any typos or improperly formatted entries in your dnsmasq.conf files, the dnsmasq service will not start.

If you use Unbound on OPNsense, the config files go in /usr/local/etc/unbound

Now, with dnsmasq on OPNsense configured to serve all the necessary records for IDM and AD to work, you should be able to authenticate to either domain from any client on your network. Here are some examples of me performing LDAP searches against both domains from my MacBook which is not joined to either domain, and just gets it's DNS via DHCP from OPNsense:

Set up Cross Domain Trust

First, you need to enable AES256_HMAC_SHA1 encryption on your domain.


  • Open the Group Policy Management Console.
  • Right-click Default Domain Policy, and select Edit. The Group Policy Management Editoropens.
  • Navigate to Computer Configuration  Policies  Windows Settings  Security Settings Local Policies  Security Options.
  • Double-click the Network security: Configure encryption types allowed for Kerberos policy.
  • Select AES256_HMAC_SHA1 and, optionally, Future encryption types.
  • Click OK.
  • Close the Group Policy Management Editor.
  • Repeat the steps for the Default Domain Controller Policy.
  • Wait until the Windows domain controllers (DC) applied the group policy automatically. Alternatively, to apply the GPO manually on a DC, enter the following command using an account that has administrator permissions:
gpupdate /force

Then on each of your IDM servers, run the command

update-crypto-policies --set DEFAULT:AD-SUPPORT

Then in the IDM console on your primary IDM server, add your AD domain as a DNS forward zone

Then on your primary IDM server run the following command and follow the prompts

ipa-adtrust-install
...
Do you wish to continue? [no]: yes
...
Enable trusted domains support in slapi-nis? [no]: yes
...
NetBIOS domain name [IDM]:
...
Do you want to run the ipa-sidgen task? [no]: yes

And finally, run the following command to set up your cross domain trust

ipa trust-add --type=ad ad.cudanet.org --admin Administrator --password

Follow the prompts. When completed, it's probably a good idea to restart your IDM server(s).

Test authentication with users on both domains

As we can see, we have authentication working with users in either domain.

Now let's do something useful with it, like set up LDAP authentication on some services. I'm not going to go super in-depth on this as it's not really within the scope of this article, but I'll share some screenshots that might give you some ideas how to implement it and where this is useful

OPNsense
Satellite
Gitea
Openshift

Enjoy!