FreeBSD + FreeIPA (via SSSD)

The following is what we did in order to utilize all of the benefits of a FreeIPA server (on Linux) with a FreeBSD client. The software packages needed are:

In order to ensure that net/openldap24-client-sasl is used, we added a line to /etc/make.conf:
Code:
WANT_OPENLDAP_SASL=yes

Once all software is installed, ensure the following directories exist:
  • /var/db/sss
  • /var/log/sssd

The base configuration needed for authentication, authorization, HBAC, and sudo (more on sudo to follow) is:
Code:
[domain/<domain_name>]
cache_credentials = True
krb5_store_password_if_offline = True
ipa_domain = <domain_name>
id_provider = ipa
auth_provider = ipa
access_provider = ipa
ipa_hostname = <fqdn>
chpass_provider = ipa
ipa_server = _srv_ #our FreeIPA server has DNS SRV entries
ldap_tls_cacert = <ldap tls CA cert location>
enumerate = True #to enumerate users and groups

[sssd]
enumerate = True
services = nss, pam, sudo
config_file_version = 2
domains = <domain_name>

[nss]

[pam]

[sudo]

The tricky part was getting sudo to work with host groups. FreeIPA keeps host groups in netgroups, and FreeBSD's support for netgroups is limited. One solution would have been to enable NIS services on the FreeIPA server so that we could use proper netgroups on FreeBSD clients. We didn't like that solution, so instead we wrote a script that pulls all netgroup data from FreeIPA and stores it in /etc/netgroup. We run the script every hour via cron.
Code:
#!/bin/sh
#
# Construct a netgroup file from LDAP hostgroup definitions.
# This is a hack for FreeBSD IPA clients because they can't get netgroup
# data through LDAP or sssd backends (lacking nsswitch/nsdb support).
#

PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
export PATH

progname=$(basename $0)
tmpf=$(mktemp)

trap "rm -f $tmpf" EXIT

ldapsearch -LLLx -H ldap://<ldap_server> \
           -b 'cn=hostgroups,cn=accounts,dc=<domain_name>' \
           '(objectClass=ipahostgroup)' cn member \
| while read line; do
  # new line between records; this means a record ended.
  if [ "$line" = "" ]; then
    # output netgroup line if we have members.
    if [ "$members" != "" ]; then
      echo "$groupname \\" >>$tmpf
      for host in $members; do
        echo " ($host, -, fxcorp) \\" >>$tmpf
      done
      echo "" >>$tmpf
    fi

    # reset data
    groupname=""
    members=""
    continue
  fi

  # parse "key: value" from LDAP
  key=${line%%: *}
  value=${line##*: }

  if [ "$key" = "dn" ]; then
    continue
  elif [ "$key" = "cn" ]; then
    groupname=$value
  elif [ "$key" = "member" ]; then
    host=${value%%,cn*}
    host=${host##fqdn=}
    members="$members $host"
  fi
done

if [ ! -s "$tmpf" ]; then
  echo "$progname: refusing to install an empty file, bailing" >&2
  exit 1
fi

install -m 0644 -o root -g wheel $tmpf /etc/netgroup
rc=$?

if [ $rc -ne 0 ]; then
  echo "$progname: error installing /etc/netgroup (rc = $rc)" >&2
  exit 2
fi

exit 0

We wrote a patch for pam_sss to support ignore_unknown_user. Without that support local users could authenticate when using SSSD for authentication. We submitted the patch upstream. It was accepted by the FreeIPA team and will hopefully be ported to FreeBSD soon. Our PAM configuration to support SSSD is:
Code:
#
# $FreeBSD: release/10.0.0/etc/pam.d/system 197769 2009-10-05 09:28:54Z des $
#
# System-wide defaults
#

# auth
auth sufficient pam_opie.so no_warn no_fake_prompts
auth requisite pam_opieaccess.so no_warn allow_local
auth sufficient pam_krb5.so no_warn try_first_pass
auth sufficient /usr/local/lib/pam_sss.so debug use_first_pass
auth required pam_unix.so no_warn try_first_pass

# account
account required pam_login_access.so
account required pam_unix.so
account required /usr/local/lib/pam_sss.so ignore_unknown_user

# session
#session optional pam_ssh.so want_agent
#session optional /usr/local/lib/pam_sss.so
session required pam_lastlog.so no_fail

# password
#password sufficient pam_krb5.so no_warn try_first_pass
password sufficient /usr/local/lib/pam_sss.so use_authtok
password required pam_unix.so no_warn try_first_pass

Code:
#
# $FreeBSD: release/10.0.0/etc/pam.d/sshd 197769 2009-10-05 09:28:54Z des $
#
# PAM configuration for the "sshd" service
#

# auth
auth sufficient pam_opie.so no_warn no_fake_prompts
auth requisite pam_opieaccess.so no_warn allow_local
auth sufficient pam_krb5.so no_warn try_first_pass
#auth sufficient pam_ssh.so no_warn try_first_pass
auth sufficient /usr/local/lib/pam_sss.so debug use_first_pass
auth required pam_unix.so no_warn try_first_pass

# account
account required pam_nologin.so
#account required pam_krb5.so
account required pam_login_access.so
account required pam_unix.so
account required /usr/local/lib/pam_sss.so ignore_unknown_user

# session
#session optional pam_ssh.so
#session required /usr/local/lib/pam_mkhomedir.so
session required pam_permit.so

# password
#password sufficient pam_krb5.so no_warn try_first_pass
password sufficient /usr/local/lib/pam_sss.so debug use_authtok
password required pam_unix.so no_warn try_first_pass

To let the system know what method to use for passwd, group, sudo, etc. we updated our /etc/nsswitch.conf:
Code:
#
# nsswitch.conf(5) - name service switch configuration file
# $FreeBSD: release/10.0.0/etc/nsswitch.conf 224765 2011-08-10 20:52:02Z dougb $
#
#group: compat
group: files sss
group_compat: nis
hosts: files dns
networks: files
#passwd: compat
passwd: files sss
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files
sudoers: sss files
netgroup: files

The final step was to create a kerberos keytab on the FreeIPA server and copy it over to our FreeBSD host. On the FreeIPA server we excecuted:
Code:
freeipa-server# ipa-host-add <fqdn>
freeipa-server# ipa-getkeytab -s <freeipa server hostname> -p host/<freebsd host fqdn> -k <location to export the keytab>

We then simply copied the keytab to /etc/krb5.keytab on our FreeBSD host.
 
Last edited by a moderator:
Thanks for the post, it seems to be the only post about FreeBSD - FreeIPA integration.

I set up everything as you advise, but get a problem: I can't locally log into my FreeBSD client (either as a local user or as an IPA user).

The problem is in this string in the /etc/pam.d/system file:
Code:
account required /usr/local/lib/pam_sss.so ignore_unknown_user
That string gives login errors, with or without the ignore_unknown_user part. The only solution I found for now is to comment that string out and add it explicitly into /etc/pam.d/login file. Then the local login process proceeds without errors.

You said: "We wrote a patch for pam_sss to support ignore_unknown_user." But the problem seems to be not in the ignore_unknown_user part, it is in the account required /usr/local/lib/pam_sss.so part.

Is it a bug in PAM/SSSD? Please advise, what to do now?
 
Last edited by a moderator:
Thanks for the post, it seems to be the only post about FreeBSD - FreeIPA integration.

I set up everything as you advise, but get a problem: I can't locally log into my FreeBSD client (either as a local user or as an IPA user).

The problem is in this string in the /etc/pam.d/system file:
Code:
account required /usr/local/lib/pam_sss.so ignore_unknown_user
That string gives login errors, with or without the ignore_unknown_user part. The only solution I found for now is to comment that string out and add it explicitly into /etc/pam.d/login file. Then the local login process proceeds without errors.

You said: "We wrote a patch for pam_sss to support ignore_unknown_user." But the problem seems to be not in the ignore_unknown_user part, it is in the account required /usr/local/lib/pam_sss.so part.

Is it a bug in PAM/SSSD? Please advise, what to do now?

I shared this problem at FreeIPA mailing lists, and Lukas Slebodnik helped to troubleshoot it:

You have a typo in pam.d/system
Here is a word-diff:
[-account-]{+acconut+} required /usr/local/lib/pam_sss.so ignore_unknown_user ignore_authinfo_unavail

It was my mistake (acconut instead of account), and a very simple one, but sometimes the simplest mistakes are hardest to find.

Another valuable advice Lukas gave was regarding comments in the /usr/local/etc/sssd/sssd.conf file, specifically this line:
Code:
enumerate = True #to enumerate users and groups

Just FYI, comments on the same line are treated as part of value i.e. not interpreted as comments.
...As for enumeration - it is not needed in 90% of cases so we recommend not to configure it.

With comments on the same line, sssd won't start. Another simple thing that causes headache.
 
It seems to me that a cleaner way than "--ignore-unknown-user" would be to port pam_localuser and put that as "sufficient" before pam_sss. (In my day job I'm a RHEL administrator, and my current employer uses the RH paid version of FreeIPA.)
 
I was able to successfully get this working based on some input from this page itself, so thanks to the contributors.

Here are my instructions.

Assumptions:

Successfully working FreeIPA servers named below:

ipa1.zone.example.com
ipa2.zone.example.com

Realm:

zone.example.com

Install the following packages:

pkg install -y cyrus-sasl cyrus-sasl-gssapi ding-libs libinotify nss \
openldap-sasl-client popt talloc tdb tevent cmocka \
lmdb gamin jansson libarchive libsunacl py37-iso8601 \
krb5 pam_mkhomedir c-ares

Compile and install the following in sequence:

For the builds below choose LMDB and GSSAPI-MIT options when the curses
menu appears after initiating the make command.

LDB14

cd /usr/ports/databases/ldb14
make
make install

Samba410

cd /usr/ports/net/samba410
make
make install

SSSD

cd /usr/ports/security/sssd
make
make install

Configure LDAP (on client host):

Add the following to /usr/local/etc/openldap/ldap.conf

BASE dc=zone,dc=example,dc=com
URI ldaps://ipa1.zone.example.com
SSL start_tls
SASL_NOCANON on
TLS_CACERT /usr/local/etc/sssd/cacert.crt
TLS_CACERTDIR /usr/local/etc/sssd

Get IPA cacert.crt file from IPA server (on client host):

mkdir -p /usr/local/etc/sssd
fetch http://ipa1.zone.example.com/ipa/config/ca.crt -o /usr/local/etc/sssd/cacert.crt

Configure the SSSD service:

Add the following content to /usr/local/etc/sssd/sssd.conf and change the "ipa_hostname" variable to the DNS resolvalble FQDN of the client host:

[domain/zone.example.com]
cache_credential = True
krb5_store_password_if_offline = True
ipa_domain = zone.example.com
id_provider = ipa
auth_provider = ipa
access_provider = ipa
ipa_hostname = <DNS resolvable hostname of this client host>
chpass_provider = ipa
ipa_server = _srv_, ipa1.zone.example.com
ldap_tls_cacert = /usr/local/etc/sssd/cacert.crt
entry_cache_timeout = 5
enumerate = True
ldap_sudo_search_base = ou=sudoers,dc=zone,dc=example,dc=com
krb5_keytab = /etc/krb5.keytab
debug_level = 3 # Granular logging 1-10
[sssd]
config_file_version = 2
services = nss, pam, sudo, ssh
domains = zone.example.com

[nss]
override_homedir = /usr/home/%u
override_shell = /bin/csh

[pam]

[sudo]

Add SSSD service start on powercycle:

Add the following entry to /etc/rc.conf

sssd_enable="YES"

Configure Kerberos Client

Add the following content to /etc/krb5.conf

[libdefaults]
default_realm = ZONE.EXAMPLE.COM
default_keytab_name = /etc/krb5.keytab
dns_lookup_realm = true
dns_lookup_kdc = true
forwardable = yes
rdns = false

[realms]
ZONE.EXAMPLE.COm = {
kdc = ipa1.zone.example.com
kdc = ipa2.zone.example.com
master_kdc = ipa1.zone.example.com
admin_server = ipa2.zone.example.com
default_domain = zone.example.com
pkinit_anchors = FILE:/usr/local/etc/sssd/cacert.crt
}

[domain_realm]
.zone.example.com = ZONE.EXAMPLE.COM
zone.example.com = ZONE.EXAMPLE.COM

[logging]
kdc = FILE:/var/log/krb5/krb5kdc.log
admin_server = FILE:/var/log/krb5/kadmin.log
kadmin_local = FILE:/var/log/krb5/kadmin_local.log
default = FILE:/var/log/krb5/krb5lib.log

Create /var/log/krb5 directory

mkdir /var/log/krb5

Add client host to the FreeIPA server

On the FreeIPA server add the client host

sudo su -
kinit <admin user>
ipa host-add <client fqdn>

Example:

sudo su -
kinit joecool
ipa host-add client1.zone.example.com

Store client keytab in a file

On the FreeIPA server get the clients keytab and store it in a file

ipa-getkeytab -p host/client1.zone.example.com -k clien1.zone.example.com.keytab

From the FreeIPA server copy the keytab file to client host

scp client1.zone.example.com.keytab user@client1.zone.example.com:~

On the client host move the keytab into its appropriate location and change the permissions (assuming user is user)

mv client1.zone.example.com.keytab /etc/krb5.keytab
chown root:wheel /etc/krb5.keytab
chmod 400 /etc/krb5.keytab

Verify if LDAP client is working

Run the following command(s) on the client host to verify if user can kinit

$ kinit <user>

Example:

root@freebsdtest:/usr/ports # kinit joecool
joecool@ZONE.EXAMPLE.COM's Password:

$ klist

Example:

$ klist
Credentials cache: FILE:/tmp/krb5cc_0
Principal: joecool@ZONE.EXAMPLE.COM

Issued Expires Principal
Jul 14 21:14:44 2020 Jul 15 07:14:44 2020 krbtgt/ZONE.EXAMPLE.COM@ZONE.EXAMPLE.COM

$ ldapsearch -Y GSSAPI

root@freebsdtest:/usr/ports # ldapsearch -Y GSSAPI
SASL/GSSAPI authentication started
SASL username: joecool@ZONE.EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
# extended LDIF
...(ouput continues)

Change SSSD config permissions

chmod 0600 /usr/local/etc/sssd/sssd.conf

Starting SSSD

On the client host machine start SSSD using the following command

# service sssd start

Configuring PAM

WARNING: Make sure you create a backup of these files in case you might
need them later. You have been warned. The author assumes no responsibility
if you are locked out of your system.

On the client host machine change the /etc/pam.d/sshd to the following

auth sufficient pam_opie.so no_warn no_fake_prompts
auth requisite pam_opieaccess.so no_warn allow_local
auth sufficient pam_krb5.so debug no_warn try_first_pass
auth sufficient /usr/local/lib/pam_sss.so use_first_pass
auth required pam_unix.so no_warn try_first_pass
account required pam_nologin.so
account required pam_login_access.so
account required pam_unix.so
account required /usr/local/lib/pam_sss.so ignore_unknown_user ignore_authinfo_unavail
session required /usr/local/lib/pam_mkhomedir.so
session required pam_permit.so
password sufficient /usr/local/lib/pam_sss.so use_authtok
password required pam_unix.so no_warn try_first_pass

On the client host machine change the /etc/pam.d/system to the following

auth sufficient pam_opie.so no_warn no_fake_prompts
auth requisite pam_opieaccess.so no_warn allow_local
auth sufficient /usr/local/lib/pam_sss.so use_first_pass
auth required pam_unix.so no_warn try_first_pass nullok
account required pam_login_access.so
account required pam_unix.so
account required /usr/local/lib/pam_sss.so ignore_unknown_user ignore_authinfo_unavail
session required pam_lastlog.so no_fail
session required /usr/local/lib/pam_mkhomedir.so
password sufficient /usr/local/lib/pam_sss.so use_authtok
password required pam_unix.so no_warn try_first_pass

Configuring nsswitch

WARNING: Make sure you create a backup of these files in case you might
need them later. You have been warned. The author assumes no responsiblity
if you are locked out of your system

On the client host machine change the /etc/nsswitch.conf to the following

group: files sss
group_compat: nis
hosts: files dns
netgroup: compat
networks: files
passwd: files sss
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files
sudoers: sss files

Use verification

On the client host, use the following command to check if IPA integration is working

$ id -a <your-FreeIPA-user>
$ getent passwd
$ getent group

Troubleshooting SSSD

To troubleshoot SSSD, issue the following command and watch its output

$ sudo sssd -i -c /usr/local/etc/sssd/sssd.conf -d6
 
Back
Top