wiltonsr / ldapAuth

An open source Traefik Middleware that enables authentication via LDAP in a similar way to Traefik Enterprise
https://plugins.traefik.io/plugins/628c9eb7ffc0cd18356a979c/ldap-auth
Apache License 2.0
117 stars 10 forks source link
authentication authentication-middleware gandalpher go go-ldap golang hacktoberfest ldap ldap-authentication plugin traefik-middleware traefik-plugin traefik-v2

Gandalpher
"You shall authenticate to the LDAP to pass" - Gandalpher, the gopher


GitHub GitHub release (latest by date including pre-releases) GitHub go.mod Go version GitHub issues GitHub last commit (branch)

Traefik ldapAuth Middleware

This project is an in-progress effort to create an open-source middleware that enables authentication via LDAP in a similar way to Traefik Enterprise.

Requirements

Traefik plugins are developed using the compiled Go language. Rather than being pre-compiled and linked, however, plugins are executed on the fly by Yaegi, an embedded Go interpreter. Due to traefik/yaegi#1275 and traefik/yaegi#1484, the ldap-go module only works after the listed version.

Usage

Add Plugin to Service

whoami:
  image: "traefik/whoami"
  container_name: "whoami"
  labels:
    - traefik.enable=true
    - traefik.http.routers.whoami.rule=Host(`whoami.localhost`)
    - traefik.http.routers.whoami.entrypoints=web
    # ldapAuth Register Middleware ====================================================
    - traefik.http.routers.whoami.middlewares=ldap_auth
    # ldapAuth Options=================================================================
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.enabled=true
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.logLevel=DEBUG
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.attribute=uid
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.baseDN=dc=example,dc=com
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].url=ldap://ldap.forumsys.com
    - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].port=389
    # =================================================================================

Bind Mode Example

[...]
labels:
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.attribute=uid
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.baseDN=dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].url=ldap://ldap.forumsys.com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].port=389

Search Mode Anonymous Example

[...]
labels:
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.attribute=uid
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.baseDN=dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.searchFilter=({{.Attribute}}={{.Username}})
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].url=ldap://ldap.forumsys.com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].port=389

Search Mode Authenticated Example

[...]
labels:
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.attribute=uid
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.baseDN=dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.bindDN=uid=tesla,dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.bindPassword=password
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.searchFilter=({{.Attribute}}={{.Username}})
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].url=ldap://ldap.forumsys.com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].port=389

Advanced Search Mode Example

[...]
labels:
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.attribute=uid
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.baseDN=dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.bindDN=uid=tesla,dc=example,dc=com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.bindPassword=password
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.searchFilter=(&(objectClass=person)({{.Attribute}}={{.Username}}))
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].url=ldap://ldap.forumsys.com
  - traefik.http.middlewares.ldap_auth.plugin.ldapAuth.serverList[0].port=389

Operations Mode

The Operation Mode detected will be used to perform all subsequent requests.

Bind Mode

If no searchFilter is specified in its configuration, the middleware runs in the default bind mode, meaning it tries to make a simple bind request to the LDAP server with the credentials provided in the request headers. If the bind succeeds, the middleware forwards the request, otherwise, it returns a 401 Unauthorized status code.

Search Mode

If a searchFilter query is specified in the configuration, then the middleware runs in search mode. In this mode, a search query with the given filter is issued to the LDAP server before trying to bind. If bindDN and bindPassword have also been provided, then the search query will use these credentials. If the result of this search returns only 1 record, it tries to issue a bind request with this record, otherwise, it aborts a 401 Unauthorized status code.

Options

enabled

Optional, Default: true

Controls whether requests will be checked against LDAP or not before being delivered.

logLevel

Optional, Default: INFO

Set LogLevel for detailed information about plugin operation.

serverList.url

Required, Default: ""

LDAP server address where queries will be performed.

serverList.port

Required, Default: 389

LDAP server port where queries will be performed.

serverList.weight

Optional, Default: 0

LDAP server weight to sort serverList. Higher weight, higher precedence.

cacheTimeout

Optional, Default: 300

Indicates the number of seconds until the session cookie expires. A zero or negative number will expire the cookie immediately.

cacheCookieName

_Optional, Default: ldapAuth_session_token_

The session cookie name.

cacheCookiePath

Optional, Default: ""

The session cookie path. By default, the cookie path will be set to the request path.

cacheCookieSecure

Optional, Default: false

Set to true if the session cookie should have the secure flag. The cookie will only be transmitted over an HTTPS connection.

cacheKey

Needs traefik >= v2.8.5

Optional, Default: super-secret-key

The key used to encrypt session cookie information. You must use a strong value here.

serverList.startTLS

Optional, Default: false

If set to true, instruct ldapAuth to issue a StartTLS request when initializing the connection with the LDAP server.

serverList.insecureSkipVerify

Optional, Default: false

When connecting to a ldaps server or startTLS is enabled, the connection to the LDAP server is verified to be secure. This option allows ldapAuth to proceed and operate even for server connections otherwise considered insecure.

serverList.minVersionTLS

Optional, Default: tls.VersionTLS12

Contains the minimum TLS version that is acceptable. By default, TLS 1.2 is currently used as the minimum. TLS 1.0 is the minimum supported by this package.

This option value must match crypto/tls versions constants.

serverList.maxVersionTLS

Optional, Default: tls.VersionTLS13

Contains the maximum TLS version that is acceptable. By default, the maximum version supported by this package is used, which is currently TLS 1.3.

This option value must match crypto/tls versions constants.

serverList.certificateAuthority

Optional, Default: ""

The serverList.certificateAuthority option should contain one or more PEM-encoded certificates to use to establish a connection with the LDAP server if the connection uses TLS but the certificate was signed by a custom Certificate Authority.

Example:

    ServerList:
        CertificateAuthority: |-
            -----BEGIN CERTIFICATE-----
            MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
            BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
            Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
            aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
            DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
            EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
            RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
            apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
            Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
            ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
            98TwDIK/39WEB/V607As+KoYazQG8drorw==
            -----END CERTIFICATE-----
attribute

Optional, Default: cn

The attribute used to bind a user in Bind Mode. Bind queries use this pattern: <attribute>=<username>,<baseDN>, where the username is extracted from the request header. If AllowedGroups option was used in Bind Mode, the same pattern is added when searching if the user belongs to the group.

searchFilter

Optional, Default: ""

If not empty, the middleware will run in Search Mode, filtering search results with the given query.

Filter queries can use the {{.Option}} format, from text/template go package, as placeholders that are replaced by the equivalent value from config. Additionally, the username provided in the Authorization header of the request can also be used.

For example: (&(objectClass=inetOrgPerson)(gidNumber=500)({{.Attribute}}={{.Username}})).

Will be replaced to: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=tesla)).

Note1: All filter options must start with Uppercase to be replaced correctly.

Note2: searchFilter must not escape curly braces when using labels.

Note3: searchFilter must escape curly braces when using yml file.

Note4: searchFilter must escape curly braces when using toml file.

baseDN

Required, Default: ""

From where the plugin will search for users.

bindDN

Optional, Default: ""

The domain name to bind to in order to authenticate to the LDAP server when running on Search Mode. Leaving this empty with Search Mode means binds are anonymous, which is rarely expected behavior. It is not used when running in Bind Mode.

bindPassword

Optional, Default: ""

The password corresponding to the bindDN specified when running in Search Mode, is used in order to authenticate to the LDAP server.

forwardUsername

Optional, Default: true

The forwardUsername option can be enabled to forward the username in a specific header, defined using the forwardUsernameHeader option.

forwardUsernameHeader

Optional, Default: Username

Name of the header to put the username in when forwarding it. This is not used if the forwardUsername option is set to false.

forwardAuthorization

Optional, Default: false

The forwardAuthorization option determines if the authorization header will be forwarded or stripped from the request after the middleware has approved it. Attention, enabling this option may expose the password of the LDAP user who is making the request.

forwardExtraLDAPHeaders

Optional, Default: false

The forwardExtraLDAPHeaders option determines if the LDAP Extra Headers, Ldap-Extra-Attr-DN and Ldap-Extra-Attr-CN, will be added or not to request. This is not used if the forwardUsername option is set to false or if searchFilter is empty.

wwwAuthenticateHeader

Optional, Default: true

If the LDAP middleware receives a request with a missing or invalid Authorization header and wwwAuthenticateHeader is enabled, it will set a WWW-Authenticate header in the 401 Unauthorized response. See the WWW-Authenticate header documentation for more information.

wwwAuthenticateHeaderRealm

Optional, Default: ""

The name of the realm to specify in the WWW-Authenticate header. This option is ineffective unless the wwwAuthenticateHeader option is set to true.

enableNestedGroupFilter

Optional, Default: false

If you need to search the user's nested group and the LDAP server support to search for LDAP_MATCHING_RULE_IN_CHAIN groups, you can enabled it by settings this parameter to true, it is disabled by default.

allowedGroups

Needs traefik >= v2.8.2

Optional, Default: []

The list of LDAP group DNs that users must be members of to be granted access. If a user is in any of the listed groups, then that user is granted access.

If set to an empty list, all users with an LDAP account can log in, without performing any group membership checks unless allowedUsers is set. In that case, the user must be a part of the allowedUsers list.

allowedGroups is not supported with labels, because multiple value labels are separated with commas. You must use toml or yaml configuration file. For more details, check examples page.

allowedUsers

Needs traefik >= v2.8.2

Optional, Default: []

The list of LDAP user DNs or usernames to be granted access. If a user is in the listed users, then that user is granted access.

If set to an empty list, all users with an LDAP account can log in, unless allowedGroups is set. In that case, group membership checks will be performed.

allowedUsers is not supported with labels, because multiple value labels are separated with commas. You must use toml or yaml configuration file. For more details, check examples page.