SSSD
SSSD stands for System Security Services Daemon and it’s actually a collection of daemons that handle authentication, authorization, and user and group information from a variety of network sources. At its core it has support for:
- Active Directory
- LDAP
- Kerberos
SSSD provides PAM and NSS modules to integrate these remote sources into your system and allow remote users to login and be recognized as valid users, including group membership. To allow for disconnected operation, SSSD also can also cache this information, so that users can continue to login in the event of a network failure, or other problem of the same sort.
This guide will focus on the most common scenarios where SSSD is deployed.
SSSD and Active Directory
This section describes the use of sssd to authenticate user logins against an Active Directory via using sssd’s “ad” provider. At the end, Active Directory users will be able to login on the host using their AD credentials. Group membership will also be maintained.
Prerequisites, Assumptions, and Requirements
-
This guide does not explain Active Directory, how it works, how to set one up, or how to maintain it.
-
This guide assumes that a working Active Directory domain is already configured and you have access to the credentials to join a machine to that domain.
-
The domain controller is acting as an authoritative DNS server for the domain.
-
The domain controller is the primary DNS resolver (check with
systemd-resolve --status
) -
System time is correct and in sync, maintained via a service like chrony or ntp
-
The domain used in this example is
ad1.example.com
.
Software Installation
Install the following packages:
sudo apt install sssd-ad sssd-tools realmd adcli
Join the domain
We will use the realm
command, from the realmd
package, to join the domain and create the sssd configuration.
Let’s verify the domain is discoverable via DNS:
$ sudo realm -v discover ad1.example.com
* Resolving: _ldap._tcp.ad1.example.com
* Performing LDAP DSE lookup on: 10.51.0.5
* Successfully discovered: ad1.example.com
ad1.example.com
type: kerberos
realm-name: AD1.EXAMPLE.COM
domain-name: ad1.example.com
configured: no
server-software: active-directory
client-software: sssd
required-package: sssd-tools
required-package: sssd
required-package: libnss-sss
required-package: libpam-sss
required-package: adcli
required-package: samba-common-bin
This performs several checks and determines the best software stack to use with sssd. sssd can install the missing packages via packagekit, but we installed them already previously.
Now let’s join the domain:
$ sudo realm join ad1.example.com
Password for Administrator:
That was quite uneventful. If you want to see what it was doing, pass the -v
option:
$ sudo realm join -v ad1.example.com
* Resolving: _ldap._tcp.ad1.example.com
* Performing LDAP DSE lookup on: 10.51.0.5
* Successfully discovered: ad1.example.com
Password for Administrator:
* Unconditionally checking packages
* Resolving required packages
* LANG=C /usr/sbin/adcli join --verbose --domain ad1.example.com --domain-realm AD1.EXAMPLE.COM --domain-controller 10.51.0.5 --login-type user --login-user Administrator --stdin-password
* Using domain name: ad1.example.com
* Calculated computer account name from fqdn: AD-CLIENT
* Using domain realm: ad1.example.com
* Sending NetLogon ping to domain controller: 10.51.0.5
* Received NetLogon info from: SERVER1.ad1.example.com
* Wrote out krb5.conf snippet to /var/cache/realmd/adcli-krb5-hUfTUg/krb5.d/adcli-krb5-conf-hv2kzi
* Authenticated as user: Administrator@AD1.EXAMPLE.COM
* Looked up short domain name: AD1
* Looked up domain SID: S-1-5-21-2660147319-831819607-3409034899
* Using fully qualified name: ad-client.ad1.example.com
* Using domain name: ad1.example.com
* Using computer account name: AD-CLIENT
* Using domain realm: ad1.example.com
* Calculated computer account name from fqdn: AD-CLIENT
* Generated 120 character computer password
* Using keytab: FILE:/etc/krb5.keytab
* Found computer account for AD-CLIENT$ at: CN=AD-CLIENT,CN=Computers,DC=ad1,DC=example,DC=com
* Sending NetLogon ping to domain controller: 10.51.0.5
* Received NetLogon info from: SERVER1.ad1.example.com
* Set computer password
* Retrieved kvno '3' for computer account in directory: CN=AD-CLIENT,CN=Computers,DC=ad1,DC=example,DC=com
* Checking RestrictedKrbHost/ad-client.ad1.example.com
* Added RestrictedKrbHost/ad-client.ad1.example.com
* Checking RestrictedKrbHost/AD-CLIENT
* Added RestrictedKrbHost/AD-CLIENT
* Checking host/ad-client.ad1.example.com
* Added host/ad-client.ad1.example.com
* Checking host/AD-CLIENT
* Added host/AD-CLIENT
* Discovered which keytab salt to use
* Added the entries to the keytab: AD-CLIENT$@AD1.EXAMPLE.COM: FILE:/etc/krb5.keytab
* Added the entries to the keytab: host/AD-CLIENT@AD1.EXAMPLE.COM: FILE:/etc/krb5.keytab
* Added the entries to the keytab: host/ad-client.ad1.example.com@AD1.EXAMPLE.COM: FILE:/etc/krb5.keytab
* Added the entries to the keytab: RestrictedKrbHost/AD-CLIENT@AD1.EXAMPLE.COM: FILE:/etc/krb5.keytab
* Added the entries to the keytab: RestrictedKrbHost/ad-client.ad1.example.com@AD1.EXAMPLE.COM: FILE:/etc/krb5.keytab
* /usr/sbin/update-rc.d sssd enable
* /usr/sbin/service sssd restart
* Successfully enrolled machine in realm
By default, realm will use the Administrator account of the domain to request the join. If you need to use another account, pass it to the tool with the -U
option.
Another popular way of joining a domain is using an OTP, or One Time Password, token. For that, use the --one-time-password
option.
SSSD Configuration
The realm tool already took care of creating an sssd configuration, adding the pam and nss modules, and starting the necessary services.
Let’s take a look at /etc/sssd/sssd.conf
:
[sssd]
domains = ad1.example.com
config_file_version = 2
services = nss, pam
[domain/ad1.example.com]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = AD1.EXAMPLE.COM
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u@%d
ad_domain = ad1.example.com
use_fully_qualified_names = True
ldap_id_mapping = True
access_provider = ad
Note
Something very important to remember is that this file must have permissions 0600 and ownership root:root, or else sssd won’t start!
Let’s highlight a few things from this config:
- cache_credentials: this allows logins when the AD server is unreachable
- home directory: it’s by default
/home/<user>@<domain>
. For example, the AD user john will have a home directory of /home/john@ad1.example.com - use_fully_qualified_names: users will be of the form user@domain, not just user. This should only be changed if you are certain no other domains will ever join the AD forest, via one of the several possible trust relationships
Automatic home directory creation
What the realm
tool didn’t do for us is setup pam_mkhomedir
, so that network users can get a home directory when they login. This remaining step can be done by running the following command:
sudo pam-auth-update --enable mkhomedir
Checks
You should now be able to fetch information about AD users. In this example, John Smith is an AD user:
$ getent passwd john@ad1.example.com
john@ad1.example.com:*:1725801106:1725800513:John Smith:/home/john@ad1.example.com:/bin/bash
Let’s see his groups:
$ groups john@ad1.example.com
john@ad1.example.com : domain users@ad1.example.com engineering@ad1.example.com
Note
If you just changed the group membership of a user, it may be a while before sssd notices due to caching.
Finally, how about we try a login:
$ sudo login
ad-client login: john@ad1.example.com
Password:
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-24-generic x86_64)
...
Creating directory '/home/john@ad1.example.com'.
john@ad1.example.com@ad-client:~$
Notice how the home directory was automatically created.
You can also use ssh, but note that the command will look a bit funny because of the multiple @ signs:
$ ssh john@ad1.example.com@10.51.0.11
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-24-generic x86_64)
(...)
Last login: Thu Apr 16 21:22:55 2020
john@ad1.example.com@ad-client:~$
Note
In the ssh example, public key authentication was used, so no password was required. Remember that ssh password authentication is by default disabled in
/etc/ssh/sshd_config
.
Kerberos Tickets
If you install krb5-user
, your AD users will also get a kerberos ticket upon logging in:
john@ad1.example.com@ad-client:~$ klist
Ticket cache: FILE:/tmp/krb5cc_1725801106_9UxVIz
Default principal: john@AD1.EXAMPLE.COM
Valid starting Expires Service principal
04/16/20 21:32:12 04/17/20 07:32:12 krbtgt/AD1.EXAMPLE.COM@AD1.EXAMPLE.COM
renew until 04/17/20 21:32:12
Note
realm also configured
/etc/krb5.conf
for you, so there should be no further configuration prompts when installingkrb5-user
Let’s test with smbclient using kerberos authentication to list he shares of the domain controller:
john@ad1.example.com@ad-client:~$ smbclient -k -L server1.ad1.example.com
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
SMB1 disabled -- no workgroup available
Notice how we now have a ticket for the cifs service, which was used for the share list above:
john@ad1.example.com@ad-client:~$ klist
Ticket cache: FILE:/tmp/krb5cc_1725801106_9UxVIz
Default principal: john@AD1.EXAMPLE.COM
Valid starting Expires Service principal
04/16/20 21:32:12 04/17/20 07:32:12 krbtgt/AD1.EXAMPLE.COM@AD1.EXAMPLE.COM
renew until 04/17/20 21:32:12
04/16/20 21:32:21 04/17/20 07:32:12 cifs/server1.ad1.example.com@AD1.EXAMPLE.COM
Desktop Ubuntu Authentication
The desktop login only shows local users in the list to pick from, and that’s on purpose.
To login with an Active Directory user for the first time, follow these steps:
- click on the “Not listed?” option:
- type in the login name followed by the password:
- the next time you login, the AD user will be listed as if it was a local user:
Resources
SSSD and LDAP
SSSD can also use LDAP for authentication, authorization, and user/group information. In this section we will configure a host to authenticate users from an OpenLDAP directory.
Prerequisites, Assumptions, and Requirements
For this setup, we need:
- an existing OpenLDAP server with SSL enabled and using the RFC2307 schema for users and groups
- a client host where we will install the necessary tools and login as an user from the LDAP server
Software Installation
Install the following packages:
sudo apt install sssd-ldap ldap-utils
SSSD Configuration
Create the /etc/sssd/sssd.conf
configuration file, with permissions 0600 and ownership root:root, and this content:
[sssd]
config_file_version = 2
domains = example.com
[domain/example.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://ldap01.example.com
cache_credentials = True
ldap_search_base = dc=example,dc=com
Make sure to start the sssd service:
sudo systemctl start sssd.service
Note
sssd will use START_TLS by default for authentication requests against the LDAP server (the auth_provider), but not for the id_provider. If you want to also enable START_TLS for the id_provider, specify
ldap_id_use_start_tls = true
.
Automatic home directory creation
To enable automatic home directory creation, run the following command:
sudo pam-auth-update --enable mkhomedir
Check SSL setup on the client
The client must be able to use START_TLS when connecting to the LDAP server, with full certificate checking. This means:
- the client host knows and trusts the CA that signed the LDAP server certificate
- the server certificate was issued for the correct host (
ldap01.example.com
in this guide) - the time is correct on all hosts performing the TLS connection
- and, of course, that neither certificate (CA or server’s) expired
If using a custom CA, an easy way to have a host trust it is to place it in /usr/local/share/ca-certificates/
with a .crt
extension and run sudo update-ca-certificates
.
Alternatively, you can edit /etc/ldap/ldap.conf
and point TLS_CACERT
to the CA public key file.
Note
You may have to restart
sssd
after these changes:sudo systemctl restart sssd
Once that is all done, check that you can connect to the LDAP server using verified SSL connections:
$ ldapwhoami -x -ZZ -h ldap01.example.com
anonymous
The -ZZ
parameter tells the tool to use START_TLS, and that it must not fail. If you have LDAP logging enabled on the server, it will show something like this:
slapd[779]: conn=1032 op=0 STARTTLS
slapd[779]: conn=1032 op=0 RESULT oid= err=0 text=
slapd[779]: conn=1032 fd=15 TLS established tls_ssf=256 ssf=256
slapd[779]: conn=1032 op=1 BIND dn="" method=128
slapd[779]: conn=1032 op=1 RESULT tag=97 err=0 text=
slapd[779]: conn=1032 op=2 EXT oid=1.3.6.1.4.1.4203.1.11.3
slapd[779]: conn=1032 op=2 WHOAMI
slapd[779]: conn=1032 op=2 RESULT oid= err=0 text=
START_TLS with err=0 and TLS established is what we want to see there, and, of course, the WHOAMI extended operation.
Final verification
In this example, the LDAP server has the following user and group entry we are going to use for testing:
dn: uid=john,ou=People,dc=example,dc=com
uid: john
objectClass: inetOrgPerson
objectClass: posixAccount
cn: John Smith
sn: Smith
givenName: John
mail: john@example.com
userPassword: johnsecret
uidNumber: 10001
gidNumber: 10001
loginShell: /bin/bash
homeDirectory: /home/john
dn: cn=john,ou=Group,dc=example,dc=com
cn: john
objectClass: posixGroup
gidNumber: 10001
memberUid: john
dn: cn=Engineering,ou=Group,dc=example,dc=com
cn: Engineering
objectClass: posixGroup
gidNumber: 10100
memberUid: john
The user john should be known to the system:
ubuntu@ldap-client:~$ getent passwd john
john:*:10001:10001:John Smith:/home/john:/bin/bash
ubuntu@ldap-client:~$ id john
uid=10001(john) gid=10001(john) groups=10001(john),10100(Engineering)
And we should be able to authenticate as john:
ubuntu@ldap-client:~$ sudo login
ldap-client login: john
Password:
Welcome to Ubuntu Focal Fossa (development branch) (GNU/Linux 5.4.0-24-generic x86_64)
(...)
Creating directory '/home/john'.
john@ldap-client:~$
SSSD, LDAP and Kerberos
Finally, we can mix it all together in a setup that is very similar to Active Directory in terms of the technologies used: use LDAP for users and groups, and Kerberos for authentication.
Prerequisites, Assumptions, and Requirements
For this setup, we will need:
- an existing OpenLDAP server using the RFC2307 schema for users and groups. SSL support is recommended, but not strictly necessary because authentication in this setup is being done via Kerberos, and not LDAP.
- a Kerberos server. It doesn’t have to be using the OpenLDAP backend
- a client host where we will install and configure SSSD
Software Installation
On the client host, install the following packages:
sudo apt install sssd-ldap sssd-krb5 ldap-utils krb5-user
You may be asked about the default Kerberos realm. For this guide, we are using EXAMPLE.COM
.
At this point, you should alreaedy be able to obtain tickets from your Kerberos server, assuming DNS records point at it like explained elsewhere in this guide:
$ kinit ubuntu
Password for ubuntu@EXAMPLE.COM:
ubuntu@ldap-krb-client:~$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: ubuntu@EXAMPLE.COM
Valid starting Expires Service principal
04/17/20 19:51:06 04/18/20 05:51:06 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 04/18/20 19:51:05
But we want to be able to login as an LDAP user, authenticated via Kerberos. Let’s continue with the configuration.
SSSD Configuration
Create the /etc/sssd/sssd.conf
configuration file, with permissions 0600 and ownership root:root, and this content:
[sssd]
config_file_version = 2
domains = example.com
[domain/example.com]
id_provider = ldap
ldap_uri = ldap://ldap01.example.com
ldap_search_base = dc=example,dc=com
auth_provider = krb5
krb5_server = kdc01.example.com,kdc02.example.com
krb5_kpasswd = kdc01.example.com
krb5_realm = EXAMPLE.COM
cache_credentials = True
This example uses two KDCs, which made it necessary to also specify the krb5_kpasswd server because the second KDC is a replica and is not running the admin server.
Start the sssd service:
sudo systemctl start sssd.service
Automatic home directory creation
To enable automatic home directory creation, run the following command:
sudo pam-auth-update --enable mkhomedir
Final verification
In this example, the LDAP server has the following user and group entry we are going to use for testing:
dn: uid=john,ou=People,dc=example,dc=com
uid: john
objectClass: inetOrgPerson
objectClass: posixAccount
cn: John Smith
sn: Smith
givenName: John
mail: john@example.com
uidNumber: 10001
gidNumber: 10001
loginShell: /bin/bash
homeDirectory: /home/john
dn: cn=john,ou=Group,dc=example,dc=com
cn: john
objectClass: posixGroup
gidNumber: 10001
memberUid: john
dn: cn=Engineering,ou=Group,dc=example,dc=com
cn: Engineering
objectClass: posixGroup
gidNumber: 10100
memberUid: john
Note how the john user has no userPassword attribute.
The user john should be known to the system:
ubuntu@ldap-client:~$ getent passwd john
john:*:10001:10001:John Smith:/home/john:/bin/bash
ubuntu@ldap-client:~$ id john
uid=10001(john) gid=10001(john) groups=10001(john),10100(Engineering)
Let’s try a login as this user:
ubuntu@ldap-krb-client:~$ sudo login
ldap-krb-client login: john
Password:
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-24-generic x86_64)
(...)
Creating directory '/home/john'.
john@ldap-krb-client:~$ klist
Ticket cache: FILE:/tmp/krb5cc_10001_BOrxWr
Default principal: john@EXAMPLE.COM
Valid starting Expires Service principal
04/17/20 20:29:50 04/18/20 06:29:50 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 04/18/20 20:29:50
john@ldap-krb-client:~$
We logged in using the kerberos password, and user/group information from the LDAP server.
SSSD and KDC spoofing
When using SSSD to manage kerberos logins on a Linux host, there is an attack scenario you should be aware of: KDC spoofing.
The objective of the attacker is to login on a workstation that is using Kerberos authentication. Let’s say he knows john
is a valid user on that machine.
The attacker first deploys a rogue KDC server in the network, and creates the john
principal there with a password of his choosing. What he has to do now is to have his rogue KDC respond to the login request from the workstation, before (or instead of) the real KDC. If the workstation isn’t authenticating the KDC, it will accept the reply from the rogue server and let john
in.
There is a configuration parameter that can be set to protect the workstation from this attack. It will have SSSD authenticate the KDC, and block the login if the KDC cannot be verified. This option is called krb5_validate
, and it’s false
by default.
To enable it, edit /etc/sssd/sssd.conf
and add this line to the domain section:
[sssd]
config_file_version = 2
domains = example.com
[domain/example.com]
id_provider = ldap
...
krb5_validate = True
The second step is to create a host
principal on the KDC for this workstation. This is how the KDC’s authenticity is verified. It’s like a “machine account”, with a shared secret that the attacker cannot control and replicate in his rogue KDC…The host
principal has the format host/<fqdn>@REALM
.
After the host principal is created, its keytab needs to be stored on the workstation. This two step process can be easily done on the workstation itself via kadmin
(not kadmin.local
) to contact the KDC remotely:
$ sudo kadmin -p ubuntu/admin
kadmin: addprinc -randkey host/ldap-krb-client.example.com@EXAMPLE.COM
WARNING: no policy specified for host/ldap-krb-client.example.com@EXAMPLE.COM; defaulting to no policy
Principal "host/ldap-krb-client.example.com@EXAMPLE.COM" created.
kadmin: ktadd -k /etc/krb5.keytab host/ldap-krb-client.example.com
Entry for principal host/ldap-krb-client.example.com with kvno 6, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal host/ldap-krb-client.example.com with kvno 6, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Then exit the tool and make sure the permissions on the keytab file are tight:
sudo chmod 0600 /etc/krb5.keytab
sudo chown root:root /etc/krb5.keytab
You can also do it on the KDC itself using kadmin.local
, but you will have to store the keytab temporarily in another file and securely copy it over to the workstation.
Once these steps are complete, you can restart sssd on the workstation and perform the login. If the rogue KDC picks the attempt up and replies, it will fail the host verification. With debugging we can see that happening on the workstation:
==> /var/log/sssd/krb5_child.log <==
(Mon Apr 20 19:43:58 2020) [[sssd[krb5_child[2102]]]] [validate_tgt] (0x0020): TGT failed verification using key for [host/ldap-krb-client.example.com@EXAMPLE.COM].
(Mon Apr 20 19:43:58 2020) [[sssd[krb5_child[2102]]]] [get_and_save_tgt] (0x0020): 1741: [-1765328377][Server host/ldap-krb-client.example.com@EXAMPLE.COM not found in Kerberos database]
And the login is denied. If the real KDC picks it up, however, the host verification succeeds:
==> /var/log/sssd/krb5_child.log <==
(Mon Apr 20 19:46:22 2020) [[sssd[krb5_child[2268]]]] [validate_tgt] (0x0400): TGT verified using key for [host/ldap-krb-client.example.com@EXAMPLE.COM].
And the login is accepted.
Debugging and troubleshooting
Here are some tips to help troubleshoot sssd.
debug_level
The debug level of sssd can be changed on-the-fly via sssctl
, from the sssd-tools
package:
sudo apt install sssd-tools
sssctl debug-level <new-level>
Or change add it to the config file and restart sssd:
[sssd]
config_file_version = 2
domains = example.com
[domain/example.com]
debug_level = 6
...
Either will yield more logs in /var/log/sssd/*.log
and can help identify what is going on. The sssctl
approach has the clear advantage of not having to restart the service.
Caching
Caching is useful to speed things up, but it can get in the way big time when troubleshooting. It’s useful to be able to remove the cache while chasing down a problem. This can also be done with the sssctl
tool from the sssd-tools
package.
You can either remove the whole cache:
# sssctl cache-remove
Creating backup of local data...
SSSD backup of local data already exists, override? (yes/no) [no] yes
Removing cache files...
SSSD= needs to be running. Start SSSD now? (yes/no) [yes] yes
Or just one element:
sssctl cache-expire -u john
Or expire everything:
sssctl cache-expire -E
Last updated 8 months ago. Help improve this document in the forum.