Sssd-based authentication when simple bind isn't allowed

In our test environment, AD's LDAP server doesn't allow Simple Bind any more. I.e. this doesn't work:

ldapsearch -LLL  -H ldap://adsv01.tspace.mydomain.com -x -D testLookup -w 'tstJOINpwd' -E pr=1000/noprompt -b 'ou=mydomain,dc=tspace,dc=mydomain,dc=com'

But this works:

ldapsearch -LLL  -H ldap://adsv01.tspace.mydomain.com -U testLookup -w 'tstJOINpwd' -E pr=1000/noprompt -b 'ou=mydomain,dc=tspace,dc=mydomain,dc=com'

The client must use SASL. But sssd, according to its docs (and my experiments), doesn't support any other SASL mechanisms than GSSAPI. So sssd has to use a Kerberos ticket to authenticate to the LDAP server. (The AD servers are Windows Server 2008, btw.)

It took me the better part of a week to get sssd working in this situation, so I'm doing a separate section on it here, with two options for authentication.

[Note]Note

In this section, nfsserv-pc (192.168.3.163) is not the NFS server as it is in the rest of the chapter, it's just a test client.

  1. Configure Kerberos

    Edit krb5.conf

    [Note]Note

    Contrary to what the manpages say, the permitted_enctypes and default_tkt_enctypes are the only settings that have any effect at all, and the only place where they seem to work is in the libdefaults section. In the realms section, they have no effect, and in the appdefaults section they confuse Heimdal to the point of being broken.

    [libdefaults]
            default_realm = TSPACE.MYDOMAIN.NL
    
            kdc_timesync = 1
            forwardable = true
            proxiable = true
    
    	# Without these settings, sssd will fail, although kinit may still work
            permitted_enctypes = arcfour-hmac-md5 aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96
            default_tkt_enctypes = arcfour-hmac-md5 aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96
    
    # The following libdefaults parameters are only for Heimdal Kerberos.
            v4_instance_resolve = false
            v4_name_convert = {
                    host = {
                            rcmd = host
                            ftp = ftp
                    }
                    plain = {
                            something = something-else
                    }
            }
            fcc-mit-ticketflags = true
    
    [realms]
            TSPACE.MYDOMAIN.NL = {
                    kdc = adsv01.tspace.mydomain.com:88
                    kdc = adsv02.tspace.mydomain.com:88
                    kdc = adsv03.tspace.mydomain.com:88
                    default_domain = mydomain.com
            }
            ATHENA.MIT.EDU = {
                    kdc = kerberos.mit.edu:88
                    kdc = kerberos-1.mit.edu:88
                    kdc = kerberos-2.mit.edu:88
                    admin_server = kerberos.mit.edu
                    default_domain = mit.edu
            }
    
    [domain_realm]
            .mydomain.com = TSPACE.MYDOMAIN.NL
            mydomain.com = TSPACE.MYDOMAIN.NL
            .mit.edu = ATHENA.MIT.EDU
            mit.edu = ATHENA.MIT.EDU
            .media.mit.edu = MEDIA-LAB.MIT.EDU
            media.mit.edu = MEDIA-LAB.MIT.EDU
            .csail.mit.edu = CSAIL.MIT.EDU
            csail.mit.edu = CSAIL.MIT.EDU
            .whoi.edu = ATHENA.MIT.EDU
            whoi.edu = ATHENA.MIT.EDU
            .stanford.edu = stanford.edu
            .slac.stanford.edu = SLAC.STANFORD.EDU
    
    
    [login]
            krb4_convert = true
            krb4_get_tickets = false
    	  

  2. Configure SSSD, option 1

    This is option 1: the administrative account 'testLookup' authenticates against Kerberos to bind to LDAP.

    1. Put a key for the administrative account in the keytab

      This also serves to test whether Kerberos works.

      root@nfsserv-pc:~#  ktutil add --principal=testLookup --enctype=arcfour-hmac-md5 -w 'tstJOINpwd' --kvno=0
      root@nfsserv-pc:~# kinit -k testLookup

      These commands should work without error, and ktutil list and klist should show you the appropriate keys and tickets.

    2. Test with ldapsearch

      If you put in /etc/ldap/ldap.conf:

      <snip>
      # use invalid certs anyway
      TLS_REQCERT allow
      	      

      ... then this should succeed (and give some useful output):

      root@nfsserv-pc:~#  ldapsearch -H ldap://adsv01.tspace.mydomain.com -Y GSSAPI -U testLookup@TSPACE.MYDOMAIN.NL -E pr=1000/noprompt -b 'ou=mydomain,dc=tspace,dc=mydomain,dc=com' '(&(objectClass=person)(uidNumber=*))' SAMAccountName uid uidNumber

    3. sssd.conf

      Edit /etc/sssd/sssd.conf (chmod 600!):

      [sssd]
      config_file_version = 2
      domains = tspace.mydomain.com
      services = nss, pam
      
      [nss]
      # These are settings to reduce traffic. Will remove them on production system.
      enum_cache_timeout = 7200
      entry_cache_nowait_percentage = 50
      # default is 15
      entry_negative_timeout = 5
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      [pam]
      # default = 5, 300 is for calm testing.  Will remove them on production system.
      pam_id_timeout = 300
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      [domain/tspace.mydomain.com]
      description = LDAP domain with AD server
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      min_id = 10000000
      
      cache_credentials = true
      enumerate = true
      
      id_provider = ldap
      auth_provider = krb5
      chpass_provider = none
      #access_provider = ldap
      access_provider = permit
      
      #dns_discovery_domain = tspace.mydomain.com
      
      # Use only one ldap server. Comment out to use service discovery on production system. (Needs DNS SRV entries.)
      ldap_uri = ldap://adsv01.tspace.mydomain.com
      #ldap_uri = ldap://adsv01.tspace.mydomain.com,ldap://adsv02.tspace.mydomain.com,ldap://adsv03.tspace.mydomain.com
      
      ldap_tls_reqcert = allow
      
      # Uncomment if using SASL/GSSAPI to bind and a valid /etc/krb5.keytab exists
      ldap_sasl_mech = GSSAPI
      # Uncomment and adjust if the default principal host/fqdn@REALM is not available
      ldap_sasl_authid = testLookup
      # These 3 needed against pre-authentication failure.
      krb5_fast_principal = testLookup
      krb5_use_fast = try
      krb5_canonicalize = false
      
      #These are don't cares:
      #krb5_renewable_lifetime = 3600
      #krb5_lifetime = 3600
      #krb5_validate = true
      
      ldap_schema = rfc2307bis
      
      ldap_search_base = dc=tspace,dc=mydomain,dc=com
      
      # It looks like the ?sub?search notation is also accepted:
      ldap_user_search_base = ou=users,ou=mydomain,dc=tspace,dc=mydomain,dc=com?sub?uidNumber=*
      #ldap_user_search_base = ou=users,ou=mydomain,dc=tspace,dc=mydomain,dc=com
      ldap_user_object_class = person
      
      #msSFU30Name? Needed because not all POSIX attributes set (admins still working on that)
      ldap_user_name = sAMAccountName
      ldap_user_home_directory = unixHomeDirectory
      ldap_user_principal = userPrincipalName
      
      # Below an ugly kludge to work around the group database still missing from AD.
      # FixMe: add posix groups to AD
      ldap_group_search_base = ou=groups,ou=mydomain,dc=tspace,dc=mydomain,dc=com?sub?gidNumber=*
      ldap_group_object_class = person
      ldap_group_name = sAMAccountName
      ldap_group_gid_number = gidNumber
      ldap_group_member = sAMAccountName
      
      ldap_access_order = expire
      ldap_account_expire_policy = ad
      ldap_force_upper_case_realm = true
      
      ldap_pwd_policy = none
      
      # Service detection works here
      krb5_realm = TSPACE.MYDOMAIN.NL
      #krb5_server = adsv01.tspace.mydomain.com adsv02.tspace.mydomain.com adsv03.tspace.mydomain.com
      
      # Don't forget the trailing newline
      	      

      Restarting sssd and tailing /var/log/sssd/sssd_tspace.mydomain.com.log should show you succesful communication between sssd and the LDAP server.

  3. Configure SSSD, option 2

    This is the alternative to the previous step: the machine is joined to the AD domain, it gets its own Kerberos host key, and that host key authenticates for the LDAP bind.

    1. Join the AD domain

      Get a key for the administrative account that you need to have:

      root@nfsserv-pc:~# ktutil add --principal=unixJOINer@TSPACE.MYDOMAIN.NL --enctype=AES256-CTS-HMAC-SHA1-96 -w 'tstJOINpwd' --kvno=0

      Be aware that ktutil doesn't test anything. If you provide the wrong password, it won't complain.

      Now use that key to authenticate:

      root@nfsserv-pc:~# kinit -k unixJOINer

      And finally, join the domain by having msktutil create an LDAP entry and keys for it:

      root@nfsserv-pc:~# msktutil --create --computer-name $(hostname) --base "ou=extra workstations,ou=computers,ou=mydomain" --user-creds-only --verbose

      If you don't have msktutil, see my note on msktutil and the next section, .

    2. sssd.conf

      Put in /etc/sssd/sssd.conf (chmod 600!):

      [sssd]
      config_file_version = 2
      domains = tspace.mydomain.com
      services = nss, pam
      
      [nss]
      # These are settings to reduce traffic. Will remove them on production system.
      enum_cache_timeout = 7200
      entry_cache_nowait_percentage = 50
      # default is 15
      entry_negative_timeout = 5
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      [pam]
      # default = 5, 300 is for calm testing.  Will remove them on production system.
      pam_id_timeout = 300
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      [domain/tspace.mydomain.com]
      description = LDAP domain with AD server
      
      # Remove this on production system.
      debug_level = 0x04f0
      
      min_id = 10000000
      
      cache_credentials = true
      enumerate = true
      
      id_provider = ldap
      auth_provider = krb5
      chpass_provider = none
      #access_provider = ldap
      access_provider = permit
      
      #dns_discovery_domain = tspace.mydomain.com
      
      # Use only one ldap server. Comment out to use service discovery on production system. (Needs DNS SRV entries.)
      ldap_uri = ldap://adsv01.tspace.mydomain.com
      #ldap_uri = ldap://adsv01.tspace.mydomain.com,ldap://adsv02.tspace.mydomain.com,ldap://adsv03.tspace.mydomain.com
      
      ldap_tls_reqcert = allow
      
      # Uncomment if using SASL/GSSAPI to bind and a valid /etc/krb5.keytab exists
      ldap_sasl_mech = GSSAPI
      
      #These are don't cares:
      #krb5_renewable_lifetime = 3600
      #krb5_lifetime = 3600
      #krb5_validate = true
      
      ldap_schema = rfc2307bis
      
      ldap_search_base = dc=tspace,dc=mydomain,dc=com
      
      # It looks like the ?sub?search notation is also accepted:
      ldap_user_search_base = ou=users,ou=mydomain,dc=tspace,dc=mydomain,dc=com?sub?uidNumber=*
      #ldap_user_search_base = ou=users,ou=mydomain,dc=tspace,dc=mydomain,dc=com
      ldap_user_object_class = person
      
      #msSFU30Name? Needed because not all POSIX attributes set (admins still working on that)
      ldap_user_name = sAMAccountName
      ldap_user_home_directory = unixHomeDirectory
      ldap_user_principal = userPrincipalName
      
      # Below an ugly kludge to work around the group database still missing from AD.
      # FixMe: add posix groups to AD
      ldap_group_search_base = ou=groups,ou=mydomain,dc=tspace,dc=mydomain,dc=com?sub?gidNumber=*
      ldap_group_object_class = person
      ldap_group_name = sAMAccountName
      ldap_group_gid_number = gidNumber
      ldap_group_member = sAMAccountName
      
      ldap_access_order = expire
      ldap_account_expire_policy = ad
      ldap_force_upper_case_realm = true
      
      ldap_pwd_policy = none
      
      # Service detection works here
      krb5_realm = TSPACE.MYDOMAIN.NL
      #krb5_server = adsv01.tspace.mydomain.com adsv02.tspace.mydomain.com adsv03.tspace.mydomain.com
      
      # Don't forget the trailing newline
      	      

  4. Restart the sssd daemon

    If you tail /var/log/sssd/sssd_tspace.mydomain.com.log, you should see lots of activity.

  5. Configure nss

    As above, put in /etc/nsswitch.conf:

    passwd:         compat sss
    group:          compat sss
    shadow:         compat sss
    
    hosts:          files dns
    networks:       files
    
    protocols:      db files
    services:       db files
    ethers:         db files
    rpc:            db files
    
    netgroup:       nis sss
    	  

  6. More testing

    Logging in using AD accounts should also work.

1. Kinit works for testLookup, but not for U1234567.
2. I get Preauthentication failed in the logs.

1.

Kinit works for testLookup, but not for U1234567.

The user accounts get their properties set in a different way than the administrative accounts, so one needs to test kinit for u1234567 separately. Maybe the user accounts haven't been imported, or not enabled.

2.

I get Preauthentication failed in the logs.

I got a lot of that too. When using a service account to authenticate for LDAP bind, as per option 1 above, I needed these options in the [domain/tspace.mydomain.com] section of /etc/sssd.conf:

ldap_sasl_authid = testLookup
# These 3 needed against pre-authentication failure.
krb5_fast_principal = testLookup
krb5_use_fast = try
krb5_canonicalize = false
	      

And no, that krb5_fast_principal is not in the manpage. And yes, it does have effect.