mirror of
https://github.com/funkypenguin/geek-cookbook/
synced 2025-12-13 01:36:23 +00:00
207 lines
7.6 KiB
Markdown
207 lines
7.6 KiB
Markdown
---
|
|
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 # (1)!
|
|
PROVIDERS_OIDC_CLIENT_SECRET=bar #(2)!
|
|
PROVIDERS_OIDC_ISSUER_URL=https://dex.example.com # (3)!
|
|
SECRET=imtoosexyformyshorts # (4)!
|
|
AUTH_HOST=auth.example.com #(5)!
|
|
COOKIE_DOMAIN=example.com #(6)!
|
|
```
|
|
|
|
1. This is the staticClients.id value in config.yml above
|
|
2. This is the staticClients.secret value in config.yml above
|
|
3. This is the issuer value in config.yml above, and it has to be reachable via a browser
|
|
4. Make this up. It's not configured anywhere else
|
|
5. This should match the value of the traefik hosts labels in Traefik Forward Auth
|
|
6. 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: ['dex', 'serve','/config.yml']
|
|
deploy:
|
|
labels:
|
|
# traefik
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=traefik_public"
|
|
- "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
|
|
|
|
{% include 'recipe-footer.md' %}
|