Lightweight Directory Access Protocol (LDAP) reference

COMMERCIAL FEATURE: Access Lightweight Directory Access Protocol (LDAP) authentication for single sign-on (SSO) in the packaged Sensu Go distribution. For more information, read Get started with commercial features.

Sensu requires username and password authentication to access the web UI, API, and sensuctl command line tool.

In addition to the built-in basic authentication provider, Sensu offers commercial support for a standards-compliant Lightweight Directory Access Protocol (LDAP) tool for single sign-on (SSO) authentication. The Sensu LDAP authentication provider is tested with OpenLDAP. If you’re using AD, head to the AD section.

For general information about configuring authentication providers, read Configure single sign-on (SSO) authentication.

LDAP configuration examples

Example LDAP configuration: Minimum required attributes

---
type: ldap
api_version: authentication/v2
metadata:
  name: openldap
spec:
  servers:
  - group_search:
      base_dn: dc=acme,dc=org
    host: 127.0.0.1
    user_search:
      base_dn: dc=acme,dc=org
{
  "type": "ldap",
  "api_version": "authentication/v2",
  "spec": {
    "servers": [
      {
        "host": "127.0.0.1",
        "group_search": {
          "base_dn": "dc=acme,dc=org"
        },
        "user_search": {
          "base_dn": "dc=acme,dc=org"
        }
      }
    ]
  },
  "metadata": {
    "name": "openldap"
  }
}

Example LDAP configuration: All attributes

---
type: ldap
api_version: authentication/v2
metadata:
  name: openldap
spec:
  allowed_groups: []
  groups_prefix: ldap
  servers:
  - binding:
      password: YOUR_PASSWORD
      user_dn: cn=binder,dc=acme,dc=org
    client_cert_file: /path/to/ssl/cert.pem
    client_key_file: /path/to/ssl/key.pem
    group_search:
      attribute: member
      base_dn: dc=acme,dc=org
      name_attribute: cn
      object_class: groupOfNames
    host: 127.0.0.1
    insecure: false
    port: 636
    security: tls
    trusted_ca_file: /path/to/trusted-certificate-authorities.pem
    user_search:
      attribute: uid
      base_dn: dc=acme,dc=org
      name_attribute: cn
      object_class: person
  username_prefix: ldap
{
  "type": "ldap",
  "api_version": "authentication/v2",
  "spec": {
    "servers": [
      {
        "host": "127.0.0.1",
        "port": 636,
        "insecure": false,
        "security": "tls",
        "trusted_ca_file": "/path/to/trusted-certificate-authorities.pem",
        "client_cert_file": "/path/to/ssl/cert.pem",
        "client_key_file": "/path/to/ssl/key.pem",
        "binding": {
          "user_dn": "cn=binder,dc=acme,dc=org",
          "password": "YOUR_PASSWORD"
        },
        "group_search": {
          "base_dn": "dc=acme,dc=org",
          "attribute": "member",
          "name_attribute": "cn",
          "object_class": "groupOfNames"
        },
        "user_search": {
          "base_dn": "dc=acme,dc=org",
          "attribute": "uid",
          "name_attribute": "cn",
          "object_class": "person"
        }
      }
    ],
    "allowed_groups": [],
    "groups_prefix": "ldap",
    "username_prefix": "ldap"
  },
  "metadata": {
    "name": "openldap"
  }
}

Example LDAP configuration: Use memberOf attribute instead of group_search

If your LDAP server is configured to return a memberOf attribute when you perform a query, you can use memberOf in your Sensu LDAP implementation instead of group_search. The memberOf attribute contains the user’s group membership, which effectively removes the requirement to look up the user’s groups.

To use the memberOf attribute in your LDAP implementation, remove the group_search object from your LDAP config:

---
type: ldap
api_version: authentication/v2
metadata:
  name: openldap
spec:
  servers:
    host: 127.0.0.1
    user_search:
      base_dn: dc=acme,dc=org
{
  "type": "ldap",
  "api_version": "authentication/v2",
  "spec": {
    "servers": [
      {
        "host": "127.0.0.1",
        "user_search": {
          "base_dn": "dc=acme,dc=org"
        }
      }
    ]
  },
  "metadata": {
    "name": "openldap"
  }
}

After you configure LDAP to use the memberOf attribute, the debug log level will include the following log entries:

{"component":"authentication/v2","level":"debug","msg":"using the \"memberOf\" attribute to determine the group membership of user \"user1\"","time":"2020-06-25T14:10:58-04:00"}
{"component":"authentication/v2","level":"debug","msg":"found 1 LDAP group(s): [\"sensu\"]","time":"2020-06-25T14:10:58-04:00"}

LDAP specification

Top-level attributes

type
description Top-level attribute that specifies the sensuctl create resource type. For LDAP definitions, the type should always be ldap.
required true
type String
example
type: ldap
{
  "type": "ldap"
}
api_version
description Top-level attribute that specifies the Sensu API group and version. For LDAP definitions, the api_version should always be authentication/v2.
required true
type String
example
api_version: authentication/v2
{
  "api_version": "authentication/v2"
}
metadata
description Top-level map that contains the LDAP definition name. See the metadata attributes reference for details.
required true
type Map of key-value pairs
example
metadata:
  name: openldap
{
  "metadata": {
    "name": "openldap"
  }
}
spec
description Top-level map that includes the LDAP spec attributes.
required true
type Map of key-value pairs
example
spec:
  servers:
  - host: 127.0.0.1
    port: 636
    insecure: false
    security: tls
    trusted_ca_file: "/path/to/trusted-certificate-authorities.pem"
    client_cert_file: "/path/to/ssl/cert.pem"
    client_key_file: "/path/to/ssl/key.pem"
    binding:
      user_dn: cn=binder,dc=acme,dc=org
      password: YOUR_PASSWORD
    group_search:
      base_dn: dc=acme,dc=org
      attribute: member
      name_attribute: cn
      object_class: groupOfNames
    user_search:
      base_dn: dc=acme,dc=org
      attribute: uid
      name_attribute: cn
      object_class: person
  allowed_groups: []
  groups_prefix: ldap
  username_prefix: ldap
{
  "spec": {
    "servers": [
      {
        "host": "127.0.0.1",
        "port": 636,
        "insecure": false,
        "security": "tls",
        "trusted_ca_file": "/path/to/trusted-certificate-authorities.pem",
        "client_cert_file": "/path/to/ssl/cert.pem",
        "client_key_file": "/path/to/ssl/key.pem",
        "binding": {
          "user_dn": "cn=binder,dc=acme,dc=org",
          "password": "YOUR_PASSWORD"
        },
        "group_search": {
          "base_dn": "dc=acme,dc=org",
          "attribute": "member",
          "name_attribute": "cn",
          "object_class": "groupOfNames"
        },
        "user_search": {
          "base_dn": "dc=acme,dc=org",
          "attribute": "uid",
          "name_attribute": "cn",
          "object_class": "person"
        }
      }
    ],
    "allowed_groups": [],
    "groups_prefix": "ldap",
    "username_prefix": "ldap"
  }
}

LDAP spec attributes

servers
description The list of LDAP servers to use. During the authentication process, Sensu attempts to authenticate against each LDAP server in sequence until authentication is successful or there are no more servers to try.
required true
type Array
example
servers:
- host: 127.0.0.1
  port: 636
  insecure: false
  security: tls
  trusted_ca_file: "/path/to/trusted-certificate-authorities.pem"
  client_cert_file: "/path/to/ssl/cert.pem"
  client_key_file: "/path/to/ssl/key.pem"
  binding:
    user_dn: cn=binder,dc=acme,dc=org
    password: YOUR_PASSWORD
  group_search:
    base_dn: dc=acme,dc=org
    attribute: member
    name_attribute: cn
    object_class: groupOfNames
  user_search:
    base_dn: dc=acme,dc=org
    attribute: uid
    name_attribute: cn
    object_class: person
{
  "servers": [
    {
      "host": "127.0.0.1",
      "port": 636,
      "insecure": false,
      "security": "tls",
      "trusted_ca_file": "/path/to/trusted-certificate-authorities.pem",
      "client_cert_file": "/path/to/ssl/cert.pem",
      "client_key_file": "/path/to/ssl/key.pem",
      "binding": {
        "user_dn": "cn=binder,dc=acme,dc=org",
        "password": "YOUR_PASSWORD"
      },
      "group_search": {
        "base_dn": "dc=acme,dc=org",
        "attribute": "member",
        "name_attribute": "cn",
        "object_class": "groupOfNames"
      },
      "user_search": {
        "base_dn": "dc=acme,dc=org",
        "attribute": "uid",
        "name_attribute": "cn",
        "object_class": "person"
      }
    }
  ]
}

allowed_groups
description An array of allowed LDAP group strings to include in the tokenized identity claim. Use to specify which groups to encode in the authentication provider’s JSON Web Token (JWT) when the authenticated LDAP user is a member of many groups and the tokenized identity claim would be too large for correct web client operation.
required false
type Array of strings
example
allowed_groups:
- sensu-viewers
- sensu-operators
{
  "allowed_groups": [
    "sensu-viewers",
    "sensu-operators"
  ]
}

groups_prefix
description The prefix added to all LDAP groups. Sensu appends the groups_prefix with a colon. For example, for the groups_prefix ldap and the group dev, the resulting group name in Sensu is ldap:dev. Use the groups_prefix when integrating LDAP groups with Sensu RBAC role bindings and cluster role bindings.
required false
type String
example
groups_prefix: ldap
{
  "groups_prefix": "ldap"
}

username_prefix
description The prefix added to all LDAP usernames. Sensu appends the username_prefix with a colon. For example, for the username_prefix ldap and the user alice, the resulting username in Sensu is ldap:alice. Use the username_prefix when integrating LDAP users with Sensu RBAC role bindings and cluster role bindings. Users do not need to provide the username_prefix when logging in to Sensu.
required false
type String
example
username_prefix: ldap
{
  "username_prefix": "ldap"
}

LDAP server attributes

host
description LDAP server IP address or FQDN.
required true
type String
example
host: 127.0.0.1
{
  "host": "127.0.0.1"
}
port
description LDAP server port.
required true
type Integer
default 389 for insecure connections; 636 for TLS connections
example
port: 636
{
  "port": 636
}
insecure
description Skips SSL certificate verification when set to true.

WARNING: Do not use an insecure connection in production environments.

required false
type Boolean
default false
example
insecure: false
{
  "insecure": false
}
security
description Determines the encryption type to be used for the connection to the LDAP server: insecure (unencrypted connection; not recommended for production), tls (secure encrypted connection), or starttls (unencrypted connection upgrades to a secure connection).
type String
default "tls"
example
security: tls
{
  "security": "tls"
}
trusted_ca_file
description Path to an alternative CA bundle file in PEM format to be used instead of the system’s default bundle. This CA bundle is used to verify the server’s certificate.
required false
type String
example
trusted_ca_file: /path/to/trusted-certificate-authorities.pem
{
  "trusted_ca_file": "/path/to/trusted-certificate-authorities.pem"
}
client_cert_file
description Path to the certificate that should be sent to the server if requested.
required false
type String
example
client_cert_file: /path/to/ssl/cert.pem
{
  "client_cert_file": "/path/to/ssl/cert.pem"
}
client_key_file
description Path to the key file associated with the client_cert_file.
required false
type String
example
client_key_file: /path/to/ssl/key.pem
{
  "client_key_file": "/path/to/ssl/key.pem"
}
binding
description The LDAP account that performs user and group lookups. If your sever supports anonymous binding, you can omit the user_dn or password attributes to query the directory without credentials.
required false
type Map
example
binding:
  user_dn: cn=binder,dc=acme,dc=org
  password: YOUR_PASSWORD
{
  "binding": {
    "user_dn": "cn=binder,dc=acme,dc=org",
    "password": "YOUR_PASSWORD"
  }
}
group_search
description Search configuration for groups. See the group search attributes for more information. Remove the group_search object from your configuration to use the memberOf attribute instead.
required false
type Map
example
group_search:
  base_dn: dc=acme,dc=org
  attribute: member
  name_attribute: cn
  object_class: groupOfNames
{
  "group_search": {
    "base_dn": "dc=acme,dc=org",
    "attribute": "member",
    "name_attribute": "cn",
    "object_class": "groupOfNames"
  }
}
user_search
description Search configuration for users. See the user search attributes for more information.
required true
type Map
example
user_search:
  base_dn: dc=acme,dc=org
  attribute: uid
  name_attribute: cn
  object_class: person
{
  "user_search": {
    "base_dn": "dc=acme,dc=org",
    "attribute": "uid",
    "name_attribute": "cn",
    "object_class": "person"
  }
}

LDAP binding attributes

user_dn
description The LDAP account that performs user and group lookups. We recommend using a read-only account. Use the distinguished name (DN) format, such as cn=binder,cn=users,dc=domain,dc=tld. If your sever supports anonymous binding, you can omit this attribute to query the directory without credentials.
required false
type String
example
user_dn: cn=binder,dc=acme,dc=org
{
  "user_dn": "cn=binder,dc=acme,dc=org"
}
password
description Password for the user_dn account. If your sever supports anonymous binding, you can omit this attribute to query the directory without credentials.
required false
type String
example
password: YOUR_PASSWORD
{
  "password": "YOUR_PASSWORD"
}

LDAP group search attributes

base_dn
description Tells Sensu which part of the directory tree to search. For example, dc=acme,dc=org searches within the acme.org directory.
required true
type String
example
base_dn: dc=acme,dc=org
{
  "base_dn": "dc=acme,dc=org"
}
attribute
description Used for comparing result entries. Combined with other filters as
"(<Attribute>=<value>)".
required false
type String
default "member"
example
attribute: member
{
  "attribute": "member"
}
name_attribute
description Represents the attribute to use as the entry name.
required false
type String
default "cn"
example
name_attribute: cn
{
  "name_attribute": "cn"
}
object_class
description Identifies the class of objects returned in the search result. Combined with other filters as "(objectClass=<ObjectClass>)".
required false
type String
default "groupOfNames"
example
object_class: groupOfNames
{
  "object_class": "groupOfNames"
}

LDAP user search attributes

base_dn
description Tells Sensu which part of the directory tree to search. For example, dc=acme,dc=org searches within the acme.org directory.
required true
type String
example
base_dn: dc=acme,dc=org
{
  "base_dn": "dc=acme,dc=org"
}
attribute
description Used for comparing result entries. Combined with other filters as
"(<Attribute>=<value>)".
required false
type String
default "uid"
example
attribute: uid
{
  "attribute": "uid"
}
name_attribute
description Represents the attribute to use as the entry name
required false
type String
default "cn"
example
name_attribute: cn
{
  "name_attribute": "cn"
}
object_class
description Identifies the class of objects returned in the search result. Combined with other filters as "(objectClass=<ObjectClass>)".
required false
type String
default "person"
example
object_class: person
{
  "object_class": "person"
}

LDAP metadata attributes

name
description A unique string used to identify the LDAP configuration. Names cannot contain special characters or spaces (validated with Go regex \A[\w\.\-]+\z).
required true
type String
example
name: openldap
{
  "name": "openldap"
}

LDAP troubleshooting

To troubleshoot any issue with LDAP authentication, start by [increasing the log verbosity][19] of sensu-backend to the debug log level. Most authentication and authorization errors are only displayed on the debug log level to avoid flooding the log files.

NOTE: If you can’t locate any log entries referencing LDAP authentication, make sure the LDAP provider was successfully installed using sensuctl.

Authentication errors

This section lists common error messages and possible solutions.

Error message: failed to connect: LDAP Result Code 200 "Network Error"

The LDAP provider couldn’t establish a TCP connection to the LDAP server. Verify the host and port attributes. If you are not using LDAP over TLS/SSL, make sure to set the value of the security attribute to "insecure" for plaintext communication.

Error message: certificate signed by unknown authority

If you are using a self-signed certificate, make sure to set the insecure attribute to true. This will bypass verification of the certificate’s signing authority.

Error message: failed to bind: ...

The first step for authenticating a user with the LDAP provider is to bind to the LDAP server using the service account specified in the binding object. Make sure the user_dn specifies a valid DN and that its password is correct.

Error message: user <username> was not found

The user search failed. No user account could be found with the given username. Check the user_search object and make sure that:

  • The specified base_dn contains the requested user entry DN
  • The specified attribute contains the username as its value in the user entry
  • The object_class attribute corresponds to the user entry object class

Error message: ldap search for user <username> returned x results, expected only 1

The user search returned more than one user entry, so the provider could not determine which of these entries to use. Change the user_search object so the provided username can be used to uniquely identify a user entry. Here are two methods to try:

  • Adjust the attribute so its value (which corresponds to the username) is unique among the user entries
  • Adjust the base_dn so it only includes one of the user entries

Error message: ldap entry <DN> missing required attribute <name_attribute>

The user entry returned (identified by <DN>) doesn’t include the attribute specified by name_attribute object, so the LDAP provider could not determine which attribute to use as the username in the user entry. Adjust the name_attribute so it specifies a human-readable name for the user.

Error message: ldap group entry <DN> missing <name_attribute> and cn attributes

The group search returned a group entry (identified by <DN>) that doesn’t have the name_attribute attribute or a cn attribute, so the LDAP provider could not determine which attribute to use as the group name in the group entry. Adjust the name_attribute so it specifies a human-readable name for the group.

Authorization issues

Once authenticated, each user needs to be granted permissions via either a ClusterRoleBinding or a RoleBinding.

The way LDAP users and LDAP groups can be referred as subjects of a cluster role or role binding depends on the groups_prefix and username_prefix configuration attributes values of the LDAP provider. For example, for the groups_prefix ldap and the group dev, the resulting group name in Sensu is ldap:dev.

Issue: Permissions are not granted via the LDAP group(s)

During authentication, the LDAP provider will print in the logs all groups found in LDAP (for example, found 1 group(s): [dev]. Keep in mind that this group name does not contain the groups_prefix at this point.

The Sensu backend logs each attempt made to authorize an RBAC request. This is useful for determining why a specific binding didn’t grant the request. For example:

[...] the user is not a subject of the ClusterRoleBinding cluster-admin [...]
[...] could not authorize the request with the ClusterRoleBinding system:user [...]
[...] could not authorize the request with any ClusterRoleBindings [...]