FreeIPA is pretty cool but it is a complex beast with a lot of moving parts. Its documentation is alright but there are many things that were (as least to me) not obvious about it.

Official Documentation

Google often lands you onto Fedora's documentation site (which is outdated) or various parts of the FreeIPA wiki (which often related to planned features, as opposed to implemented ones).

The best place to start when looking for reference documentation is Red Hat's Red Hat Identity Management Documenatation index.

See also the FreeIPA documentation index.

Directory suffix

The examples below assume a FreeIPA domain of When naming directory entries, replace SUFFIX, with dc=ipa,dc=example,dc=com.

If you use the integrated CA feature, then Dogtag's state will be stored in the directory at another suffix: o=ipaca. You mostly don't have to worry about that detail except when configuring and monitoring replication status.

Connecting to the directory via UNIX sockets

To administer the directory server, you have to use Simple Authentication, specifying cn=Directory Manager as the password. Having to keep the password handy is a bit annoying.

There is an alternative: a process connecting via a UNIX socket can use SASL EXTERNAL authentication in order to be identified by their UID/GID. On the command line:

# ldapwhoami -H ldapi://%2frun%2fslapd-IPA-EXAMPLE-COM.socket -Y EXTERNAL
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
dn: cn=Directory Manager

Note that we weren't prompted for a password--the root user is mapped to cn=Directory Manager by default.

This can be made the default for the root user by putting the following in /root/.ldaprc:

URI ldapi://%2frun%2fslapd-IPA-EXAMPLE-COM.socket

if you connect via a UNIX socket then SASL EXTERNAL authentication password handy, you can connect directly to the LDAP server via a UNIX socket by using the -H ldapi://%2frun%2fslapd-IPA-EXAMPLE-COM.socket -Y EXTERNAL options to ldapsearch et. al.

Root DSE attributes

As with all LDAP directories, some interesting details can be queried anonymously by performing a search for the root entry:

See Root DSE Attributes for an explanation of what they mean.

Password storage

The cn=Directory Manager password is stored on the nsslapd-rootpw attribute of cn=config.

Password hashes are stored in the userPassword attribute.

The default hash format is (now) {PBKDF2_SHA256}; it used to be the (weak) {SSHA512}.

The AllowNThash password plugin poilicy is enabled by default. If ipa-adtrust-install has been run, then the NT hash (unsalted MD4, gotta love that security) will be written to the sambaNTPassword and/or ipaNTHash attributes during password change (or during kerberos authentication to a Sabma server, maybe?)

Replication status monitoring

dsconf URL replication monitor: a port of to Python. Added in as part of #50545 which made it into 389-ds

dsconf URL replication get --suffix=SUFFIX just dumps the nds5replica object at cn=replica,SUFFIX,cn=mapping tree,cn=config object, in LDIF format (or JSON with -j).

dsconf URL repl-agmt list --suffix=SUFFIX just dumps the nsds5replicationagreement objects underneath the nds5replica object for SUFFIX, in LDIF format (or JSON with -j).

dsconf URL healthcheck presumably exits non-zero if there's a problem with the server.

Checking RUVs manually

For each replicated suffix, on the supplier get the replica id and the maximum CSN of each replication agreement:

There will be one attribute per agreement in the format:

For each of these agreements, *on the consumer*:

There will be one attribute per agreement in the format:

Match the suppler and consumer replica agreement IDs up and check that the max CSNs are the same.

If they are different, calculate the lag time by extracting the timestamps from the max CSNs (first 8 digits), parsing the hexadecimal number, taking the difference as the number of seconds.

The Red Hat Directory Server manual has all the info about how replication works.

Exposing to the Internet

Certificate storage locations

Trust Store

The list of known CA certificates that the FreeIPA installation trusts is kept in the directory under cn=certificates,cn=ipa,cn=etc,SUFFIX. For a stand-alone CA installation, the store will normally only contain the CA's certificate (IPA.EXAMPLE.COM IPA CA). But for an externally signed CA installation, it will contain the external CA certificate as well. This bug shows examples of the schema.

The ipa-cacert-manage list command will perform an LDAP search, and print an entry for each certificate it finds.

New certificates can be installed with ipa-cacert-manage install. There's no command to remove them.

The ipa-certupdate can be run on a client to make sure any new or renewed certificates added to the trust store are applied to the local machine. On a server it will additionally ensure that new or renewed certificates added to the trust store are installed into the the KDC, web and directory server certificate databases (or is this done instead by ipa-server-certinstall?)

/!\ If you have more than one certificate in the trust store, this bug means that OpenSSL on Debian-based systems won't trust *any* of them. I'm working on a fix for this.

Legacy CAcert container

The entry cn=CAcert,cn=ipa,cn=etc,SUFFIX contains the IPA CA certificate. It's used by:

When certmonger starts up, it uses this entry to refresh its cached copy of the IPA CA certificate (ref: fetch_roots function).


cn=cas,cn=ca,SUFFIX contains the IPA CA certificates themselves (plural because IPA supports multiple 'lightweight sub-CAs'.

Host Aliases

Say you have a host,, with an IP address of

The host is behind a NAT gateway with an address on the Internet of

If you enable dyndns_update, a will point at Although this leaks information about foo's local network to the public, at least users on foo's network will be able to reach it using that FQDN.

But what if the NAT gateway is provided by Sky Broadband? Sky's routers intercept DNS traffic, preventing their customers from using third-party DNS resolvers, doubtless so that Sky can sell information about the web sites their customers visit to advertisers. As a side effect of this, some more exotic forms of DNS traffic are blocked. This includes the GSS-TSIG messages from nsupdate, which is the mechanism that sssd uses to perform DNS updates. (Debugging this was not fun.)

One alternative is for users on foo's network to make use of mDNS and reach it at foo.local. In order to make sure that they can use Kerberos to log in, we must make use of FreeIPA's Kerberos Principal Alias feature:

Users can now obtain a ticket for host/foo.local and use it to authenticate to the SSH server running on foo.

However, users will still be prompted to confirm foo's SSH host key; this is because sss_ssh_knownhostsproxy requests the host keys for foo.local, and SSSD's SSH responder isn't able to search the directory for hosts by alias.

CA renewal server/CRL publisher promotion

The documentation for removing a server from the topology doesn't mention that you need to move the CA renewal server and CRL publisher roles to another server with the CA role.

If you don't do this, it's not fatal, but your CRL file won't be updated.

Both steps are explained in a separate chapter, Decommissioning a server that performs the CA renewal server and CRL publisher role. There is overlap with content from the Managing Replication Topology chapter.

If you want to check the status of your CRL file:

$ curl -sS -L | openssl crl -inform der -noout -lastupdate
lastUpdate=Nov 16 15:13:34 2021 GMT

... you can view the whole CRL with -text and [other options are available|].

The rest of the notes under this heading are obsolete now that I've straightened things up, linked to the docs and filed the above bugs to try to get them cross linked... just skip past them. I'll remove them eventually...

The Starting CRL generation on RHEL 8 chapter of the "Migrating IdM from RHEL 7 to RHEL 8 and keeping it up-to-date" section of the RHEL 8 Installing IdM manual doesn't make much sense. The new replica is running RHEL 8, so why do the prerequisites talk about RHEL 7.6/7.7?

After following these steps on a CentOS 8.0.1905 machine, the CRL is not available:

The manual mentions a ipa-crlgen-manage command, which does not exist in CentOS 8, but it does exist in CentOS 7:

Examining the FreeIPA source reveals that this script was added in FreeIPA 4.8:

And backported to FreeIPA 4.7.3 and 4.6.5:

So I guess it will show up in CentOS 8.1. But until then, examining the source code reveals that, after manually enabling CRL generation, there is an additional undocumented step:

Unfortunately the updateCRL method was likewise only added in FreeIPA 4.7.3. Fortunately it's not too complex to prevent me from bodging together the following:

And behold, we now have a CRL on the new master:

Remaining questions

There are still seemingly significant differences in Tomcat's configuration between the old and new masters:

These settings are mentioned in older documentation and on a post to the mailing list:

So I'm still not sure whether my new master CRL generator will actually listen to updates from replicas and/or periodically check the status of certificates for updates. I also wonder whether has to be updated on ipa1...

PKI topology goes out of sync with LDAP server topology

After removing some servers with the CA/KRA roles, the list of servers in Dogtag will get out of sync with the replication topology in the directory.

This will cause ipa-healthcheck to complain about non-contactable CA/KRA servers.

The upstream bug shows how to fix this:

... run that for each removed CA/KRA server.

Extending FreeIPA

Custom subtrees should go in an nsContainer directly under SUFFIX.

DNS: long TXT records

DMARC requires rather long TXT records. Attempting to create one of these in the web UI or on the command line works, but then named-pkcs11 logs:

The reason for this is not obvious.

So, RFC 1035 describes the data of a TXT RR as simply "One or more <character-string>s". And describes <character-string> as "a single length octet followed by that number of characters. <character-string> is treated as binary information, and can be up to 256 characters in length (including the length octet)."

So our everyday experience of a TXT record is wrong! We naïvely think of it as "just a string", when really it has structure; in this case, one or more arrays of bytes each of which can be up to 255 characters. BIND is choking because it's trying to compile a TXT record consisting of a single <character-string> of well over 300 bytes!

The RFC also defines how to represent a <character-string> in a Zone file, as parsed by BIND:


So it turns out that zone file format is more of a literal transcription of DNS data into a binary format than I had expected. So where you express the following in a zone file:

... the compiled RRDATA for the record consists of *nine* length-prefixed byte strings. It's only RFC 7489, sec. 6.1 that determines that they are stitched together into a single string by the entity making use of the records:

Stitching this knowledge together we can now create the record in the web UI or the ipa command, simply by adding spaces to the record data so that no one run of characters lasts for more than 255 bytes. For example:

While figuring out the above I ran into RFC 1464, which proposes a way to store structured data within TXT records, by having each <character-string> within the RDATA for a TXT record represent an attribute and value pair, separated by =. e.g.:

It does not state, although I presume, that you can have multiple attributes by using multiple <character-string>s within the RDATA:

... up to the maximum length of the RRDATA for a record which is 65536 bytes. I guess that one of the reasons this never took off is that the length of each value would be limited to 254 - (length of attribute) bytes.

CategoryTechnote FreeIPA (last edited 2021-11-17 00:33:54 by sam)

© Sam Morris <>.
Content may be distributed and modified providing this notice is preserved.