Traefik Forward Auth

Traefik’s Dashboard doesn’t have user authentication by default, which means you need to implement authentication through other methods. The simplest method is to use the Basic Auth middleware, and another slightly more complex solution is to use an AccessToken as authentication credentials in the Dashboard route.
However, both methods above are not flexible enough. In a team environment, we might want to dynamically add authentication and manage it flexibly.
Prerequisites⌗
- Traefik: https://traefik.svc.dev
- Zitadel: https://zitadel.svc.dev
- OAuth2 Proxy: https://authentication.svc.dev
Zitadel is an open-source external identity provider. If you’re not familiar with Zitadel, you can check out my article Open Source Identity Authentication and Authorization Solutions.
Traefik Configuration⌗
services:
traefik:
image: traefik:latest
labels:
- traefik.tls.stores.default.defaultgeneratedcert.resolver=step-ca
- traefik.tls.stores.default.defaultgeneratedcert.domain.main=svc.dev
- traefik.tls.stores.default.defaultgeneratedcert.domain.sans=*.svc.dev
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.traefik-dashboard.tls=true
- traefik.http.routers.traefik-dashboard.tls.certresolver=step-ca
- traefik.http.routers.traefik-dashboard.rule=Host(`traefik.svc.dev`)
- traefik.http.routers.traefik-dashboard.entrypoints=http,https
- traefik.http.routers.traefik-dashboard.service=dashboard@internal
# Set middleware for Traefik Dashboard
- traefik.http.routers.traefik-dashboard.middlewares=unauthentication@docker,authentication@docker
- traefik.http.routers.traefik-dashboard-api.tls=true
- traefik.http.routers.traefik-dashboard-api.tls.certresolver=step-ca
- traefik.http.routers.traefik-dashboard-api.rule=Host(`traefik.svc.dev`) && PathPrefix(`/api`)
- traefik.http.routers.traefik-dashboard-api.entrypoints=http,https
- traefik.http.routers.traefik-dashboard-api.service=api@internal
# Set middleware for Traefik Dashboard
- traefik.http.routers.traefik-dashboard-api.middlewares=unauthentication@docker,authentication@docker
# Set up /oauth2 route for Traefik, forwarding to OAuth2 proxy
- traefik.http.routers.traefik-oauth.tls=true
- traefik.http.routers.traefik-oauth.tls.certresolver=step-ca
- traefik.http.routers.traefik-oauth.rule=Host(`traefik.svc.dev`) && PathPrefix(`/oauth2`)
- traefik.http.routers.traefik-oauth.entrypoints=http,https
- traefik.http.routers.traefik-oauth.service=authentication
- traefik.http.routers.traefik-oauth.middlewares=unauthentication@docker
- traefik.http.middlewares.authentication.forwardauth.address=https://authentication.svc.dev/oauth2/auth
- traefik.http.middlewares.authentication.forwardauth.trustForwardHeader=true
- traefik.http.middlewares.authentication.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Preferred-Username,X-Auth-Request-Access-Token,X-Auth-Request-Groups,Authorization,Set-Cookie,Location
- traefik.http.middlewares.authentication.forwardauth.tls.insecureSkipVerify=true
- traefik.http.middlewares.unauthentication.errors.query=/oauth2/sign_in
- traefik.http.middlewares.unauthentication.errors.status=401-403
- traefik.http.middlewares.unauthentication.errors.service=authentication
restart: always
hostname: traefik
networks:
- traefik
command:
- --api=true
- --api.insecure=false
- --api.dashboard=true
- --log.level=ERROR
- --ping=true
- --providers.file=true
- --providers.file.watch=true
- --providers.file.directory=/etc/traefik/config
- --providers.file.debugloggeneratedtemplate=true
- --providers.docker=true
- --providers.docker.watch=true
- --providers.docker.network=traefik
- --providers.docker.useBindPortIP=false
- --providers.docker.endpoint=unix:///var/run/docker.sock
- --entrypoints.http.address=:80
- --entrypoints.http.http.redirections.entryPoint.to=https
- --entrypoints.http.http.redirections.entryPoint.scheme=https
- --entryPoints.http.http.redirections.entrypoint.permanent=true
- --entrypoints.https.address=:443
- --entryPoints.https.http3.advertisedport=443
- --entryPoints.https.http.tls.certResolver=step-ca
- --entryPoints.https.http.tls.domains[0].main=svc.dev
- --entryPoints.https.http.tls.domains[0].sans=*.svc.dev
- --serverstransport.insecureskipverify=true
volumes:
- ./certs/:/certs/:rw
- ./config/:/etc/traefik/config/:ro
- /var/run/docker.sock:/var/run/docker.sock
environment:
- TZ=Asia/Shanghai
container_name: traefik
networks:
traefik:
external: true
OAuth2 Proxy Configuration⌗
services:
authentication:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1
labels:
- traefik.enable=true
- traefik.http.routers.authentication.tls=true
- traefik.http.routers.authentication.tls.certresolver=step-ca
- traefik.http.routers.authentication.rule=Host(`authentication.svc.dev`) && PathPrefix(`/oauth2/`)
- traefik.http.routers.authentication.service=authentication
- traefik.http.routers.authentication.entrypoints=http,https
- traefik.http.routers.authentication.middlewares=authentication-headers@docker
- traefik.http.services.authentication.loadbalancer.server.port=4180
- traefik.http.middlewares.authentication-headers.headers.sslHost=svc.dev
- traefik.http.middlewares.authentication-headers.headers.frameDeny=true
- traefik.http.middlewares.authentication-headers.headers.stsSeconds=315360000
- traefik.http.middlewares.authentication-headers.headers.stsPreload=true
- traefik.http.middlewares.authentication-headers.headers.sslRedirect=true
- traefik.http.middlewares.authentication-headers.headers.forceSTSHeader=true
- traefik.http.middlewares.authentication-headers.headers.browserXssFilter=true
- traefik.http.middlewares.authentication-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.authentication-headers.headers.stsIncludeSubdomains=true
volumes:
- ./templates:/templates
restart: no
hostname: authentication
networks:
- traefik
environment:
- OAUTH2_PROXY_PROVIDER=oidc
- OAUTH2_PROXY_PROVIDER_DISPLAY_NAME=ZITADEL
- OAUTH2_PROXY_PROVIDER_CA_FILES=/root_ca.crt
- OAUTH2_PROXY_HTTP_ADDRESS=0.0.0.0:4180
- OAUTH2_PROXY_EMAIL_DOMAINS=*
- OAUTH2_PROXY_OIDC_ISSUER_URL=https://zitadel.svc.dev
- OAUTH2_PROXY_CLIENT_ID=
- OAUTH2_PROXY_CLIENT_SECRET=
- OAUTH2_PROXY_COOKIE_NAME=authentication
- OAUTH2_PROXY_COOKIE_SECURE=true
- OAUTH2_PROXY_COOKIE_SECRET=
- OAUTH2_PROXY_COOKIE_DOMAINS=.svc.dev
- OAUTH2_PROXY_WHITELIST_DOMAINS=*.svc.dev
- OAUTH2_PROXY_REVERSE_PROXY=true
- OAUTH2_PROXY_PASS_ACCESS_TOKEN=true
- OAUTH2_PROXY_CUSTOM_TEMPLATES_DIR=/templates
- OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL=true
- OAUTH2_PROXY_UPSTREAMS=file:///dev/null
- OAUTH2_PROXY_UPSTREAM_TIMEOUT=30s
- OAUTH2_PROXY_SSL_INSECURE_SKIP_VERIFY=true
- OAUTH2_PROXY_SSL_UPSTREAM_INSECURE_SKIP_VERIFY=false
container_name: authentication
volumes:
step-ca:
name: step-ca
external: true
networks:
traefik:
external: true
Zitadel Configuration⌗
With the above configuration, you can implement user authentication for the Traefik Dashboard.
I hope this is helpful, Happy hacking…