LDAP authentication with Sensu Go: troubleshooting & tips (Part 2)

Sensu creator and Developer Advocate Todd Campbell recently wrote about using LDAP authentication for single-sign on (SSO) with Sensu Go. That post provided a great overview of Sensu authentication and included some useful LDAP troubleshooting tips. In this post, we'll focus on the Sensu LDAP implementation and explore how SSO/LDAP users are linked to RBAC "profiles" (i.e. Roles and ClusterRoles). We'll also demonstrate how Sensu supports multiple LDAP providers thanks to its groups_prefix feature.

ldap authentication part 2

Diagnosing Sensu LDAP authentication providers

Both the LDAP and AD authentication provider types in Sensu use the same fundamental mechanism: they bind to an LDAP server implementation and do searches. Bind, in this context, is the LDAP bind process that lets you authenticate that an LDAP user/password exists in the LDAP server matching some conditions. The only real difference between the LDAP and AD providers are some of the defaults used for the LDAP search settings.

LDAP is really flexible in terms of what attributes can be used to store information, so the default user and group search settings Sensu provides might not work for your organization's LDAP schema. If as a Sensu admin, you need to integrate with an LDAP server implemented by another part of your internal organization, it might not be clear what search settings to use, especially if the default settings Sensu provides aren't working. I've found that the best way to figure this out is to use ldapsearch and ldapwhoami on the system where sensu-backend is expected to operate.

If you can construct ldapsearch and ldapwhoami command line operations that work, then you have all the information you need to translate into a working LDAP or AD authentication provider configuration in Sensu.

When using LDAP authentication provider, Sensu does four steps to authenticate with the LDAP server:

  1. Binds with privileged user
  2. Performs a user search using privileged user to make sure the desired login user exists
  3. Performs a group search using a privileged user to pull group info to be optionally used in Sensu RBAC
  4. Binds with login user to authenticate provided user/password credentials

The privileged LDAP user

The privileged LDAP user has permissions to perform LDAP searches for users and groups.

You may need to specifically ask the LDAP/AD admin for an LDAP account that will allow you to perform ldapsearch commands. Specifically, you'll need the Distinguished Name (aka dn) and password for the privileged user.

For the following examples, I'm going to assume a privileged user with a Distinguished Name of

“cn=sensuldap,dc=example,dc=com”

Security Settings

You'll have to discuss with your LDAP/AD admin as to whether or not they are using TLS-secured LDAP and if they require a custom CA or client certificate. Both ldapsearch and sensu-backend support these options. For brevity, I'm not going to go into the details of cert signing or the installation of a custom CA. For the purposes of the following ldapseach examples, I'm going to assume the LDAP server is using secure LDAP and that the TLS_CACERT TLS_CERT and TLS_KEY environment variables are set appropriately if needed. If the LDAP server you are connecting to requires client certificates, you'll definitely need to discuss the configuration with your LDAP admin.

The user search command

Once you have the privileged user credentials and have your TLS environment set up, you can use ldapsearch to mimic how Sensu will search for users and groups. Let's assume that you want to login into Sensu web-ui using an LDAP user with a uid attribute of sensu-admin. We want to be able to login to the Sensu web-ui by entering the LDAP uid attribute and LDAP password. We can construct the search Sensu will perform using an ldapsearch command similar to this:

ldapsearch -x -H "ldaps://ldap.example.com"  -D “cn=sensuldap,dc=example,dc=com” -b "dc=example,dc=com" "(&(objectClass=person)(uid=sensu-admin))"

If this is a valid unique search, you should get the result indicating numEntries: 1. If you are getting more than one match, you'll need to review and see if you can adjust the search. Note that it's possible to search non-unique fields in LDAP — such as human names. If your user search test returns more than a single result, you may need to change the base search by including one or more Organizational Units(ou) attributes to narrow the search further. Once you have the search base tailored to provide a unique match, you should see the details of the matching LDAP record including the Distinguished Name attribute for the user:

dn: uid=sensu-admin,dc=example,dc=com

The value of the dn attribute is what Sensu uses when authenticating the user trying to login by binding to the LDAP server after the privileged user search is complete.

This search command binds to the LDAP server as the privileged user and asks for the privileged user's password. The -D option holds privileged user's Distinguished Name and corresponds to the Sensu LDAP authentication provider binding.user_dn setting.

The user search is restricted by the -b option which represents a search base. It's a subset of the available distinguished name LDAP attribute (dn) that must match. You'll want to confirm the correct search base with your LDAP admin. This search base corresponds to the Sensu LDAP auth provider user_Search.base_dn setting.

Lastly come the search filters. Sensu uses two LDAP search filters: a filter on ObjectClass, where the value is configurable as part of the Sensu authentication provider configuration, and then a second filter using a configurable LDAP attribute name corresponding to the login name you want to use in Sensu.

The needed configuration attributes for Sensu LDAP authentication provider can be taken from the ldapsearch example above. Here's what the final Sensu LDAP authentication provider looks like:

---
type: ldap
api_version: authentication/v2
metadata:
  name: openldap
spec:
  servers:
  - binding:
      password: <<privileged_user_password>> 
      user_dn: cn=sensuldap,dc=example,dc=com
    host: ldaps.example.com
    insecure: false
    port: 636
    security: tls
    user_search:
      attribute: uid
      base_dn: dc=example,dc=com
      name_attribute: uid
      object_class: person

The Sensu LDAP authentication provider binding section needs to have the user_dn attribute that matches the privileged LDAP user authorized to perform user and group searches, and the -D argument in the ldapsearch call above.

The user_search section takes information from the ldapsearch -b argument in the command we did above. The base_dn attribute matches the common elements of the search for all users. The attribute is the LDAP attribute that matches the unique name you want to use when you login to Sensu. It may be a username or an email address or something else your organization uses for unique login names. The object_class is the type of record you want to search. The default value is person — which is the most common LDAP configuration usage — but you may need to change the object class to match your LDAP configuration details.

Once you are more familiar with the contents of your LDAP records you'll probably end up using a different value for name_attribute. The name_attribute is used to display the user info inside Sensu, and is not part of the LDAP query. When starting out, I find it's easier to set this to the same value as attribute setting, but once you have everything working, you may change this to the LDAP attribute that holds the person's full name or something else. For example, name search could be based on email username only (e.g. "lizy" instead of "lizy@sensu.io") and name_attribute could be the full email address, or vice versa. Unlike attribute, the name_attribute doesn't need to be unique because it's not part of a user search.

The group search command

Once Sensu does the user search, it goes on to perform a search for all groups that a particular user is a member of. The search Sensu will perform will look similar to this ldapsearch command:

ldapsearch -x -H "ldaps://ldap.example.com"  -D “cn=sensuldap,dc=example,dc=com” -b "ou=Groups,dc=example,dc=com" "(&(objectClass=groupOfNames)(member=sensu-admin))"

Similar to the user search before, this group search uses the privileged user Distinguished Name and search base options. What's different here are the search filters. ObjectClass filter is still being used, but now we are only matching for groupOfNames. The second filter is the group attribute filter, where we are choosing to match the attribute named member, and the value is the same as the uid from the user search, since we are trying to find which groups the sensu-admin user belongs to.

Note the search base for groups may be different than the search base most appropriate for user searches due to the use of Organization Unit_(ou)_ attributes in the dn.

Translating the group search into the Sensu LDAP authentication configuration settings:

group_search:
      attribute: member
      base_dn: ou=Groups,dc=example,dc=com
      name_attribute: cn
      object_class: groupOfNames

For the group_search.attribute, you'll want to make sure you are selecting the attribute that corresponds to the user's login name you are trying to use. The group will have multiple versions of the attribute, indicating membership to the group for multiple users. Because of the flexibility of LDAP, you may need to talk to your LDAP admin as to what group search attribute and object class to use. Or you can do some exploratory searches with different filters to explore your LDAP records.

Group search pairs well with a Sensu RBAC feature called groups_prefix. When defining any Sensu authentication provider (LDAP, AD and OIDC), you can identify a groups_prefix string that you can use in your Sensu role-based access control rules to distinguish LDAP groups from Sensu native groups, so you can give different access based on authentication provider.

For example, you could set groups_prefix: “ldap” and then write Sensu RBAC role binding rules with a group subject "ldap:operators". If this groups_prefix is configured in the LDAP authentication provider, Sensu would interpret the "ldap:" prefix in the group name in any RBAC rules to only match groups from the LDAP provider.

Similarly, Sensu also has a user_prefix feature that lets you distinguish Sensu native users from users authenticated from an external provider like LDAP, if you need to write RBAC rules that target specific LDAP users instead of groups.

Moreover, the groups and user prefix let you write granular Sensu RBAC rules for multiple authentication providers.

The ldapwhoami command

Once you have established the user and group search settings for your Sensu LDAP/AD authentication provider configuration, you'll also want to make sure that the login user that needs to authenticate is able to bind to the LDAP server. You may have to work with your LDAP admin to correctly set permission for the users you want to use LDAP authentication with. Part of this is making sure the user has an LDAP password defined (hint: ldappasswd command) but also that the user has permissions to bind to the LDAP server. The easiest way for you to test that the target user has the necessary credentials and permissions is to use the ldapwhoami command and successfully bind to the LDAP server.

Let’s take the Distinguished Name from the user search example from above and use it in the ldapwhoami command:

ldapwhoami -x -H "ldaps://ldap.example.com"  -D “uid=sensu-admin,dc=example,dc=com”

If the entered password is correct, the output should look like this:

dn:uid=sensu-admin,dc=example,dc=local

If you run into an error, you may need to talk to your LDAP/AD admin to ensure your user has simple bind access with user/password instead of relying on an external Kerberos server to provide user authentication.

NOTE: LDAP simple bind is a critical requirement for Sensu's LDAP and AD authentication provider implementations.

As an aside, if you have time to read up on the history of why Kerberos exists, the history is sort of fascinating. I'd wager that if we had mutual TLS as a network security standard earlier, something like Kerberos wouldn't have been widely adopted.

We'd love to hear about your experience with the Sensu LDAP implementation! Let us know in discourse:

Join the conversation!