Sensu Go SSO w/ LDAP authentication

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 :sweat_smile:):

  • The ldapsearch utility is your friend. If you’re troubleshooting connectivity issues, learning how to query an LDAP server using ldapsearch is very helpful. Here’s an example ldapsearch 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 just sales); this prefix is required if you configure the groups_prefix attribute in the LDAP provider (in my case, I used the groups_prefix: sensu.io, so I would have to add sensu.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!

#monitoringlove

:v:

4 Likes