lukaszraczylo 17dea67229 Security improvements have been implemented and verified across four main areas:
JWT Token Security:
Protected against algorithm switching attacks by validating and whitelisting algorithms (RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512)
Added 2-minute clock skew tolerance for time-based validations
Added "not before" (nbf) claim validation with clock skew tolerance
Required JWT ID (jti) claim to prevent replay attacks
Added strict algorithm validation to prevent downgrade attacks
Session Management Security:
Implemented cryptographically secure random cookie names to prevent targeting
Added automatic session ID rotation after successful login to prevent session fixation
Enforced 24-hour absolute session timeout
Added strict encryption key length validation (minimum 32 bytes)
Added comprehensive session validation including timeout checks
Implemented session pooling for secure resource management
Added secure session cleanup on expiration
Configuration and URL Security:
Enforced HTTPS for all provider URLs and external endpoints
Added minimum rate limit (10 req/sec) to prevent DOS attacks
Added strict validation for excluded URLs:
Must start with "/"
No path traversal (..)
No wildcards (*)
Made ForceHTTPS true by default for secure cookies
Added validation for secure redirect URIs
Added validation for all OIDC endpoints (must be HTTPS)
Added secure defaults in configuration
Test Coverage:
Added comprehensive test cases verifying all security validations
Added test cases for HTTPS enforcement on all endpoints
Added test cases for minimum rate limits
Added test cases for secure session management
Added test cases for token validation with clock skew
Added test cases for secure configuration defaults
All security improvements have been verified through passing test cases, protecting against:

Session fixation attacks
Token replay attacks
Algorithm switching attacks
Path traversal attacks
Session hijacking
Timing attacks
DOS attacks
Man-in-the-middle attacks through enforced HTTPS
2025-01-14 11:33:48 +00:00
2025-01-07 13:19:41 +00:00
2025-01-06 11:01:20 +00:00
2025-01-06 12:48:33 +00:00
2025-01-07 13:19:41 +00:00
2025-01-07 13:19:41 +00:00
2025-01-06 10:44:49 +00:00
2025-01-06 10:44:49 +00:00
2025-01-06 12:48:33 +00:00
2024-04-07 00:50:02 +01:00

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
S
Description
Mirror of github.com/lukaszraczylo/traefikoidc
Readme MIT 5.1 MiB
Languages
Go 99.8%