FreeIPA, Kerberos, LDAP, Subversion Stack Part 3: LDAP Setup

If you’ve read this far, Your site config isn’t complete and we’re still working inside the <location> directive.  My last post ended with the Kerberos configs.  Get through this post and there is one to go to use Apache’s Require directive to tighten things up.

Before you continue.

It’s going to be very helpful to be able to tail the 389DS logs in the freeIPA server.  Apache’s LDAP and Kerberos auth error logs are cryptic.  If you can check the 389DS logs, you can get an idea where the issue lies.

If you don’t have an LDAP browser, you should probably get one.  It’s very helpful in being sure your paths are set up right.  I like jxplorer.  The SSL setup is pretty straightforward, especially if you have previous experience in Java’s encryption norms.

LDAP Module Settings

This configures default caching and the very important path to the certificate authority (CA) cert.  Get the CA cert using openssl’s s_client directive.  There are tons of examples on the internet.

Start a new file.

nano /etc/httpd/conf.d/ldap.conf.
LDAPSharedCacheSize 500000
LDAPCacheEntries 1024
LDAPCacheTTL 600
LDAPOpCacheEntries 1024
LDAPOpCacheTTL 600
LDAPTrustedGlobalCert CA_BASE64 /etc/httpd/certs/ca.crt myPassword?

I’m not 100% sure what’s going on with those default settings until you get to the last one.  The last one is Certificate Authority path.  You must have this in order to initiate SSL LDAP connections.  If your certificate is encrypted with a password, the password goes on the end.

The quick and dirty way to get your CA is to initiate an ssl request using openssl and the s_client directive.  Apache supports two formats for keys, pem and der.  CA_BASE64 is “pem” format.  FreeIPA exports the PEM format and so does openssl.

Be sure Apache and only Apache can read the file.


For me, in August 2017, the handy AuthBasicProvider directives did not work as advertised.  It is probably me.  If you can get it to work, it’s a very handy way to trim and reuse directives.

Here’s the LDAP portion of the subversion site.

# AuthBasicProvider ldap1 ldap2 does not work
 AuthLDAPBindDN uid=ldapsearcher,cn=users,cn=accounts,dc=mydomain,dc=la
 AuthLDAPBindPassword Preposterous!!
 AuthLDAPURL ldaps://,cn=accounts,dc=mydomain,dc=la?krbPrincipalName?sub
 LDAPTrustedClientCert CERT_BASE64 /etc/httpd/certs/apache-host.crt

Notice that I set up a normal user without host login rights that can search.  389DS has some anonymous searching permissions set, but, certainly not enough to do group searches and little logging of the permission denial.    There are a couple of different blog posts describing another way to add an unprivileged user to the 389DS config instance on the Internet. But,  the config method didn’t work for me in 2017.


Here’s the second most important stanza in the LDAP setup.  The construction of the stanza with spaces added for clarity is ldaps:// Fully Qualified Host Name / Search Base? / Search field ?sub.

A fully qualified domain name works with SSL. The “search base” is where the client begins the search for the user. The “search field” is the attribute used to find the user name passed into Apache from the login form. The “sub” directive means to search every branch below the search base.  The question marks matter.

If you don’t get this stanza set up right, LDAP just won’t work and it won’t be obvious why if you are just checking Apache’s logs.  Here is where you need to tail the 389DS logs looking for Apache’s client search activity.  The 389DS log is busy.  You’ll need good grep-fu to pick the Apache activity out.


The Apache server’s host certificate needs to be stored inside a directory Apache can read.  How about putting it in with your CA cert?  You can get the certificate from the freeIPA website GUI under the host info.  Copy/paste and set correct permissions so only Apache can read it.

Advanced Config Wish List

I haven’t worked through the method of using the user logging into the repository Kerberos credentials to do the search. Apparently, this is possible.

Building and Running Freeipa 4.4.4 on Centos 7

I was trying to replicate Freeipa from a Fedora 25/Freeipa 4.4.4 to NOT Fedora 25.  How hard could it be to rebuild Freeipa 4.4.4 on Centos?  It turns out it is fiddly to get the packages built.

The following is not for the faint of heart and leaves out a bunch of build environment stuff, so this is not a good package to learn rebuilding a package.  But, the instructions  should save you a ton of time.

Download Fedora 25’s Freeipa source.  It should be in this directory:

Download mod_wsgi source from Fedora 25.  It should be in this directory.

Download dinglibs source for Fedora 25.  I found it here:

Download cmocka source for Fedora 25.  I found it here:

And so on for the following: ldns, python-astroid, pylint.  I was unable to build the sssd version that ships with Fedora 25 and a couple of the Python packages.  That means the freeipa.spec file gets modified with lower version requirements and the python package requirements get commented out and installed with pip.

There are also modifications to the spec files needed to be sure the packages don’t conflict with themselves.

The modifications to the spec files to accept a lower version of some of the packages are easy.  The build script should complain the correct version isn’t available. Figure out what your distro packages and modify the spec file accordingly.

My recollection is the general order of build was:

  1. build mod-wsgi
  2. build dinglibs
  3. build cmocka
  4. build python-astroid
  5. build pylint
  6. build ldns
  7. build free-ipa

The freeipa build will probably fail a couple of times on simple dependencies in the spec file.  Just keep adjusting the spec file and you’ll get built packages in a few tries.

Here is my freeipa.spec file.  It is not perfect as a number of the packages built complain about conflicting with themselves. freeipa.spec

If, after you get the packages built and the install goes okay AND you are running in an SELinux environment, be sure to run audit2allow -w -a after the IPA server stack is up to check for policy denials.

Do This Too!

For some reason, the replication setup script demands testing TCP port 7389 as another way to reach the LDAP server.  You need a port address translation for it.

firewall-cmd --permanent --zone=public --add-rich-rule="rule 
family="ipv4" \
source address="" \
port protocol="tcp" port="7389" accept"

firewall-cmd --permanent --zone=public --add-forward-port=port=7389:proto=tcp:toport=636:toaddr=

That’s the firewall-cmd way to forward anything showing up on TCP 7389 from the LAN and sending it to 636.  Adjust as needed.  It works for me.

Good luck!


Advanced Unbound DNS Server

Unbound is a multi-function DNS server from the BSD side of the Unix world.  It supports more features than dnsmasq, in particular, lots of security features related to DNSSEC.

Below is a configuration with no explicit DNSSEC that supports Kerberos, and LDAP.  It explicitly disables DNSSEC while acting as a local domain name server.

   access-control: allow
   cache-max-ttl: 14400
   cache-min-ttl: 900
   hide-identity: yes
   hide-version: yes
   minimal-responses: yes
   prefetch: yes
   qname-minimisation: yes
   rrset-roundrobin: yes
   use-caps-for-id: yes
   verbosity: 1

      name: "."
      forward-addr:        # Google
      forward-addr:        # Google
private-domain: "mydomain.zed"
domain-insecure: "mydomain.zed"
domain-insecure: ""
local-zone: "" nodefault
local-zone: "mydomain.zed." static
local-data: "mydomain.zed. 86400 IN NS ns1.mydomain.zed."
local-data: "mydomain.zed. 86400 IN NS ns2.mydomain.zed."
local-data: "mydomain.zed. 86400 IN SOA ns1.mydomain.zed. nobody.invalid. 1 3600 1200 604800 1080"
local-data: "mydomain.zed. 86400 IN SOA ns2.mydomain.zed. nobody.invalid. 1 3600 1200 604800 1080"
local-data: "ns1.mydomain.zed. 86400 IN A"
local-data: "ns2.mydomain.zed. 86400 IN A"
local-data: "server1.mydomain.zed. IN A"
local-data-ptr: " server1.mydomain.zed"
local-data: "server2.mydomain.zed IN A"
local-data-ptr: " server2.mydomain.zed"
local-data: "idserver.mydomain.zed IN A"
local-data-ptr: " idserver.mydomain.zed"
local-data: "_kerberos._tcp.mydomain.zed. 3600 IN SRV 0 100 88 idserver.mydomain.zed"
local-data: "_kerberos._udp.mydomain.zed. 3600 IN SRV 0 100 88 idserver.mydomain.zed"
local-data: "_kerberos-adm._tcp.mydomain.zed. 3600 IN SRV 0 100 749 idserver.mydomain.zed"
local-data: '_kerberos.mydomain.zed. TXT mydomain.zed"'
local-data: "idserver CNAME idserver.mydomain.zed"
local-data: "_kerberos-master._udp.mydomain.zed. 3600 IN SRV 0 100 749 idserver.mydomain.zed"
local-data: "_kpasswd._udp.mydomain.zed. 3600 IN SRV 0 100 749 idserver.mydomain.zed"
local-data: '_kerberos.mydomain.zed. TXT "mydomain.zed"'
local-data: "_ldap._tcp.mydomain.zed. 3600 IN SRV 0 100 389 idserver.mydomain.zed"

PAY ATTENTION to the use of single-quotes for the TXT record!

There’s an unbound package for Debian Stable (Stretch at time of writing)

Things to Know about Samba 4.x in 2017

It’s April, 2017 and Samba 3.x has been used as a domain controller for many, many years.  Samba 4.x has introduced radical new capabilities while still including the 3.x kitchen sink.

I recently successfully migrated a Windows domain controller to Samba 4.x and discovered a few very important distinctions and supported capabilities of 4.x vs. 3.x CentOS vs. Debian that a new Samba admin should know.

  1. Samba 4.x is nothing like 3.x.  4.x doesn’t need much in the way of a configuration.  Samba-tool makes an smb.conf and kerberos config for you. Use them.
  2. CENTOS  Samba 4.0 domain controller functionality is entirely unsupported.  What CENTOS 7.x supports is running Samba 4.x in 3.x mode. Samba-tool does not work therefore it isn’t provided. That’s very important to know if you are trying to set up a modern Windows domain.  The reason for the required the encryption backend isn’t in CENTOS and apparently there are no plans for it.
  3. Use Debian Testing as a virtual machine.  You get everything you need with Debian Testing.  There is full Samba 4.x support, samba-tool works like the wiki states.  I run CENTOS 7.x as the host OS for a bunch of servers. Running libvirt/kvm-qemu works great.

Things to Know Before Setting Up FreeIPA

A few notes about the things I discovered  testing FreeIPA about February, 2017.

  1. It’s NOT A Windows domain controller. This should be obvious just checking the basic docs.
  2. It conflicts with samba.  The first impulse is to deny this claim because, hey, there’s ample documentation about adding samba and some kind of connector/backend from FreeIPA to Samba.  However FreeIPA forces /etc/hosts format to be opposite Samba’s demanded order.   For example freeipa and freeipa.  I’m not sure how one gets around this.
  3. The LDAP server must be dedicated to freeIPA.  Putting other databases in the same 389 server causes some confusion on the part of the FreeIPA environment.  The systemd scripts just don’t work with more than one 389 database.
  4.  Use a virtual machine like kvm.  FreeIPA can run as an lxc-container. BUT  auditing does not work.  This is a limitation of the lxc container.
  5. /etc/hosts file parsing is quite strict.  If things don’t work while the system configures itself, check the arrangement in /etc/hosts.

ISC DHCPD with LDAP Part 2

If you haven’t set up your LDAP server and added the DHCP schema, then visit Part 1 of the series before moving on.

Thanks to this guy:

Based on that blogspot post, I was able to get pretty far. You should too.

Step 1: Add OU

What worked for me was adding an organizationalUnit to the LDAP tree, ou=dhcp,dc=michaelpapet,dc=com.  All the configs sit under that branch.

Step 2: /etc/dhcp/dhcpd.conf

Since we are letting Debian install the server, the slapd package maintainer allows anonymous search “out of the box.” the /etc/dhcp/dhcpd.conf doesn’t need a username and password.  If you want, you can do that.

ldap-server                 "localhost";
ldap-port                   389;
# We do an anonymous bind
# ldap-username             "cn=directorymanagerloginname";
# ldap-password             "mypassword";
ldap-base-dn                "ou=dhcp,dc=michaelpapet,dc=com";
ldap-method                 static;
ldap-debug-file             "/var/log/dhcp-ldap-startup.log";
ldap-dhcp-server-cn         "cn=server,ou=dhcp,dc=michaelpapet,dc=com"


There are two options for ldap-method.  Static reads the ldap directory and writes a config based on the directory contents.  Dynamic reads the ldap directory as needed. This has bad consequences if you are trying to debug your config with a cat /var/log/dhcp-ldap-startup.log.  Some of the config wil be “missing” on startup.  But, if a client somehow triggers a search for all settings, then the setting would be returned.

Order matters in the LDAP tree for the dhcpd server.  AFAICT, the easiest way to set it up is to adhere to the parent/child relationships mentioned below.

Step 3: Add the service.

Then, per the instructions, you add the service.  Note that the service has to correctly reference the server.  And, the server has to  correctly reference the service path.  The URL above shows that pretty clearly.

Also worth noting, your global DHCP server options go under the service.  For example, authoritative, classes, subclass and more are added using the dhcpStatements attribute.

Step 4: Add the subnet setting beneath the service

The subnet, and related settings goes in the subnet objectClass.  For example, default-lease-time would go into the dhcpOption attribute.  You will probably add a few.

Optional Step 5: Add pools as children to subnet and classes

If you want pools, then set them up under the subnet.  If you want allow/deny rules, then add something to the dhcpPermitList attribute like

allow members of "my-hosts"

Which leads us to the dhcpClass attribute.  I got it to work by using the attribute below the dhcpServer objectClass. In LDAP-ese cn=my-hosts,cn=MainServer,ou=dhcp,dc=michaelpapet,dc=com.

Then the attribute dhcpSubClassesdn points to a group of mac addresses.  For example, ou=my-macs,cn=MainServer,ou=dhcp,dc=michaelpapet,dc=com.

Under ou=my-macs, add objectClass dhcpSubClass.  As an example, attribute dhcpClassData = my-macs, cn=1:0a:1b:2c:3d:4e:5f NOTE THE 1: prefix to the mac address.  My limited understanding this means it identifies the MAC address.

Step 6: Test
dhcpd -f -d

If there were no problems, then the server is running, not forked.  You can then see it working to be sure it does what you want.

To see what config the server is running,

cat /var/log/dhcp-ldap-startup.log

Again, be sure the dhcpd server is running in static mode in /etc/dhcp/dhcpd.conf to see the config that is/isn’t running.

ISC DHCPD with LDAP Config Part 1

The average environment with one or two admins can probably do just fine with the /etc/dhcp/dhcpd.conf flat file.  Syntax isn’t the challenge.  As soon as you get into access control and many devices/subnets, the flat file gets long and that’s when mistakes happen. LDAP backend makes everything easier.

It’s important to note at the outset I’m running Debian Testing,  February 2016, Debian’s repositories.  Maybe by the time you read this, things have changed.  If you are new to LDAP, it’s a learning curve.  This first part might take a while.  I’m rushing through setup.

Get Ready

I like using an LDAP browser.  I like jxplorer because it supports the modern cn=config editing.  On Windows, the popular (and useful) ldapadmin is good, but does not support cn=config editing.

Get Packages
apt-get install slapd isc-dhcp-server-ldap isc-dhcp-server

Debian’s packages set up slapd (that’s the openldap server) for you, prompting you for an admin password.  It seems like they want you to use the command line tools ldapsearch and ldapmodify to edit cn=config. Check out what’s configured with this.

ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config"


This is probably bad advice: I set a cn=config password.  A little later on, I can use jxplorer to change the config.

To start: use ldapsearch to find the config database.

ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config"

Then you write the file that adds the password.

dn: olcDatabase={0}config,cn=config #be sure config is database 0.  
#You looked carefully at the output of ldapsearch, right?
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}some_hashed_password #this was made with slappasswd

Then ldapmodify to add a password field. ldapmodify -c -Y EXTERNAL -H ldapi:/// -f /home/thatsme/pwd.ldif

If you aren’t familiar with ldif syntax, that should take a while to learn.


Debian’s package includes the schema file.  Openldap’s cn=config doesn’t support old-school schema files and that’s what the Debian package maintainer ships.  So, you have to find someone who has converted it for you if you don’t want to do a bunch of search/replace.

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/dhcp.ldif

This is a good stopping place.  Next article, the ISC DHCP server setup.