Stop Managing Users, DNS, and Certs Separately: FreeIPA Does It All

You’ve got ten servers. Each one has its own /etc/passwd, its own SSH keys pasted in authorized_keys, and HTTPS certs you renewed by hand last February. Adding a new engineer means logging into each box, creating a user, copying keys, and hoping nobody forgets one. When someone leaves the company, you do it all backwards — and you probably miss one.

This is the sysadmin equivalent of storing passwords in a spreadsheet. It scales to about three machines before it becomes a liability.

The usual answer is "just use Active Directory" — but AD is Windows-first, opaque, requires a CAL-counting Microsoft licensing conversation, and runs awkwardly on Linux unless you’re throwing money at Centrify or SSSD glue.

FreeIPA is the alternative that doesn’t compromise. It’s LDAP + Kerberos + DNS + a full PKI CA + a web UI that doesn’t make you want to close the tab immediately. It’s what Red Hat ships as IdM, and it’s what this article will walk you through deploying properly — not the "quick start that breaks in production" version.

The official project lives at https://www.freeipa.org and the source at https://github.com/freeipa/freeipa.

What You’re Actually Getting

Before touching a command, understand the stack. FreeIPA bundles:

  • 389 Directory Server — the LDAP backend. Everything lives here: users, groups, policies, host records.
  • MIT Kerberos (krb5) — authentication tickets. No password sent over the wire, ever. SSO across all enrolled hosts.
  • Dogtag PKI — a full certificate authority. Issues TLS certs for services, user certs for smart card auth, signs S/MIME. It’s not a toy — the same CA software underpins Red Hat’s own product.
  • BIND with a custom plugin — authoritative DNS that syncs dynamically with the LDAP database. Add a host, get a DNS record. No zone file editing.
  • Certmonger — a daemon that watches certs and auto-renews them against Dogtag. Set it and genuinely forget it.

Every component talks to the others. Kerberos principal names match LDAP entries. DNS records correspond to LDAP host objects. Certs are issued against principals the CA already knows. That coherence is the point — it’s why FreeIPA beats cobbling together OpenLDAP + Let’s Encrypt + a standalone Kerberos install.

Architecture Decisions Before You Start

Two servers minimum for anything you care about. FreeIPA uses multi-master replication — both masters accept writes. You’ll configure the second replica in a later section. Don’t run a single-node IPA in production; Kerberos tickets can’t be issued if your one server is rebooting for a kernel update.

DNS is the load-bearing wall. FreeIPA’s integrated DNS is not optional in practice. You can technically point FreeIPA at an external DNS, but then dynamic DNSUPDATE doesn’t work, host enrollment is manual, and you lose a chunk of the automation. Use the integrated DNS.

Realm naming matters and cannot be changed later. Your Kerberos realm is permanent. Use your actual domain in ALL CAPS. If your domain is infra.example.com, your realm is INFRA.EXAMPLE.COM. Don’t use a made-up realm name unless you enjoy future misery.

Environment

This guide uses Rocky Linux 9 (works identically on AlmaLinux 9, RHEL 9). The commands are the same on Fedora; on Debian/Ubuntu, the package is freeipa-server from the universe repo, but the web UI and some tuning options differ — I’d recommend staying RHEL-family for FreeIPA if you have a choice.

Specs that actually work (not the bare minimum from docs that will collapse under Dogtag):

  • 2 vCPU, 4 GB RAM per IPA server
  • 20 GB disk (Dogtag’s NSSDB and CRL files grow)
  • Static IP, resolvable hostname

Two machines for this guide:

  • ipa1.infra.example.com — 192.168.1.10
  • ipa2.infra.example.com — 192.168.1.11

Pre-flight: Hostname and /etc/hosts

FreeIPA’s installer uses the system hostname to derive the server’s Kerberos principal, LDAP DN, and initial DNS records. Get it wrong and you’ll be reinstalling.

# On ipa1
hostnamectl set-hostname ipa1.infra.example.com

# Verify — must return FQDN
hostname -f

Add both servers to /etc/hosts on each machine. IPA’s installer checks forward and reverse DNS before it even starts — if they don’t resolve consistently, the installer bails:

192.168.1.10  ipa1.infra.example.com  ipa1
192.168.1.11  ipa2.infra.example.com  ipa2

Gotcha: If your VM gets its hostname from DHCP, hostname -f may return the short name or something cloud-init invented. Fix /etc/hostname and /etc/hosts first, then verify hostname -f shows the full FQDN. The installer is unforgiving here.

Firewall

FreeIPA is not a single-port service. Open these on both servers:

firewall-cmd --permanent --add-service=freeipa-ldap
firewall-cmd --permanent --add-service=freeipa-ldaps
firewall-cmd --permanent --add-service=dns
firewall-cmd --permanent --add-service=ntp
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=kerberos
firewall-cmd --permanent --add-service=kpasswd
firewall-cmd --reload

Between the two IPA masters you also need port 7389 (replica agreement sync) and 8443 (Dogtag replication):

# On both servers, allow from the other IPA node
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.11" port port="7389" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.11" port port="8443" protocol="tcp" accept'
firewall-cmd --reload

Installing the Primary Server

dnf install -y ipa-server ipa-server-dns

Now the actual install. Every flag matters:

ipa-server-install \
  --domain=infra.example.com \
  --realm=INFRA.EXAMPLE.COM \
  --ds-password='YourDirManager$ecret' \
  --admin-password='YourAdmin$ecret' \
  --mkhomedir \
  --setup-dns \
  --forwarder=1.1.1.1 \
  --forwarder=8.8.8.8 \
  --auto-reverse \
  --no-ntp \
  -U

Flag breakdown:

  • --setup-dns — enable integrated BIND. Without this, you manage DNS externally and lose dynamic updates.
  • --forwarder — where BIND forwards queries it isn’t authoritative for. Use your upstream DNS.
  • --auto-reverse — automatically creates the reverse zone (1.168.192.in-addr.arpa.). You want this.
  • --no-ntp — if you already run chrony, don’t let IPA install its own NTP. Kerberos is extremely time-sensitive (5-minute skew tolerance); make sure chrony is synced before enrolling clients.
  • -U — unattended mode, reads passwords from flags. Skip this if you prefer interactive prompts.

The installer takes 5–10 minutes. It’s setting up 389-DS, Kerberos KDC, Dogtag, and BIND, then wiring them together. Watch the output — if it fails mid-way on the Dogtag step, it’s almost always a Java heap issue or a hostname resolution problem.

When it finishes:

kinit admin
ipa user-find admin

If you get a ticket and see the admin user, you’re live.

Gotcha: kinit admin failing with kinit: Cannot contact any KDC for realm means Kerberos can’t reach the KDC — usually a firewall rule or the hostname in /etc/krb5.conf not resolving. Check cat /etc/krb5.conf and verify the kdc entry matches your server’s FQDN.

The Web UI

Navigate to https://ipa1.infra.example.com/ipa/ui/. Your browser needs to trust the IPA CA, which Dogtag just created at /etc/ipa/ca.crt. Install that cert into your browser’s trusted CA store, or use the SSSD/IPA client tools on your workstation.

The UI is genuinely useful — user management, host management, HBAC (host-based access control) rules, sudo rules, DNS records, and cert management all live there. You won’t need it for everything, but it’s a good mental model of what IPA tracks.

DNS Integration: How It Actually Works

FreeIPA runs BIND with a custom plugin called bind-dyndb-ldap. When you create a host object in IPA, the plugin reads the LDAP database and populates DNS zones dynamically — no zone file, no rndc reload. DNS records appear within seconds.

Add a host record:

ipa host-add db1.infra.example.com --ip-address=192.168.1.20

Check it:

dig @192.168.1.10 db1.infra.example.com

You get an A record. The reverse PTR record was created too if --auto-reverse was set at install time.

For services that need SRV records (like XMPP or SIP), IPA has you covered:

ipa dns-record-add infra.example.com _xmpp-server._tcp \
  --srv-priority=10 --srv-weight=10 \
  --srv-port=5269 --srv-target=xmpp.infra.example.com.

Gotcha: The bind-dyndb-ldap plugin has a quirk with zone transfers — it doesn’t support AXFR from secondary nameservers by default. If you need secondary NS (you do, for HA), either add a second IPA replica (which gets its own authoritative BIND), or configure explicit allow-transfer ACLs in /etc/named/ipa-options-ext.conf. Don’t edit /etc/named.conf directly — IPA will overwrite it.

Kerberos: What It Gives You on Enrolled Hosts

Once a Linux host is enrolled in IPA with ipa-client-install, users log in with their IPA credentials. SSSD handles the translation between Kerberos and PAM. SSH with GSSAPI means a user with a valid ticket doesn’t type a password at all:

ssh -o GSSAPIAuthentication=yes [email protected]

No password. The Kerberos ticket does the auth. And because the ticket came from your KDC, you have a central audit trail.

Service principals work the same way. Register a service:

ipa service-add HTTP/webserver.infra.example.com

Then on the web server, use ipa-getcert (via certmonger) to get a cert:

ipa-getcert request \
  -k /etc/pki/tls/private/webserver.key \
  -f /etc/pki/tls/certs/webserver.crt \
  -N CN=webserver.infra.example.com \
  -D webserver.infra.example.com \
  -K HTTP/webserver.infra.example.com

The cert is issued by your Dogtag CA, tracked by certmonger, and will auto-renew 28 days before expiry. No cron job, no Let’s Encrypt rate limits, no cert.sh script run from someone’s laptop.

Gotcha: Certmonger tracks renewal state per-cert in /var/lib/certmonger/requests/. If a cert fails to renew (Dogtag down, replica disagreement), certmonger backs off and retries — but it won’t alert you loudly. Set up monitoring on cert expiry as a belt-and-suspenders check. getcert list shows the state.

Dogtag PKI: Your Internal Certificate Authority

Dogtag is the PKI component most people underestimate. It’s not a wrapper around OpenSSL — it’s a full-blown certificate management system with its own web interface (port 8080/8443 on the IPA host), OCSP responder, and CRL publication.

Out of the box, IPA configures Dogtag as a subordinate CA, with the root key stored in an NSS database at /var/lib/pki/pki-tomcat/alias/. Back this up:

# Backup the NSS database — do this immediately after install
tar czf /root/ipa-ca-nssdb-backup-$(date +%F).tar.gz \
  /var/lib/pki/pki-tomcat/alias/

Store that archive somewhere not on the IPA server itself. If you lose the CA key, you lose the ability to issue or revoke certs from this CA — every cert it ever issued will still work until expiry, but you can’t renew them.

For services that need to trust your IPA CA (internal apps, curl, Java clients), distribute /etc/ipa/ca.crt. On RHEL-family machines enrolled as IPA clients, this happens automatically.

External CA signing — if your organization already has a root CA (corporate PKI, hardware HSM), you can install FreeIPA with --external-ca so Dogtag’s CA cert is signed by your existing root. This is the right call in an enterprise context. The process involves generating a CSR during install, signing it externally, then feeding the signed cert back to the installer. The FreeIPA docs cover this flow in detail.

Enrolling Clients

On any RHEL/Rocky/Alma/Fedora machine you want to bring into the domain:

dnf install -y ipa-client
ipa-client-install \
  --domain=infra.example.com \
  --server=ipa1.infra.example.com \
  --principal=admin \
  --password='YourAdmin$ecret' \
  --mkhomedir \
  --unattended

After this, SSSD is configured to query IPA for users and groups, PAM uses Kerberos, and SSH keys stored in IPA (via ipa user-mod --sshpubkey) work for login. The host gets a host principal in Kerberos and an entry in LDAP.

For client-side failover, list both replicas:

ipa-client-install \
  --server=ipa1.infra.example.com \
  --server=ipa2.infra.example.com \
  ...

SSSD will round-robin and fall back if one is unreachable.

Setting Up Replication (Second Master)

On ipa2.infra.example.com, install the server package:

dnf install -y ipa-server ipa-server-dns

Run the replica installer:

ipa-replica-install \
  --domain=infra.example.com \
  --realm=INFRA.EXAMPLE.COM \
  --principal=admin \
  --admin-password='YourAdmin$ecret' \
  --setup-ca \
  --setup-dns \
  --forwarder=1.1.1.1 \
  --forwarder=8.8.8.8 \
  --auto-reverse \
  --no-ntp \
  -U

The --setup-ca flag is critical — it installs a Dogtag instance on the replica so it can issue certs independently if the primary is down. Without it, your replica can authenticate users but can’t issue or renew certs.

Replication uses LDAP sync agreements — both masters replicate the full DIT bidirectionally. Check the status:

ipa-replica-manage list
ipa-replica-manage status ipa2.infra.example.com

For Dogtag-specific replication (the PKI LDAP backend is separate from the main 389-DS instance):

ipa-csreplica-manage list
ipa-csreplica-manage status ipa2.infra.example.com

Both should show Last update status: 0 Replica acquired successfully.

Gotcha: FreeIPA replication does not use Paxos or Raft — it’s eventually consistent LDAP multi-master. If you write a user on ipa1 and immediately try to authenticate on ipa2, there’s a window (typically under a second on a LAN, longer over WAN) where ipa2 doesn’t know the user yet. For SSO this is fine; for automation scripts that create-then-immediately-use a user, add a retry loop or sleep.

Gotcha: Clock skew kills Kerberos. Both masters and all clients must agree on time within 5 minutes. In a VM environment, check that your hypervisor clock sync isn’t fighting with chrony. On KVM/QEMU, disable kvm-clock in the VM if you’re seeing time drift under load.

HBAC: Host-Based Access Control

This is FreeIPA’s answer to "not every user should log into every server." By default after install, the allow_all HBAC rule permits any IPA user to log into any enrolled host. That’s fine for a homelab, wrong for production.

Create a targeted rule:

# Create a group for the DB team
ipa group-add db-admins --desc "Database administrators"
ipa group-add-member db-admins --users=jsmith

# Create a hostgroup for DB servers
ipa hostgroup-add db-servers
ipa hostgroup-add-member db-servers --hosts=db1.infra.example.com

# Allow db-admins to SSH into db-servers
ipa hbacrule-add allow_db_admins
ipa hbacrule-add-user allow_db_admins --groups=db-admins
ipa hbacrule-add-host allow_db_admins --hostgroups=db-servers
ipa hbacrule-add-service allow_db_admins --hbacsvcs=sshd

# Disable the catch-all rule
ipa hbacrule-disable allow_all

Test the rule before you lock yourself out:

ipa hbactest --user=jsmith --host=db1.infra.example.com --service=sshd

You’ll see which rules matched. Only disable allow_all after verifying at least one rule grants your admin account access to at least one server.

Sudo Rules in IPA

Rather than maintaining /etc/sudoers on each box, define sudo rules centrally:

# Allow db-admins to run pg_dump as postgres on db-servers
ipa sudorule-add db_pg_dump
ipa sudorule-add-user db_pg_dump --groups=db-admins
ipa sudorule-add-host db_pg_dump --hostgroups=db-servers
ipa sudorule-add-runasuser db_pg_dump --users=postgres
ipa sudorule-add-option db_pg_dump --sudooption='!authenticate'

# Specify allowed commands
ipa sudocmd-add /usr/bin/pg_dump
ipa sudorule-add-allow-command db_pg_dump --sudocmds=/usr/bin/pg_dump

SSSD on the enrolled host picks this up — no nscd flush, no config file change needed.

Production-Ready Checklist

A few things the install docs gloss over that bite people in production:

Backup strategy. FreeIPA has a built-in backup tool: ipa-backup. Run it with --online so Dogtag doesn’t need to be stopped:

ipa-backup --online --logs
# Output goes to /var/lib/ipa/backup/

Schedule this with a systemd timer on both replicas and ship the archives off-box. Dogtag’s NSS database, the 389-DS backend, and the Kerberos stash file are all included.

CRL management. Dogtag publishes a Certificate Revocation List. By default, only the master CA (the one you installed first) generates CRLs. The replica’s Dogtag is configured to fetch CRLs from the master rather than generate its own. This is correct behavior — don’t change it unless you know what you’re doing with OCSP responders.

LDAP connection pooling. Applications connecting to IPA’s LDAP directly (rather than via SSSD) should use ldaps:// on port 636, not ldap:// on 389. The self-signed IPA CA cert is at /etc/ipa/ca.crt — configure your LDAP client to trust it.

Monitoring. Watch these:

  • systemctl status ipa — IPA’s umbrella service
  • ipactl status — shows each component (Kerberos, BIND, Dogtag, 389-DS, HTTPD) individually
  • Cert expiry via getcert list for anything certmonger is tracking
  • Replication status via ipa-replica-manage status in a cron job that alerts on errors

Log noise. 389-DS and Dogtag are verbose by default. Their logs land in /var/log/dirsrv/ and /var/log/pki/. If you’re shipping logs to a SIEM, filter out the OPERATIONS level entries from 389-DS — they log every LDAP bind and search, which is thousands of events per hour on a busy host. You want ERRORS and AUDIT.

Where This Leaves You

After this setup, your infrastructure has a single source of truth for users, credentials, SSH keys, TLS certificates, and DNS. Onboarding a new engineer is: create an IPA user, add them to the right groups, done. Their SSH keys are in LDAP, HBAC controls which servers they reach, sudo rules define what they can do there, and every cert in the environment auto-renews against your internal CA.

Offboarding is ipa user-disable username. Their Kerberos principal stops issuing tickets immediately. No spreadsheet of servers to check.

That’s what a real identity layer looks like.

👁 Views: 202,852 · Unique visitors: 57,408