Recently a member of the Sensu Community Slack needed some help troubleshooting LDAP which led to a discussion we felt other Sensu users might benefit from:
Here are some key takeaways from that discussion (117 replies later ):
-
The
ldapsearch
utility is your friend. If you’re troubleshooting connectivity issues, learning how to query an LDAP server usingldapsearch
is very helpful. Here’s an exampleldapsearch
query to get you started:$ ldapsearch -x -H 'ldap://ldap.yourcompany.com:636' \ -b 'dc=sensu,dc=io' '(mail=username@sensu.io)' \ -D username -w password
-
In earlier versions of Sensu Go (pre-5.6.0) LDAPS was not supported, but LDAPS was still possible using
stunnel
. This should no longer be required, but we noted this for posterity.Here’s an example
stunnel.conf
file that could be used for testing:foreground = yes [gsuite-ldap] client = yes accept = 0.0.0.0:1636 connect = ldap.google.com:636 cert = /etc/stunnel/gsuite-ldap.crt key = /etc/stunnel/gsuite-ldap.key
NOTE: in this example, I’m using Stunnel to proxy traffic to Google G Suite / Google Cloud Identity’s LDAP service.
To use this configuration file, just run the command:
stunnel /path/to/stunnel.conf
After running this command (e.g. on the same node as the Sensu Go backend), you could perform
ldapsearch
queries or configure a Sensu Go LDAP provider to point at “localhost” port 1636. -
At the end of the day, Sensu Go needs to be configured to lookup users via a configurable attribute (e.g. an email address like “lizy@company.com”, or just the username (e.g. “lizy”), and then it needs to know how to perform group searches (this is also configurable in Sensu Go). Here’s an example LDAP Provider template for Sensu Go and Google G Suite’s Google Cloud Identify LDAP service:
--- type: ldap api_version: authentication/v2 metadata: name: gsuite-ldap spec: servers: - host: ldap.google.com port: 636 insecure: false security: tls client_cert_file: /etc/sensu/ldap/gsuite-ldap.crt client_key_file: /etc/sensu/ldap/gsuite-ldap.key binding: user_dn: username password: password group_search: base_dn: dc=sensu,dc=io # attribute: member # name_attribute: cn # object_class: memberOf user_search: base_dn: dc=sensu,dc=io attribute: mail # name_attribute: displayName # object_class: uid groups_prefix: sensu.io # username_prefix: gsuite-ldap
NOTE: because Sensu Go supports multiple SSO providers, you can optionally configure a
groups_prefix
to help avoid group membership name collisions (e.g. if two SSO providers both have “engineering” groups, and members of these groups need to have different levels of access in Sensu Go). -
Sensu RBAC resources offer very granular controls around how to associate SSO-authenticated users to the corresponding Role (or ClusterRole). Here’s an example RBAC profile (Role + RoleBinding) for Sensu Go:
--- type: ClusterRole api_version: core/v2 metadata: name: sensu:sales spec: rules: - resources: - assets verbs: - get - list - resources: - handlers verbs: - get - list - resources: - checks - entities - events - filters - hooks - mutators - silenced verbs: - get - list - create - update - delete --- type: ClusterRoleBinding api_version: core/v2 metadata: name: sensu:sales spec: role_ref: type: ClusterRole name: sensu:sales subjects: - type: Group name: sensu.io:sales
NOTE: as commented on above, note that the group name here is
sensu.io:sales
(instead of justsales
); this prefix is required if you configure thegroups_prefix
attribute in the LDAP provider (in my case, I used thegroups_prefix: sensu.io
, so I would have to addsensu.io:
in front of group names in my RBAC resources). -
Finally, Sensu Go has very detailed debug logging available to help troubleshoot SSO/LDAP configuration issues. Here’s an example excerpt:
{"component":"authentication","error":"key xxxxxxxx@sensu.io not found","level":"debug","msg":"could not authenticate with provider \"basic\"","time":"2020-04-25T00:21:48Z"} {"component":"authentication/v2","level":"debug","msg":"using ldap server ldap.google.com:636","time":"2020-04-25T00:21:48Z"} {"component":"authentication/v2","level":"debug","msg":"running ldap search with basedn \"dc=sensu,dc=io\" and filter \"(\u0026(objectClass=person)(mail=xxxxxxxx@sensu.io))\"","time":"2020-04-25T00:21:48Z"} {"component":"authentication/v2","level":"debug","msg":"username \"xxxxxxxx@sensu.io\" mapped to entry \"uid=xxxxxxxx,ou=Employees,ou=Users,dc=sensu,dc=io\"","time":"2020-04-25T00:21:48Z"} {"component":"authentication/v2","level":"debug","msg":"running ldap search with basedn \"dc=sensu,dc=io\" and filter \"(\u0026(objectclass=groupOfNames)(member=uid=xxxxxxxx,ou=Employees,ou=Users,dc=sensu,dc=io))\"","time":"2020-04-25T00:21:48Z"} {"component":"authentication/v2","level":"debug","msg":"found 13 group(s): [\"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"xxxxxxxx\" \"sales\" \"xxxxxxxx\" \"xxxxxxxx\"]","time":"2020-04-25T00:21:49Z"} {"component":"apid","duration":"2534.143ms","level":"info","method":"GET","msg":"request completed","path":"/auth","size":1091,"status":200,"time":"2020-04-25T00:21:50Z"} {"component":"backend.api","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"namespaces","resourceName":"default","username":"xxxxxxxx","verb":"get"}} {"component":"apid","duration":"8.580ms","level":"info","method":"POST","msg":"request completed","path":"/graphql","size":157,"status":200,"time":"2020-04-25T00:21:51Z"} {"component":"backend.api","level":"debug","msg":"all namespaces implicitly authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"","resource":"namespaces","resourceName":"","username":"xxxxxxxx","verb":"list"}} {"component":"apid","duration":"6.808ms","level":"info","method":"POST","msg":"request completed","path":"/graphql","size":190,"status":200,"time":"2020-04-25T00:21:51Z"} {"component":"backend.api","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"namespaces","resourceName":"default","username":"xxxxxxxx","verb":"get"}} {"component":"rbac","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"events","resourceName":"","username":"xxxxxxxx","verb":"list"}} {"component":"apid","duration":"11.267ms","level":"info","method":"POST","msg":"request completed","path":"/graphql","size":207,"status":200,"time":"2020-04-25T00:21:51Z"} {"component":"backend.api","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"namespaces","resourceName":"default","username":"xxxxxxxx","verb":"get"}} {"component":"rbac","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"events","resourceName":"","username":"xxxxxxxx","verb":"list"}} {"component":"rbac","level":"debug","msg":"request authorized by the binding sensu:sales","time":"2020-04-25T00:21:51Z","zz_request":{"apiGroup":"core","apiVersion":"v2","namespace":"default","resource":"entities","resourceName":"","username":"xxxxxxxx","verb":"list"}}
If you look closely, you can observe Sensu Go first attempt to authenticate the user against the built-in “basic” provider (i.e. Sensu’s built-in username+password auth provider); it errors with the message
"could not authenticate with provider \"basic\""
, and then proceeds to attempt authentication against the other configured provider(s) – in this case, an LDAP provider.
I hope this helps anyone who is just getting started with Sensu Go and need configure SSO!