This is a long post with several long configuration file so TLDR; download the docker-compose file, the OpenLDAP base.ldif and the Athelia config.yml

! Please change all the usernames and passwords in the above files !

Authelia

Protect your applications with Single Sign-On and 2 Factor. Authelia is an open-source full-featured authentication server available on Github .

Traefik

Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience.

I have been trying to setup up Authelia with Traefik as an authentiation middleware for a while and got close many time but it never quite worked. I had searched many many forums and eventually managed to find a valid configuration. However, I didn’t keep track of these sites.

Structure

The folder structure should be something as follows

.
|-- docker-compose.yml
|-- .env
|-- volumes/
|   |-- authelia/
|   |   |-- config.yml
|   |   |-- database/
|   |-- heimdall/
|   |-- ldap/
|   |   |-- custom_config/
|   |   |   |-- base.ldif
|   |   |-- data/
|   |   |-- slapd/

Docker Compose

Initally, we define the Traefik service and a service that can be protected by the authentication middleware. Note, in production, the dashboard should be protected but for this we are leaving it open to make life slightly easier during setup.

This configuration of Traefik enables the dashboard and the api, defines two entrypoints for HTTP (named web) and HTTPS (named websecure). The service also creates an HTTPS middleware that will redirect any HTTP traffic to HTTPS, assuming the middleware is enabled.

version: "3"

services:
  traefik:
    image: traefik:v2.2
    container_name: traefik
    command:
      - "--log.level=DEBUG"
      - "--api=true"
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "80:80"
      - "443:443"
    links:
      - authelia
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
      - "traefik.http.middlewares.compressor.compress=true"
      - "traefik.enable=true"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.rule=Host(`traefik.${DOMAIN}`)"
      - "traefik.http.routers.api.entrypoints=web"
      - "traefik.http.routers.api.middlewares=https-redirect"
      - "traefik.http.routers.api-secure.rule=Host(`traefik.${DOMAIN}`)"
      - "traefik.http.routers.api-secure.entrypoints=websecure"
      - "traefik.http.routers.api-secure.tls=true"

  heimdall:
    image: linuxserver/heimdall
    container_name: heimdall
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
    volumes:
      - ${VOLUMES}/heimdall:/config
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.heimdall.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.heimdall.entrypoints=web"
      - "traefik.http.routers.heimdall.middlewares=https-redirect"
      - "traefik.http.routers.heimdall-secure.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.heimdall-secure.entrypoints=websecure"
      - "traefik.http.routers.heimdall-secure.middlewares=authelia"
      - "traefik.http.routers.heimdall-secure.tls=true"

Authelia

This setup of Authelia will use the LDAP authentication backend, MySQL for data storage and Redis for session management. Currently I haven’t managed to setup a notifer yet and so this is left as the default file system notifier.

docker-compose

The setup of Authelia uses the domain auth.${DOMAIN}, where domain is set in your .env file. The connection to MySQL, Redis and OpenLDAP are done via docker links, meaning all this communication is local and never accessible externally.

For more detailed information about the OpenLDAP setup, you can visit the GitHub page for the image here.

   authelia:
    image: authelia/authelia:4.6
    container_name: authelia
    environment:
      - TZ=Europe/London
    volumes:
      - ${VOLUMES}/authelia/config.yml:/etc/authelia/configuration.yml:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)"
      - "traefik.http.routers.authelia.entrypoints=web"
      - "traefik.http.routers.authelia.middlewares=https-redirect"
      - "traefik.http.routers.authelia-secure.rule=Host(`auth.${DOMAIN}`)"
      - "traefik.http.routers.authelia-secure.entrypoints=websecure"
      - "traefik.http.routers.authelia-secure.tls=true"
      - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/"
      - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=X-Forward-User"

  authelia_mysql:
    image: linuxserver/mariadb
    container_name: mariadb
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=helloworld
      - TZ=Europe/London
      - MYSQL_DATABASE=authelia
      - MYSQL_USER=authelia
      - MYSQL_PASSWORD=helloworld
    volumes:
      - ${VOLUMES}/authelia/database:/config
    expose:
      - 3306

  authelia_redis:
    image: redis
    container_name: redis
    expose:
      - 6379

  openldap:
    image: osixia/openldap:1.3.0
    container_name: openldap
    command:
      - "--copy-service"
      - "--loglevel=debug"
    environment:
      - LDAP_LOG_LEVEL=256
      - LDAP_ORGANISATION=MyOrganisation
      - LDAP_DOMAIN=${DOMAIN}
      - LDAP_ADMIN_PASSWORD=helloworld
      - LDAP_CONFIG_PASSWORD=helloworld
      - LDAP_READONLY_USER=true
      - LDAP_READONLY_USER_USERNAME=readonly
      - LDAP_READONLY_USER_PASSWORD=readonly
      - LDAP_ADDITIONAL_MODULES=memberof
      - LDAP_ADDITIONAL_SCHEMAS=openldap
      - LDAP_TLS=false
      - LDAP_TLS_VERIFY_CLIENT=false
    volumes:
      - ${VOLUMES}/ldap/custom_config:/container/service/slapd/assets/config/bootstrap/ldif/custom
      - ${VOLUMES}/ldap/data:/var/lib/ldap
      - ${VOLUMES}/ldap/slapd:/etc/ldap/slapd.d
    expose:
      - 389
      - 636

Authelia Config

Once all the relevant services have been configured, Authelia’s config can be created. This will define how Authelia connects to these services as well as how they are used.

The configuration file below will use example.co.uk as the domain. This makes the configuration easier to understand, particularly the ldap section. Whenever the domain is reference in the LDAP configuration section each full stop in the domain becomes a ‘dc=’ e.g.

  • example.co.uk => dc=example,dc=co,dc=uk
  • example.com => dc=example,dc=com
  • sub.example.com => dc=sub,dc=example,dc=com

The example Authelia configuration file gives a very good description of the various values defined in the configuraiton file below. Found here.

host: 0.0.0.0
port: 9091
log_level: debug

jwt_secret: some_secret_secret
default_redirection_url: https://example.co.uk/

authentication_backend:
  ldap:
    # 'openldap' is the name of the link defined in the docker-compose file
    url: ldap://openldap
    skip_verify: false
    base_dn: dc=example,dc=co,dc=uk
    username_attribute: uid
    additional_users_dn: ou=users
    users_filter: (cn={0})
    additional_groups_dn: ou=groups
    groups_filter: (&(member={dn})(objectclass=groupOfNames))
    group_name_attribute: cn
    mail_attribute: mail
    user: cn=admin,dc=example,dc=co,dc=uk
    password: helloworld

access_control:
  default_policy: one_factor
  rules:
    - domain: example.co.uk
      policy: bypass

    - domain: traefik.example.co.uk
      policy: one_factor

session:
  name: authelia_session
  expiration: 3600
  inactivity: 600
  domain: example.co.uk
  secret: some_secret_secret

  redis:
    # 'authelia_redis' is the name of the link in the docker-compose file
    host: authelia_redis
    port: 6379

regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300

storage:
  mysql:
    # 'authelia_mysql' is the name of the link in the docker-compose file
    host: authelia_mysql
    port: 3306
    database: authelia
    username: authelia
    password: helloworld

notifier:
  filesystem:
    filename: /tmp/authelia/notification.txt

OpenLDAP Config

The LDAP configuration requires several groups to be setup before users can be created. As seen in the docker-compose entry, there is a custom config folder mapped into the container. This allows us to define a set of users and groups to be created upon container initialization.

This LDIF file will create a unit to hold two groups, ‘dev’ and ‘admin’ and then a unit to hold users. These users are then added to the groups. The example below defines an admin group whose sole member is John Doe. You can copy the relevant sections to create more users and groups as you will.

dn: ou=groups,dc=example,dc=co,dc=uk
objectclass: organizationalUnit
objectclass: top
ou: groups

dn: ou=users,dc=example,dc=co,dc=uk
objectclass: organizationalUnit
objectclass: top
ou: users

dn: cn=dev,ou=groups,dc=example,dc=co,dc=uk
cn: dev
member: cn=john,dc=example,dc=co,dc=uk
objectclass: groupOfNames
objectclass: top

dn: cn=admins,ou=groups,dc=example,dc=co,dc=uk
cn: admins
member: cn=john,ou=users,dc=example,dc=co,dc=uk
objectclass: groupOfNames
objectclass: top

dn: cn=john,ou=users,dc=example,dc=co,dc=uk
cn: john
objectclass: inetorgPerson
objectclass: top
mail: john.doe@example.co.uk
sn: John Doe
userpassword: helloworld

OpenLDAP Admin

To help out with the management of users or to create more, you can use the phpLDAPadmin docker image, also by osixia, to provide a phpMyAdmin like interface to OpenLDAP. To enable this add the following to the bottom of the docker-compose file. You should also enable the authelia authentication middleware here as this service should be protected. For ease-of-use during the setup and to help debug it is left open.

  phpldapadmin:
    image: osixia/phpldapadmin
    container_name: phpldapadmin
    environment:
      - PHPLDAPADMIN_HTTPS=false
      - PHPLDAPADMIN_LDAP_HOSTS=openldap
    depends_on:
      - openldap
    links:
      - openldap:openldap
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.ldap.rule=Host(`ldap.${DOMAIN}`)"
      - "traefik.http.routers.ldap.entrypoints=web"
      - "traefik.http.routers.ldap.middlewares=https-redirect"
      - "traefik.http.routers.ldap-secure.rule=Host(`ldap.${DOMAIN}`)"
      - "traefik.http.routers.ldap-secure.entrypoints=websecure"
      - "traefik.http.routers.ldap-secure.tls=true"