Traefik SSO with Authelia across multiple hosts

Over the last few days I've been trying to get Authelia and Traefik to play nice with each-other across multiple hosts.

The idea being, Authelia runs on one of my hosts (let's call it AuthServer) behind a Traefik instance, managing authentication to apps on that server, but also to another server's apps (let's call that one AppServer).

Prerequisites

I'm assuming that you have a working Traefik instance using docker-compose to configure it, as well as a working Authelia instance. A good starting point for the Authelia configuration is the Lite Bundle from their Docker documentation.

We will be using our entrypoint websecure which handles all HTTPS traffic and in this tutorial we'll be protecting the Traefik API dashboard with Authelia on both the AppServer and AuthServer. Any additional services can then easily be added in the future.

AuthServer configuration

Traefik Configuration

We'll start with configuring Traefik on the AuthServer. Please note that the snippets below are an abbreviated version, only highlighting relevant lines that you need to take into account.

services:
  traefik:
    image: "traefik:latest"
    restart: unless-stopped
    [...]
    command:
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # Authelia Third Party Hosts
      - "--entryPoints.websecure.forwardedHeaders.trustedIPs=10.0.0.0/8"
      - "--entryPoints.websecure.proxyProtocol.trustedIPs=10.0.0.0/8"
      [...]

    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.example.com`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls=true"
      [...]
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - 'traefik.http.routers.traefik.middlewares=authelia@docker'

docker-compose.yml (Traefik)

In the command section above we define foreardedHeaders and proxyProtocol to trust other services' headers. Be sure to add the IP addresses of your other hosts (i.e. AppServer) here.

As we're configuring Traefik with Docker Labels, we'll add the definition for the AuthServer's Traefik API dashboard under the labels, and then protect it with the authelia middleware.

Authelia configuration

Now let's configure the Authelia container, so that Traefik's Dashboard can authenticate against it.

services:
  authelia:
    image: authelia/authelia
    container_name: authelia
    [...]
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.authelia.rule=Host(`auth.example.com`)'
      - 'traefik.http.routers.authelia.entrypoints=websecure'
      - 'traefik.http.routers.authelia.tls=true'
      [...]
      - 'traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/authz/forward-auth'
      - 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
      - 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email'
      [...]
    expose:
      - 9091
    [...]

docker-compose.yml (Authelia)

We're hosting Authelia on AuthServer as well and will be serving it on auth.example.com on the websercure entrypoint.

Authelia configuration

Last step is to make sure we configure traefik-dashboard.example.com under our access control policies. For this, edit Authelia's configuration.yml.

access_control:
  default_policy: 'deny'
  rules:
    - domain: 'traefik-dashboard.example.com'
      policy: 'two_factor'

configuration.yml (Authelia)

The above access policy will by default deny all access to undefined resources. For the traefik-dashboard.example.com domain, we'll be overriding the default deny and require two_factor authentication. You can also apply the one_factor policy or disable authentication by using bypass - although the latter wouldn't make any sense.

Testing the first part

Now, redeploy the containers so that they apply the new labels and configuration and check that Authelia works as expected on traefik-dashboard.example.com. It should redirect you to auth.example.com if you're not logged in.

In case it doesn't work, the Authelia logs are generally super helpful and will give more information why access was or wasn't granted.

AppServer configuration

With Authelia working as expected behind Traefik on a single host, let's configure our second host, AppServer, to forward requests to the AuthServer's Authelia instance.

Traefik configuration

We will configure the Authelia middleware and apply it to the API dashboard of Traefik.

  traefik:
    image: "traefik:latest"
    restart: unless-stopped
    command:
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      [...]
    [...]
    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`app-dashboard.example.com`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls=true"
      [...]
      - "traefik.http.routers.traefik.entrypoints=websecure"
      #Authelia Config
      - 'traefik.http.middlewares.authelia.forwardauth.address=https://auth.example.com/api/authz/forward-auth'
      - 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
      - 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email'
      - "traefik.http.routers.traefik.middlewares=authelia"

The above snippet will configure the API to be served on the websecure entrypoint on app-dashboard.example.com and adds a middleware called authelia that will redirect all authentication to auth.example.com.

As we have now defined the middleware, for any subsequent router rules, you only need to add the following line to the container that's being exposed by Traefik on the AppServer host: - "traefik.http.routers.ROUTERNAME.middlewares=authelia"

Authelia configuration (on AuthServer)

Lastly, we'll just need to update our Authelia configuration.yml policies on the AuthServer to handle this additional host.

access_control:
  default_policy: 'deny'
  rules:
    [...]
    - domain: 'app-dashboard.example.com'
      policy: 'one_factor'

We'll add the domain with a one_factor policy.

All done!

That should be it! You should now have Authelia running on AuthServer, protecting your content on AppServer, all levaraging your SSO policies on a single server. Remember to keep the trustedIPs up to date on the AuthServer traefik configuration, as every remote Traefik server needs to be trusted for the headers to be read correctly.