--- title: SSO with traefik forward auth and Dex description: Traefik forward auth needs an authentication backend, but if you don't want to use a cloud provider, you can setup your own simple OIDC backend, using Dex. --- # Traefik Forward Auth for SSO with Dex (Static) [Traefik Forward Auth](/docker-swarm/traefik-forward-auth/) is incredibly useful to secure services with an additional layer of authentication, provided by an OIDC-compatible provider. The simplest possible provider is a self-hosted instance of [CoreOS's Dex](https://github.com/dexidp/dex), configured with a static username and password. This recipe will "get you started" with Traefik Forward Auth, providing a basic authentication layer. In time, you might want to migrate to a "public" provider, like [Google][tfa-google], or GitHub, or to a [Keycloak][keycloak] installation. --8<-- "recipe-tfa-ingredients.md" ## Preparation ### Setup dex config Create `/var/data/config/dex/config.yml` something like the following (*this is a bare-bones, [minimal example](https://github.com/dexidp/dex/blob/master/config.dev.yaml)*). At the very least, you want to replace all occurances of `example.com` with your own domain name. (*If you change nothing else, your ID is `foo`, your secret is `bar`, your username is `admin@yourdomain`, and your password is `password`*): ```yaml # The base path of dex and the external name of the OpenID Connect service. # # This is the canonical URL that all clients MUST use to refer to dex. If a # path is provided, dex's HTTP service will listen at a non-root URL. issuer: https://dex.example.com storage: type: sqlite3 config: file: var/sqlite/dex.db web: http: 0.0.0.0:5556 oauth2: skipApprovalScreen: true staticClients: - id: foo redirectURIs: - 'https://auth.example.com/_oauth' name: 'example.com' secret: bar enablePasswordDB: true staticPasswords: - email: "admin@example.com" # bcrypt hash of the string "password" hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" username: "admin" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" ``` ### Prepare Traefik Forward Auth environment Create `/var/data/config/traefik-forward-auth/traefik-forward-auth.env` per the following example configuration: ```bash DEFAULT_PROVIDER: oidc PROVIDERS_OIDC_CLIENT_ID: foo # This is the staticClients.id value in config.yml above PROVIDERS_OIDC_CLIENT_SECRET: bar # This is the staticClients.secret value in config.yml above PROVIDERS_OIDC_ISSUER_URL: https://dex.example.com # This is the issuer value in config.yml above, and it has to be reachable via a browser SECRET: imtoosexyformyshorts # Make this up. It's not configured anywhere else AUTH_HOST: auth.example.com # This should match the value of the traefik hosts labels in Traefik Forward Auth COOKIE_DOMAIN: example.com # This should match your base domain ``` ### Setup Docker Stack for Dex Now create a docker swarm config file in docker-compose syntax (v3), per the following example: ```yaml version: '3' services: dex: image: dexidp/dex volumes: - /etc/localtime:/etc/localtime:ro - /var/data/config/dex/config.yml:/config.yml:ro networks: - traefik_public command: ['serve','/config.yml'] deploy: labels: # traefik - traefik.enable=true - traefik.docker.network=traefik_public # traefikv1 - traefik.frontend.rule=Host:dex.example.com - traefik.port=5556 - traefik.docker.network=traefik_public # and for traefikv2: - "traefik.http.routers.dex.rule=Host(`dex.example.com`)" - "traefik.http.routers.dex.entrypoints=https" - "traefik.http.services.dex.loadbalancer.server.port=5556" networks: traefik_public: external: true ``` --8<-- "premix-cta.md" ### Setup Docker Stack for Traefik Forward Auth Now create a docker swarm config file for traefik-forward-auth, in docker-compose syntax (v3), per the following example: ```yaml version: "3.2" services: traefik-forward-auth: image: thomseddon/traefik-forward-auth:2.2.0 env_file: /var/data/config/traefik-forward-auth/traefik-forward-auth.env volumes: - /var/data/config/traefik-forward-auth/config.ini:/config.ini:ro networks: - traefik_public deploy: labels: # traefikv1 - "traefik.port=4181" - "traefik.frontend.rule=Host:auth.example.com" - "traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181" - "traefik.frontend.auth.forward.trustForwardHeader=true" # traefikv2 - "traefik.docker.network=traefik_public" - "traefik.http.routers.auth.rule=Host(`auth.example.com`)" - "traefik.http.routers.auth.entrypoints=https" - "traefik.http.routers.auth.tls=true" - "traefik.http.routers.auth.tls.domains[0].main=example.com" - "traefik.http.routers.auth.tls.domains[0].sans=*.example.com" - "traefik.http.routers.auth.tls.certresolver=main" - "traefik.http.routers.auth.service=auth@docker" - "traefik.http.services.auth.loadbalancer.server.port=4181" - "traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181" - "traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true" - "traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User" - "traefik.http.routers.auth.middlewares=forward-auth" # This simply validates that traefik forward authentication is working whoami: image: containous/whoami networks: - traefik_public deploy: labels: # traefik - "traefik.enable=true" - "traefik.docker.network=traefik_public" # traefikv1 - "traefik.frontend.rule=Host:whoami.example.com" - "traefik.http.services.whoami.loadbalancer.server.port=80" - "traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181" - "traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User" - "traefik.frontend.auth.forward.trustForwardHeader=true" # traefikv2 - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)" - "traefik.http.routers.whoami.entrypoints=https" - "traefik.http.services.whoami.loadbalancer.server.port=80" - "traefik.http.routers.whoami.middlewares=forward-auth" networks: traefik_public: external: true ``` ## Serving ### Launch Deploy dex with `docker stack deploy dex -c /var/data/dex/dex.yml`, to launch dex, and then deploy Traefik Forward Auth with `docker stack deploy traefik-forward-auth -c /var/data/traefik-forward-auth/traefik-forward-auth.yml` Once you redeploy traefik-forward-auth with the above, it **should** use dex as an OIDC provider, authenticating you against the `staticPasswords` username and hashed password described in `config.yml` above. ### Test Browse to `https://whoami.example.com` (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you'll be redirected to a CoreOS Dex login. Once successfully logged in, you'll be directed to the basic whoami page :thumbsup: ### Protect services To protect any other service, ensure the service itself is exposed by Traefik. Add the following label: ```yaml - "traefik.http.routers.radarr.middlewares=forward-auth" ``` And re-deploy your services :) ## Summary What have we achieved? By adding an additional label to any service, we can secure any service behind our (static) OIDC provider, with minimal processing / handling overhead. !!! summary "Summary" Created: * [X] Traefik-forward-auth configured to authenticate against Dex (static) [^1]: You can remove the `whoami` container once you know Traefik Forward Auth is working properly --8<-- "recipe-footer.md"