Musings of a noob as I migrate from Windows to FreeBSD in my homelab

Service deployment update: OpenLDAP + Kerberos is up and running (4 of 4)​


Problems I encountered (or created for myself) getting surfrock’s prescription for a KDC+LDAP up and running​

In no particular order (at least not chronological), here’s a sampling of what went wrong during this adventure:
  • The #1 issue I had was typos, of course. I think I set a personal best (worst?) for fat-fingered mistakes. It doesn’t help that the Rx for my glasses is long-overdue for an update, making it easier to misread the config I’m working on (multiple times!) and search elsewhere for a fix, when the real fix was staring me right in the face.
    Example: My first attempt at parsing the initial .ldif into a starter database puked. So did my 2nd, and even my 3rd. The reason? Stupid things like mis-typing “olcDatabase” as “oldDatabase”. I was using vim to edit, so I can’t blame autocorrect… eventually I got rid of the gross typos and was left with more subtle ones (like not being consistent on how I specified the DNs for users)​
    Example #2: # service slapd start failed the first time with the error error: grep: /usr/local/etc/openldap/slapd.d/cn=config/olcDatabase=*: No such file or directory. Another stupid compound typo… when I created the folder /usr/local/etc/openldap/slapd.d/, I mis-named it slap.d/. Not only that, but my slapadd command to parse the ldif file into the database folder had the same typo, so it worked (the folder existed). Of course, rc went looking for the correct folder name and couldn’t find it…​
  • TLS didn’t work out of the box, for several reasons:
    1. I forgot to import my CA certificates into the LDAP jail. Easily fixed.
    2. I followed the FreeBSD Handbook’s instructions for hashing the server certificate (found in the Chapter 32.5 discussion of OpenLDAP), which it turns out is out of date. The command c_rehash . has been depricated and removed from the openssl package. The correct command to use is openssl rehash .
    3. I followed JamieLinux’s advice on creating a single .pem with the complete CA chain: intermediate CA cert listed first, followed by the root CA. OpenLDAP apparently can’t read a .pem with more than a single certificate in it. So, I split the CA chain cert into separate certs for each CA and only listed the intermediate CA in the olcTLSCACertificateFile: attibute in slapd.ldif. Seems to work fine… both CAs have their certs in /usr/share/certs/trusted/, and I made sure those were recognized by the system using certctl rehash.
    4. The FreeBSD handbook section on OpenLDAP doesn’t mention that TLS needs to be explicitly enabled in /etc/rc.conf. Specifically, slapd_flags needs to also have an entry ldaps://0.0.0.0/. If that’s not there, rc won’t launch the service with TLS enabled and there’s no possiblity of getting it to work. This was the last piece I needed to get secure TLS communication working.
  • The first time I tried to modify the database using ldapadd -Y EXTERNAL -H ldapi:/// -f 01.config.InstallMemberOf.ldif it failed with an insufficient access error. This one took me a bit to figure out, and I learned something along the way (bonus!). My first slapd.ldif was based on the example provided with the FreeBSD openldap26-server pkg install. That example does not allow this command to run out of the box.
    Explanation: using the -Y EXTERNAL flag tells ldapadd (or ldapmodify) to use the SASL layer to map the root user (uid=0,gid=0) to an LDAP-formated DN, and then asks LDAP to run the command using that DN for credentials. The DN format from SASL doesn’t match the global config administrator (cn=admin,cn=config), so the command is rejected.​
    Solution: I went off to do quite a bit of reading, which eventually led me to taking a look at the template slapd.ldif provided by Ubuntu. They include an ACL that explicitly allows the SASL-formatted DN to make management-level changes: olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break. Applying this to both the frontend and config database sections solved the issue. Given that the Ubuntu template seems a little more modern and full-featured than the one that FreeBSD ships, I switched my entire template over to the Ubuntu version and customized from there.​
  • The kadmind service failed to start on the first try with the error kadmind: LDAP bind dn value missing while initializing, aborting.
    • This was by far the most insideous problem I had to solve, and it took me a little over a week (I have a day job) to get past it. The issue wasn’t anything to do with Ubuntu vs FreeBSD minutae, typos, incomplete / out of date FreeBSD Handbook entries, or anything along those lines. What I finally tracked down makes me wonder about how package maintainers make their decisions on which options to include, however.
      The core issue: Take a look at surfrock66’s definitions for his user (and service) account DNs. You’ll notice that all his DNs have cn=somename,… However, if you read the OpenLDAP section on SASL authentication with GSSAPI, it explicitly says that the form of the DNs being used by SASL is uid=somename,…​
      Somehow, surfrock66’s setup is working using a nonstandard DN format.
      I went through and modified all the ldif files to use the uid convention for account DNs – making sure to explicitly change not just the accounts but all the ACLs that have them hardcoded in. Once I did this (basically required a rebuild), kadmind started without issue.​
      Conclusion? I can’t say for sure, but one explanation that comes to mind is that there’s a strict name-checking option enabled in the FreeBSD version of either cyrus-sasl-gssapi or openldap26-server that’s not enabled in the Ubuntu versions. Either that or I went completely crazy, because switching from the cn= to uid= version of account DNs was the only change I made, and kadmind went from not working to working. I’m glad it works for surfrock66, but if you want to copy his setup on FreeBSD you’ll need to do what I did and switch to uid=.​
    • Of course, there were the expected Ubuntu vs FreeBSD differences in paths for executables, logs, config files, along with differences in how flags get passed to services during startup. That’s all straightforward to figure out, if a little tedious.
    So, that’s the flavor of what I went through… to anyone looking to do this yourself, good luck! Take your time and be prepared to learn more than you’d like to. Not much of this is very well documented. I found myself re-reading the same man pages multiple times over different days to try and suss out how things should be working.

    Next up: enable pf on the LDAP/Kerberos jail (it’s wide open atm). Once that’s tightened up I’ll create a backup LDAP service in a jail on my other box and get 1-way replication working. Finally, a secondary KDC goes in that jail, and my setup will be done.

    My testing laptop running 15.0-RELEASE is reading from the directory and I can log in using my “firstuser” account on the laptop. All directory-specified items work: home directory, login shell, access to sudo privilages, etc.
 
Last edited:
Squaring the circle, because I feel a bit guilty about not posting a client config. Here's what got my test laptop integrated with the Kerberos+LDAP system:
  • # pkg install openldap26-client cyrus-sasl-gssapi krb5 pam_ldap sssd2 sudo-sssd
  • Copy your CA certificate(s) into /usr/share/certs/trusted/ and run # certctl rehash
  • Edit the following files:
    • /usr/local/etc/openldap/ldap.conf
      TLS_CACERTDIR /usr/share/certs/trusted/
      TLS_CACERT /usr/share/certs/trusted/intermediateca.mydomain.com.cert.pem
    • /etc/krb5.conf
      [logging]
      default = FILE:/var/log/krb5.log​
      [libdefaults]
      default_realm = MYDOMAIN.COM
      dns_lookup_realm = true
      dns_lookup_kdc = true
      kdc_timesync = 1
      ccache_type = 4
      forwardable = true
      proxiable = true
      fcc-mit-ticketflags = true​
      [realms]
      MYDOMAIN.COM = {​
      kdc = ldapjail.mydomain.com
      admin_server = ldapjail.mydomain.com
      default_domain = mydomain.com​
      }​
      [domain_realm]
      .mydomain.com = MYDOMAIN.COM
      mydomain.com = MYDOMAIN.COM​
    • /etc/nsswitch.conf
      group: files sss
      hosts: files dns
      netgroup: files sss
      networks: files
      passwd: files sss
      shells: files sss
      services: files sss
      protocols: files
      rpc: files
      sudoers: files sss
    • /usr/local/etc/sssd/sssd.conf
      [sssd]
      services= nss, pam, sudo
      config_file_version = 2
      domains = MYDOMAIN.COM
      debug_level=4

      [nss]
      shell_fallback=/bin/sh

      [sudo]
      debug_level=4

      [domain/MYDOMAIN.COM]
      debug_level=4
      cache_credentials = False
      enumerate = True
      id_provider = ldap
      sudo_provider = ldap
      ldap_uri = ldap://ldapjail.mydomain.com
      ldap_search_base = dc=mydomain,dc=com
      ldap_group_search_base = ou=groups,dc=mydomain,dc=com
      ldap_sudo_search_base = ou=SUDOers,dc=mydomain,dc=com
      ldap_sudo_full_refresh_interval = 86400
      ldap_sudo_smart_refresh = 3600
      ldap_schema = rfc2307bis
      ldap_user_object_class = domainAccount
      ldap_group_object_class = domainGroup
      ldap_group_member = member
      ldap_default_bind_dn = uid=ldapbinduser,ou=accounts,dc=mydomain,dc=com
      ldap_default_authtok = Plain_text_password_here
      ldap_id_use_start_tls = True
      ldap_tls_reqcert = demand
      ldap_tls_cacert = /usr/share/certs/trusted/intermediateca.mydomain.com.cert.pem
      ldap_tls_cacertdir = /usr/share/certs/trusted
      auth_provider = krb5
      chpass_provider = krb5
      krb5_server = ldapjail.mydomain.com
      krb5_kpasswd = ldapjail.mydomain.com
      krb5_realm = MYDOMAIN.COM
      create_homedir = False

      [pam]
      pam_passkey_auth = False
    • /etc/pam.d/sudo
      auth sufficient pam_unix.so no_warn
      auth sufficient pam_sss.so use_first_pass

      account required pam_unix.so no_warn use_first_pass

      session required pam_permit.so
    • /etc/pam.d/sddm
      auth sufficient pam_sss.so try_first_pass
      auth required pam_unix.so no_warn try_first_pass

      account required pam_unix.so
      account sufficient pam_sss.so

      password required pam_unix.so no_warn try_firts_pass
      password sufficient pam_sss.so

      session required pam_permit.so
      session optional pam_sss.so
    • Add sssd_enable="YES" to /etc/rc.conf
  • Reboot
I'm using SDDM, so obviously swap this out and modify as appropriate for whatever display manager you're using in your setup. Also, note that I've set create_homedir=False in /usr/local/etc/sssd/sssd.conf. I did this because I didn't have time to play around with the pam_zfs_key.so module that supports creation of encrypted /home/$user datasets on first login. Given the extremely low number of people using my systems (4 total, and 2 of those almost never), I'm fine with manually setting up home datasets for family before they can log on to a host. There really won't be that many hosts that allow local logon... if the situation ever changes I'll dig in and look at enabling automatic home folder / dataset creation, but for now I'll skip that potential headache.

Happy holidays!
 
Last edited:
Back
Top