Integrating FreeBSD w/ FreeIPA/SSSD
Prerequisites and Requirements
- Client must have A & PTR records in DNS
- Client hostname must be set to it’s FQDN
- Client host table must include a matching FQDN/IP address record
- Client should have a so-called break-glass UNIX account
- Binary package repository w/ packages supporting FreeIPA
- A Kerberos keytab for the client
It is unknown what behavior results due the lack of meeting requirements 1 – 3.
The break-glass account is a local, UNIX-based account on the client filtered via SSSD policy/config. It will not use SSSD for authentication and it can be arbitrary in nature, so long as it is filtered. This is useful when remote access is lost due to service outage or similar. It is also useful to open a session to this user while this process is executed.
Client services won’t start and the client will not authenticate against FreeIPA without the modules installed with the binary packages without having a prepared repository. This repository must contain the requisite packages compiled with the custom options as described below.
Finally, the host keytab file is generated in the FreeIPA infrastructure during host enrollment. The keytab file can be retrieved from the IPA server using ipa-getkeytab. Securely copy this file to the client with mode 0600 to /etc/krb5.keytab.
Overview
The end goal of this work is to integrate FreeBSD into the FreeIPA architecture utilizing remote ssh and sudo. No other authentication or authorization methods were attempted. Additionally, this post is being constructed from notes and memory. Hopefully nothing has been missed and everything is accurate, but it is possible this is not the case. Help me keep this correct, if necessary.
There are two high level tasks to be completed; Generate the binary package repository with FreeIPA-enabled packages and client installation/configuration. The binary package repository only needs to be done once. Ongoing maintenance of binary repositories is necessary to make newer versions available when necessary.
Building The Binary Package Repository
Execute this process to build a binary package repository containing the necessary packages w/ custom options enabled. It is assumed a pre-existing Poudriere build and distribution environment is available.
$jail_id is the Poudriere jail ID within which the repo is to be built
$portstree_id is the Poudrere Ports tree ID on which to execute the build
$ cat >> $jail_id-make.conf <EOF WANT_OPENLDAP_SASL=YES WITH_GSSAPI=YES EOF $ cat > pkg_list <<EOF security/cyrus-sasl2-gssapi security/sssd security/sudo security/openssh-portable security/pam_mkhomedir EOF $ poudriere options -c -n -p $portstree_id security/sssd security/sudo security/openssh-portable $ poudriere bulk -f pkg_list -j $jail_id -p $portstree_id
Step 3 presents users with dialog boxes populated with various radio options. A null radio is an unselected option while options denoted by an “X” are selected. Configure options for each of the packages as described below:
security/sssd: Enable SMB (Builds and installs the IPA provider)
security/sudo: Enable SSSD backend
security/openssh-portable: Enable MIT Kerberos
Installing/Configuring The Client
The procedure below includes commands executed on the command line as well as descriptions of operations needed to be completed such as editing or creating a file. Several commands and/or files include hostnames inherently describing a dependency on DNS. Open a standby shell in order to maintain access to the system during this operation as access to the system can be halted in executing it.
$cblrserver is the hostname or IP of the server from which to grab content. This is simply an HTTP accessible resource.
$ipaserver is the hostname or IP of the IPA server with which to communicate
$domain is the domain of the target host
$hostname is the fully qualified hostname
1) Configure the binary package repository and install the required packages:
$ cat > /etc/pkg/ipa.conf <<-EOF ipa: { url: "http://$cblrserver/cobbler/repo_mirror/freebsd-10_0-amd64-pkgs-ipa", mirror_type: "none", enabled: yes } EOF $ pkg update -f $ mkdir -p /etc/ipa /usr/compat/linux/proc /var/log/sssd /var/run/sss/private /var/db/sss $ pkg install -y -r ipa cyrus-sasl-gssapi sssd sudo openssh-portable pam_mkhomedir
2) Configure Kerberos and SSSD
$ cat /etc/krb5.conf [libdefaults] default_realm = EXAMPLE.COM default_keytab_name = FILE:/etc/krb5.keytab default_tkt_enctypes = aes256-cts des-cbc-crc aes128-cts arcfour-hmac default_tgs_enctypes = aes256-cts des-cbc-crc aes128-cts arcfour-hmac dns_lookup_realm = false dns_lookup_kdc = false rdns = false ticket_lifetime = 24h forwardable = yes [realms] EXAMPLE.COM = { kdc = $ipaserver:88 master_kdc = $ipaserver:88 admin_server = $ipaserver:749 default_domain = $domain pkinit_anchors = FILE:/etc/ipa/ca.crt } [domain_realm] .example.com = 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 [edit] $ $ $ cat /usr/local/etc/sssd/sssd.conf [domain/$domain] #debug_level = 9 cache_credentials = True krb5_store_password_if_offline = True krb5_realm = EXAMPLE.COM ipa_domain = $domain id_provider = ipa auth_provider = ipa access_provider = ipa ipa_hostname = $hostname chpass_provider = ipa ipa_server = _srv_, $ipaserver ldap_tls_cacert = /etc/ipa/ca.crt krb5_keytab = /etc/krb5.keytab [sssd] services = nss, pam, ssh, sudo config_file_version = 2 domains = $domain [nss] filter_users = root,smash homedir_substring = /home [pam] [sudo] [ssh] $ $
3) Configure NSS similarly to the below:
$ cat /etc/nsswitch.conf group: files sss group_compat: nis hosts: files dns networks: files passwd: files sss passwd_compat: nis shells: files services: compat services_compat: nis protocols: files rpc: files sudoers: files sss netgroup: files
4) Configure and mount the linproc filesystem
# echo "linproc /usr/compat/linux/proc linprocfs rw 0 0" >> /etc/fstab # mount -a
5) Configure rc.conf and domainname
$ cat /etc/rc.conf rpcbind_enable=“YES” sshd_enable=“NO” openssh_enable="YES" ntpd_enable="YES" nisdomainname=“example.com” sssd_enable="YES" $ sudo domainname example.com
6) Configure openssl-portable similarly to:
$ cat /usr/local/etc/ssh/sshd_config ... GSSAPIAuthentication yes GSSAPICleanupCredentials yes PasswordAuthentication yes ...
7) Download the CA certificate
$ wget -O /etc/ipa/ca.crt http://$ipaserver/ipa/config/ca.crt
8) Configure PAM according to these configs:
$ cat /etc/pam.d/sshd # 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 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 sufficient /usr/local/lib/pam_sss.so ignore_unknown_user account required pam_unix.so # session #session optional pam_ssh.so want_agent 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 password required pam_unix.so no_warn try_first_pass $ $ $ cat /etc/pam.d/system # 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 auth required pam_unix.so no_warn try_first_pass nullok # account #account required pam_krb5.so account sufficient /usr/local/lib/pam_sss.so ignore_unknown_user account required pam_login_access.so account required pam_unix.so # session #session optional pam_ssh.so want_agent 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 password required pam_unix.so no_warn try_first_pass
9) Create /etc/netgroup with the following script. Set this script to run via cron to rebuild the file periodically.
This script is ported from one of the references internally to update /etc/netgroup locally on FreeBSD hosts. LDAPSRV is the hostname or IP of the LDAP server to query. This is generally the same as the IPA servers internally. Executing this script via cron will keep the file updated.
#!/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 LDAPSRV=ipa.example.com export PATH progname=$(basename $0) tmpf=$(mktemp) trap "rm -f $tmpf" EXIT ldapsearch -LLLx -H ldap://${LDAPSRV} \ -b 'dc=example,dc=com' \ '(objectClass=$netgroup)' cn $netgroupobj \ | 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 \\" >>$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" = "$netgroupobj" ]; 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
10) Restart services or reboot
$ sudo service sssd start $ sudo service sshd stop &amp;&amp; sudo service openssh start
Upon completion of this procedure, the target host has been configured to communicate with the authentication and authorization frameworks. Reboot is not required, but certainly recommended.
References
Disclaimer
Data and information described on this blog are for informational purposes only. The author of this blog provides no warranty/guarantee, expressed or implied, that this data and information will function as described here. Readers are expected to exercise due diligence when researching, developing, and deploying techniques and methods for use within their environments.
Comments posted are the explicit opinions of the comment poster themselves and does not necessarily reflect the views and opinions of the author of this blog.
