LDAP Authentication

TraefikEE can integrate with LDAP in order to restrict the access to applications.

Authentication in TraefikEE is implemented as a middleware. To avoid having sensitive information such as LDAP credentials specified as labels (or in CRDs) by applications and to allow multiple middlewares to reuse the same authentication method, the reusable portion of the configuration is externalized in Authentication Sources.

Authentication Sources are defined in the static configuration of the cluster and are referenced by authentication middlewares.

Authentication Source

Before configuring an LDAP middleware, an LDAP Authentication Source must be defined in the static configuration.

Authentication Source Options

url

Required, Default=""

The url option should be set to the URL of your LDAP server. It should use either the ldaps or ldap protocol and end with a port, like ldaps://ldap.example.org:636 for example.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      url = "ldaps://ldap.example.org:636"
authSources:
  ldapSource:
    ldap:
      url: ldaps://ldap.example.org:636

startTLS

Optional, Default=false

startTLS, if set to true, instructs TraefikEE to issue a StartTLS request when initializing the connection with the LDAP server.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      startTLS = true
authSources:
  ldapSource:
    ldap:
      startTLS: true

certificateAuthority

Optional, Default=""

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

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      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-----
            """
authSources:
  ldapSource:
    ldap:
      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-----

insecureSkipVerify

Optional, Default=false

When TLS is enabled, the connection to the LDAP server is verified to be secure. This option allows TraefikEE to proceed and operate even for server connections otherwise considered insecure.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      insecureSkipVerify = true
authSources:
  ldapSource:
    ldap:
      insecureSkipVerify: true

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.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      bindDN = "cn=admin,dc=example,dc=com"
authSources:
  ldapSource:
    ldap:
      bindDN: cn=admin,dc=example,dc=com

bindPassword

Optional, Default=""

The password to use in order to authenticate to the LDAP server.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      bindPassword = "mypassword"
authSources:
  ldapSource:
    ldap:
      bindPassword: mypassword

connPool

Optional, Default=None

In order to minimize the impact on the performance of requests using an LDAP authentication middleware, TraefikEE keeps a pool of connections to the LDAP server and reuses them instead of opening a new connection for each request.

connPool.size

Optional, Default=10

The number of connections managed by the pool can be customized with the size property.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      [authSources.ldapSource.ldap.connPool]
        size = 42
authSources:
  ldapSource:
    ldap:
      connPool:
        size: 42

connPool.burst

Optional, Default=5

burst connections are ephemeral connections that are opened when the pool is already full. Once the number of connection exceeds size + burst, a Too Many Connections error is returned.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      [authSources.ldapSource.ldap.connPool]
        burst = 42
authSources:
  ldapSource:
    ldap:
      connPool:
        burst: 42

connPool.ttl

Optional, Default=60s

Pooled connections are still meant to be short-lived, so they are closed after roughly one minute by default. This behavior can be modified with the ttl property.

[authSources]
  [authSources.ldapSource]
    [authSources.ldapSource.ldap]
      [authSources.ldapSource.ldap.connPool]
        ttl = 42s
authSources:
  ldapSource:
    ldap:
      connPool:
        ttl: 42s

LDAP Middleware

After declaring an LDAP Authentication Source in the static configuration of the cluster, LDAP middlewares can be added to routers.

The LDAP middleware will look for user credentials in the Authorization header of each request. Credentials must be encoded with the following format: base64(username:password).

Bind Mode vs Search Mode

If no filter is specified in its configuration, the middleware runs in the default bind mode, meaning that 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.

If a filter query is specified in the middleware configuration and the Authentication Source referenced has a bindDN and a password, 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 result of this search returns only 1 record, it tries to issue the bind request with this record to LDAP, otherwise it aborts a 401 Unauthorized status code.

Middleware Options

source

Required, Default=""

The source option should contain the name of the authentication source used by the middleware.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.source=ldapAuthSource"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      source: ldapAuthSource
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.source=ldapAuthSource"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.source": "ldapAuthSource"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.source=ldapAuthSource"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    source = "ldapAuthSource"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          source: ldapAuthSource

baseDN

Required, Default=""

The baseDN option should be set to the base domain name that should be used for bind and search queries.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.baseDN=dc=example,dc=com"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      baseDN: dc=example,dc=com
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.baseDN=dc=example,dc=com"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.baseDN": "dc=example,dc=com"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.baseDN=dc=example,dc=com"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    baseDN = "dc=example,dc=com"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          baseDN: dc=example,dc=com

attribute

Required, Default="cn"

The attribute used to search and bind a user. Queries use this pattern <attr>=<username>,<baseDN>.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.attribute=cn"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      attribute: cn
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.attribute=cn"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.attribute": "cn"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.attribute=cn"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    attribute = "cn"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          attribute: cn

forwardUsername

Optional, Default=""

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

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsername=true"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      forwardUsername: true
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsername=true"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsername": true
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsername=true"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    forwardUsername = true
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          forwardUsername: true

forwardUsernameHeader

Required, 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.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsernameHeader=userID"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      forwardUsernameHeader: userID
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsernameHeader=userID"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsernameHeader": "userID"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardUsernameHeader=userID"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    forwardUsernameHeader = "userID"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          forwardUsernameHeader: userID

forwardAuthorization

Required, Default=false

The forwardAuthorization option determines if the authorization header will be forwarded or stripped from a request after it has been approved by the middleware.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardAuthorization=true"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      forwardAuthorization: true
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardAuthorization=true"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardAuthorization": true
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.forwardAuthorization=true"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    forwardAuthorization = true
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          forwardAuthorization: true

searchFilter

Optional, Default=""

Filter queries can use the %s placeholder that is replaced by the username provided in the Authorization header of the request. For example: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s)).

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.searchFilter=(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      searchFilter: "(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.searchFilter=(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.searchFilter": "(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.searchFilter=(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    searchFilter = "(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          searchFilter: "(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"

wwwAuthenticateHeader

Optional, Default=false

When wwwAuthenticateHeader is enabled, the WWW-Authenticate header is set to Basic realm="<wwwAuthenticateHeaderRealm>"

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeader=true"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      wwwAuthenticateHeader: true
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeader=true"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeader": true
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeader=true"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    wwwAuthenticateHeader = true
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          wwwAuthenticateHeader: true

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.

labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeaderRealm=myRealm"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap
spec:
  plugin:
    ldapAuth:
      wwwAuthenticateHeaderRealm: "myRealm"
- "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeaderRealm=myRealm"
"labels": {
  "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeaderRealm": "myRealm"
}
labels:
  - "traefik.http.middlewares.test-ldap.plugin.ldapAuth.wwwAuthenticateHeaderRealm=myRealm"
[http.middlewares]
  [http.middlewares.test-ldap.plugin.ldapAuth]
    wwwAuthenticateHeaderRealm = "myRealm"
http:
  middlewares:
    test-ldap:
      plugin:
        ldapAuth:
          wwwAuthenticateHeaderRealm: "myRealm"

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.

Note

The realm directive of the WWW-Authenticate header can be customized with the wwwAuthenticateHeaderRealm option.

Advanced Configuration Examples

For applications to be secured with LDAP authentication, an ldapAuth middleware must be created and enabled in the router. Here are some examples of the middleware configuration in its simplest form depending on the provider you're using:

labels:
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.source=ldapSource"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.baseDN=dc=example,dc=org"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap-auth
spec:
  plugin:
    ldapAuth:
      source: ldapSource
      baseDN: dc=example,dc=org
[http.middlewares]
  [http.middlewares.test-ldap-auth.plugin.ldapAuth]
    source = "ldapSource"
    baseDN = "dc=example,dc=org"
http:
  middlewares:
    test-inflightreq:
      plugin:
        ldapAuth:
          source: ldapSource
          baseDN: dc=example,dc=org

Below is a more advanced configuration example using search, bind and the WWW-Authenticate header:

labels:
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.source=ldapSource"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.baseDN=dc=example,dc=org"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.searchFilter=(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.forwardUsername=true"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.forwardUsernameHeader=Custom-Username-Header-Name"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.wwwAuthenticateHeader=true"
  - "traefik.http.middlewares.test-ldap-auth.plugin.ldapAuth.wwwAuthenticateHeaderRealm=traefikee"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: test-ldap-auth
spec:
  plugin:
    ldapAuth:
      source: ldapSource
      baseDN: dc=example,dc=org
      searchFilter: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))
      forwardUsername: true
      forwardUsernameHeader: Custom-Username-Header-Name
      wwwAuthenticateHeader: true
      wwwAuthenticateHeaderRealm: traefikee
[http.middlewares]
  [http.middlewares.test-ldap-auth.plugin.ldapAuth]
    source = "ldapSource"
    baseDN = "dc=example,dc=org"
    searchFilter = "(&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))"
    forwardUsername = true
    forwardUsernameHeader = "Custom-Username-Header-Name"
    wwwAuthenticateHeader = true
    wwwAuthenticateHeaderRealm = "traefikee"
http:
  middlewares:
    test-ldap-auth:
      plugin:
        ldapAuth:
          source: ldapSource
          baseDN: dc=example,dc=org
          searchFilter: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))
          forwardUsername: true
          forwardUsernameHeader: Custom-Username-Header-Name
          wwwAuthenticateHeader: true
          wwwAuthenticateHeaderRealm: traefikee