Skip to content

lukaszraczylo/traefikoidc

Repository files navigation

Traefik OIDC middleware

This middleware is supposed to replace the need for the forward-auth and oauth2-proxy when using traefik as a reverse proxy to support the OIDC authentication.

Middleware has been tested with Auth0 and Logto.

Traefik version compatibility

Code follows closely the current traefik helm chart versions. If plugin fails to load - it's time to update to the latest version of the traefik helm chart.

Configuration options

Middleware currently supports following scenarios:

  • Setting custom callback and logout URLs via callbackURL and logoutURL
  • Allowing for access only from the listed domains if allowedUserDomains is set, otherwise it relies entirely on the OIDC provider
  • Using excluded URLs which do NOT require the OIDC authentication
  • Rate limiting requests to prevent the bruteforce attacks

How to configure...

Keeping secrets secret

This works ONLY in kubernetes environments. Don't forget to create secret traefik-middleware-oidc with fields ISSUER, CLIENT_ID and SECRET keys.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: oidc-with-open-urls
  namespace: traefik
spec:
  plugin:
    traefikoidc:
      providerURL: urn:k8s:secret:traefik-middleware-oidc:ISSUER
      clientID: urn:k8s:secret:traefik-middleware-oidc:CLIENT_ID
      clientSecret: urn:k8s:secret:traefik-middleware-oidc:SECRET
      sessionEncryptionKey: vvv
      callbackURL: /cool-oidc/callback
      logoutURL: /cool-oidc/logout
      postLogoutRedirectURI: /my-website/you-have-logged-out # Optional post logout URL redirection
      scopes:
        - openid
        - email
        - profile
      excludedURLs: # Determines the list of URLs which are NOT a subject to authentication
        - /login # covers /login, /login/me, /login/reminder etc.
        - /my-public-data
Excluded URLs with open access
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: oidc-with-open-urls
  namespace: traefik
spec:
  plugin:
    traefikoidc:
      providerURL: xxx
      clientID: yyy
      clientSecret: zzz
      sessionEncryptionKey: vvv
      callbackURL: /cool-oidc/callback
      logoutURL: /cool-oidc/logout
      scopes:
        - openid
        - email
        - profile
      excludedURLs: # Determines the list of URLs which are NOT a subject to authentication
        - /login # covers /login, /login/me, /login/reminder etc.
        - /my-public-data
Allowed email domains

Assuming that your OIDC provider allows anyone to log in, you may want to limit the access to people using emains in specific domain.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: oidc-only-my-users
  namespace: traefik
spec:
  plugin:
    traefikoidc:
      providerURL: xxx
      clientID: yyy
      clientSecret: zzz
      sessionEncryptionKey: vvv
      callbackURL: /new-oidc/callback
      logoutURL: /new-oidc/logout
      scopes:
        - openid
        - email
        - profile
      allowedUserDomains:
        - raczylo.com
Allowed groups and roles

In case of multiple roles / groups and access separation for various endpoints you will need to create multiple traefik middlewares. Following example allows access for users who have additional role guest-endpoints assigned.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: oidc-guest-endpoints
  namespace: traefik
spec:
  plugin:
    traefikoidc:
      providerURL: xxx
      clientID: yyy
      clientSecret: zzz
      sessionEncryptionKey: vvv
      callbackURL: /my-oidc/callback
      logoutURL: /my-oidc/logout
      scopes:
        - openid
        - email
        - profile
        - roles     # This line queries the OIDC provider for roles
      forceHTTPS: true
      allowedRolesAndGroups:
        - guest-endpoints  # This line specifies the roles or groups allowed to access content
      allowedUserDomains:
        - raczylo.com

Docker compose example

docker-compose.yaml

version: "3.7"

services:
  traefik:
    image: traefik:v3.0.1
    command:
      - "--experimental.plugins.traefikoidc.modulename=github.com/lukaszraczylo/traefikoidc"
      - "--experimental.plugins.traefikoidc.version=v0.2.1"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik-config/traefik.yml:/etc/traefik/traefik.yml
      - ./traefik-config/dynamic-configuration.yml:/etc/traefik/dynamic-configuration.yml
    labels:
      - "traefik.http.routers.dash.rule=Host(`dash.localhost`)"
      - "traefik.http.routers.dash.service=api@internal"

    ports:
      - "80:80"

  hello:
    image: containous/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.hello.entrypoints=http
      - traefik.http.routers.hello.rule=Host(`hello.localhost`)
      - traefik.http.services.hello.loadbalancer.server.port=80
      - traefik.http.routers.hello.middlewares=my-plugin@file

  whoami:
    image: jwilder/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.entrypoints=http
      - traefik.http.routers.whoami.rule=Host(`whoami.localhost`)
      - traefik.http.services.whoami.loadbalancer.server.port=8000
      - traefik.http.routers.whoami.middlewares=my-plugin@file

traefik-config/traefik.yaml

log:
  level: INFO

experimental:
  localPlugins:
    traefikoidc:
      moduleName: github.com/lukaszraczylo/traefikoidc

# API and dashboard configuration
api:
  dashboard: true
  insecure: true

entryPoints:
  http:
    address: ":80"
    forwardedHeaders:
      insecure: true

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /etc/traefik/dynamic-configuration.yml

traefik-config/dynamic-configuration.yaml

http:
  middlewares:
    my-plugin:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: 1234567890.apps.googleusercontent.com
          clientSecret: secret
          callbackURL: /oauth2/callback
          logoutURL: /oauth2/logout
          scopes: # If not provided, default scopes will be used (openid, email, profile)
            - openid
            - email
            - profile
          allowedUserDomains: # If not provided - will rely entirely on the OIDC yes/no
            - raczylo.com
          sessionEncryptionKey: potato-secret
          forceHTTPS: false
          logLevel: debug # debug, info, warn, error
          rateLimit: 100 # Simple rate limiter to prevent brute force attacks
          excludedURLs: # Determines the list of URLs which are NOT a subject to authentication
            - /login # covers /login, /login/me, /login/reminder etc.
            - /my-public-data