Dogfooding it, Pt 7 - Authentik

I was trying to avoid this. Getting into authentication is a rabbit hole. For the moment, I am choosing Authentik because it is reasonably easy to configure, and supports the features I want.

For a good start, Authentik uses Redis / Valkey as memory cache. So, we'll need to set that up. The relevant compose file fragment is

  valkey:
    command: "valkey-server --save 30 1"
    deploy:
      replicas: 1
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      start_period: 20s
      interval: 30s
      timeout: 3s
    image: "valkey/valkey:7.2-alpine"
    logging:
      driver: journald
    networks:
      - homelab
    restart: unless-stopped
    user: "10007:10007"
    volumes:
      - "/srv/data/docker/redis/data:/data"

And create the directory for the Docker volume:

$ mkdir -p /srv/data/docker/valkey/data
$ sudo chown -R 10007:10007 /srv/data/docker/valkey
$ sudo chmod -R g-rwx,o-rwx /srv/data/docker/valkey

With the preparation for Authentik done, it's time to deploy the Authentik application itself. For the moment, we will NOT allow Authentik to manage its own outposts - we'll simply use the one integrated in the server. Authentik consists of two containers, the frontend server and a worker; they share some volumes, but we will not locate these in /srv/data/shared, as they are all internal to Authentik and will not be exported to and by a variety of unrelated services.

$ mkdir -p /srv/data/docker/authentik/{certs,custom-templates,media}
$ sudo chown -R 10008:10008 /srv/data/docker/authentik
$ sudo chmod -R g-rwx,o-rwx /srv/data/docker/authentik
$ pwgen > secrets/authentik-postgres
$ cat /dev/urandom | tr -cd [:graph:] | fold -w 60 | head -n1 > secrets/authentik-secret

Add those to the docker-compose secrets, in the root secrets section:

  authentik-postgres:
    - file: /home/<your user>/secrets/authentik-postgres
  authentik-secret:
    - file: /home/<your user>/secrets/authentik-secret

And, add in the postgres section, to the secrets section:

      - authentik-postgres

Now, redeploy the stack, to make the changes live:

$ docker stack deploy -c <dockerfile> --prune homelab

Now create the database for Authentik:

$ docker container ls
$ docker container exec -it <postgres container ID> bash
$ $ psql -U postgres << EOSQL
create role authentik with login password '$(cat /run/secrets/authentik-postgres)';
create database authentik with owner authentik;
grant all privileges on database authentik to authentik;
EOSQL

Finally, we set up the containers for Authentik:

  authentik-server:
    command: server
    depends_on:
      - postgres
      - redis
    deploy:
      labels:
        traefik.enable: "true"
        traefik.http.routers.authentik-rtr.rule: 'Host(`authentik.your.domain`) || HostRegexp(`{subdomain:[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?}.your.domain`) && PathPrefix(`/outpost.goauthentik.io/`)'
        traefik.http.routers.authentik-rtr.service: "authentik"
        traefik.http.services.authentik.loadbalancer.server.port: "9000"
        traefik.http.middlewares.authentik.forwardauth.address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
        traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
        traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: "X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
      replicas: 1
    environment:
      AUTHENTIK_POSTGRESQL__HOST: "postgres"
      AUTHENTIK_POSTGRESQL__NAME: "authentik"
      AUTHENTIK_POSTGRESQL__USER: "authentik"
      AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/authentik-postgres"
      AUTHENTIK_REDIS__HOST: "valkey"
      AUTHENTIK_SECRET_KEY: "file:///run/secrets/authentik-secret"
      AUTHENTIK_EMAIL__HOST: "munin.your.domain"
      AUTHENTIK_EMAIL__FROM: "authentik@turriff.net"
    hostname: "authentik-server"
    image: "ghcr.io/goauthentik/server:2024.4"
    logging:
      driver: journald
    networks:
      - homelab
    restart: on-failure
    secrets:
      - authentik-postgres
      - authentik-secret
    user: "10008:10008"
    volumes:
      - "/srv/data/docker/authentik/media:/media"
      - "/srv/data/docker/authentik/custom-templates:/templates"

  authentik-worker:
    command: worker
    depends_on:
      - postgres
      - redis
    deploy:
      replicas: 1
    environment:
      AUTHENTIK_POSTGRESQL__HOST: "postgres"
      AUTHENTIK_POSTGRESQL__NAME: "authentik"
      AUTHENTIK_POSTGRESQL__USER: "authentik"
      AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/authentik-postgres"
      AUTHENTIK_REDIS__HOST: "valkey"
      AUTHENTIK_SECRET_KEY: "file:///run/secrets/authentik-secret"
      AUTHENTIK_EMAIL__HOST: "munin.your.domain"
      AUTHENTIK_EMAIL__FROM: "authentik@turriff.net"
    image: "ghcr.io/goauthentik/server:2024.4"
    logging:
      driver: journald
    networks:
      - homelab
    restart: on-failure
    secrets:
      - authentik-postgres
      - authentik-secret
    user: "10008:10008"
    volumes:
      - "/srv/data/docker/authentik/media:/media"
      - "/srv/data/docker/authentik/certs:/certs"
      - "/srv/data/docker/authentik/custom-templates:/templates"

Most of this should be pretty self-explanatory at this point. We do configure a Traefik middleware when the Authentik frontend comes up, to implement forward-auth.

Time to bring the stack up.

$ docker stack deploy -c <compose file> --prune homelab

Authentik needs a bit of configuration, which I'll demonstrate for Traefik's dashboard. Any other application requiring forward-auth (you can tell by it being labeled to use the middleware authentik@swarm) will work analog to this.

First, though, we need to do the basic Authentik configuration. You'll need to access https://authentik.<your domain>/if/flow/initial-setup/ and follow the steps to set up your built-in admin user. You can add other users by going to the Admin Interface > Directory > Users > Create. For the moment, all users so created will have access to all applications you protect. Policy setup for Authentik is beyond my scope at the moment.

Next, we'll want to properly protect Traefik's dashboard, instead of relying on IP whitelisting. The steps are

  1. Go to the Admin Interface
  2. Go to Applications > Providers > Create
  3. Select Proxy Provider
  4. Name: Traefik
  5. Authentication Flow: default-authentication-flow
  6. Authorization Flow: default-provider-authorization-explicit-consent
  7. Forward Auth (Single Application)
  8. External Host: https://traefik.your.domain
  9. Finish
  10. Go to Applications > Applications > Create
  11. Name: Traefik
  12. Slug: traefik-slug
  13. Finish

Now modify Traefik's section in your docker compose file, and replace the current middleware line with

       traefik.http.routers.traefik-rtr.middlewares: "authentik@swarm"

Hitting https://traefik.your.domain should now greet you with an Authentik logon.

Subscribe to Homelab Adventures

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe