Giter Site home page Giter Site logo

thomseddon / traefik-forward-auth Goto Github PK

View Code? Open in Web Editor NEW
2.0K 26.0 387.0 220 KB

Minimal forward authentication service that provides Google/OpenID oauth based login and authentication for the traefik reverse proxy

License: MIT License

Go 99.26% Dockerfile 0.63% Makefile 0.11%
traefik oauth2 oauth2-proxy google-oauth docker-swarm kubernetes beyondcorp openid-connect

traefik-forward-auth's Introduction

Traefik Forward Auth Build Status Go Report Card Docker Pulls GitHub release

A minimal forward authentication service that provides OAuth/SSO login and authentication for the traefik reverse proxy/load balancer.

Why?

  • Seamlessly overlays any http service with a single endpoint (see: url-path in Configuration)
  • Supports multiple providers including Google and OpenID Connect (supported by Azure, Github, Salesforce etc.)
  • Supports multiple domains/subdomains by dynamically generating redirect_uri's
  • Allows authentication to be selectively applied/bypassed based on request parameters (see rules in Configuration)
  • Supports use of centralised authentication host/redirect_uri (see auth-host in Configuration)
  • Allows authentication to persist across multiple domains (see Cookie Domains)
  • Supports extended authentication beyond Google token lifetime (see: lifetime in Configuration)

Contents

Releases

We recommend using the 2 tag on docker hub (thomseddon/traefik-forward-auth:2).

You can also use the latest incremental releases found on docker hub and github.

ARM releases are also available on docker hub, just append -arm or -arm64 to your desired released (e.g. 2-arm or 2.1-arm64).

We also build binary files for usage without docker starting with releases after 2.2.0 You can find these as assets of the specific GitHub release.

Upgrade Guide

v2 was released in June 2019, whilst this is fully backwards compatible, a number of configuration options were modified, please see the upgrade guide to prevent warnings on startup and ensure you are using the current configuration.

Usage

Simple:

See below for instructions on how to setup your Provider Setup.

docker-compose.yml:

version: '3'

services:
  traefik:
    image: traefik:v2.2
    command: --providers.docker
    ports:
      - "8085:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  traefik-forward-auth:
    image: thomseddon/traefik-forward-auth:2
    environment:
      - PROVIDERS_GOOGLE_CLIENT_ID=your-client-id
      - PROVIDERS_GOOGLE_CLIENT_SECRET=your-client-secret
      - SECRET=something-random
      - INSECURE_COOKIE=true # Example assumes no https, do not use in production
    labels:
      - "traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
      - "traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
      - "traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181"

  whoami:
    image: containous/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.mycompany.com`)"
      - "traefik.http.routers.whoami.middlewares=traefik-forward-auth"

Advanced:

Please see the examples directory for a more complete docker-compose.yml or kubernetes/simple-separate-pod.

Also in the examples directory is docker-compose-auth-host.yml and kubernetes/advanced-separate-pod which shows how to configure a central auth host, along with some other options.

Provider Setup

Below are some general notes on provider setup, specific instructions and examples for a number of providers can be found on the Provider Setup wiki page.

Google

Head to https://console.developers.google.com and make sure you've switched to the correct email account.

Create a new project then search for and select "Credentials" in the search bar. Fill out the "OAuth Consent Screen" tab.

Click "Create Credentials" > "OAuth client ID". Select "Web Application", fill in the name of your app, skip "Authorized JavaScript origins" and fill "Authorized redirect URIs" with all the domains you will allow authentication from, appended with the url-path (e.g. https://app.test.com/_oauth)

You must set the providers.google.client-id and providers.google.client-secret config options.

OpenID Connect

Any provider that supports OpenID Connect 1.0 can be configured via the OIDC config options below.

You must set the providers.oidc.issuer-url, providers.oidc.client-id and providers.oidc.client-secret config options.

Please see the Provider Setup wiki page for examples.

Generic OAuth2

For providers that don't support OpenID Connect, we also have the Generic OAuth2 provider where you can statically configure the OAuth2 and "user" endpoints.

You must set:

  • providers.generic-oauth.auth-url - URL the client should be sent to authenticate the authenticate
  • providers.generic-oauth.token-url - URL the service should call to exchange an auth code for an access token
  • providers.generic-oauth.user-url - URL used to retrieve user info (service makes a GET request)
  • providers.generic-oauth.client-id - Client ID
  • providers.generic-oauth.client-secret - Client Secret

You can also set:

  • providers.generic-oauth.scope- Any scopes that should be included in the request (default: profile, email)
  • providers.generic-oauth.token-style - How token is presented when querying the User URL. Can be header or query, defaults to header. With header the token is provided in an Authorization header, with query the token is provided in the access_token query string value.

Please see the Provider Setup wiki page for examples.

Configuration

Overview

The following configuration options are supported:

Usage:
  traefik-forward-auth [OPTIONS]

Application Options:
  --log-level=[trace|debug|info|warn|error|fatal|panic] Log level (default: warn) [$LOG_LEVEL]
  --log-format=[text|json|pretty]                       Log format (default: text) [$LOG_FORMAT]
  --auth-host=                                          Single host to use when returning from 3rd party auth [$AUTH_HOST]
  --config=                                             Path to config file [$CONFIG]
  --cookie-domain=                                      Domain to set auth cookie on, can be set multiple times [$COOKIE_DOMAIN]
  --insecure-cookie                                     Use insecure cookies [$INSECURE_COOKIE]
  --cookie-name=                                        Cookie Name (default: _forward_auth) [$COOKIE_NAME]
  --csrf-cookie-name=                                   CSRF Cookie Name (default: _forward_auth_csrf) [$CSRF_COOKIE_NAME]
  --default-action=[auth|allow]                         Default action (default: auth) [$DEFAULT_ACTION]
  --default-provider=[google|oidc|generic-oauth]        Default provider (default: google) [$DEFAULT_PROVIDER]
  --domain=                                             Only allow given email domains, can be set multiple times [$DOMAIN]
  --lifetime=                                           Lifetime in seconds (default: 43200) [$LIFETIME]
  --logout-redirect=                                    URL to redirect to following logout [$LOGOUT_REDIRECT]
  --url-path=                                           Callback URL Path (default: /_oauth) [$URL_PATH]
  --secret=                                             Secret used for signing (required) [$SECRET]
  --whitelist=                                          Only allow given email addresses, can be set multiple times [$WHITELIST]
  --port=                                               Port to listen on (default: 4181) [$PORT]
  --rule.<name>.<param>=                                Rule definitions, param can be: "action", "rule" or "provider"

Google Provider:
  --providers.google.client-id=                         Client ID [$PROVIDERS_GOOGLE_CLIENT_ID]
  --providers.google.client-secret=                     Client Secret [$PROVIDERS_GOOGLE_CLIENT_SECRET]
  --providers.google.prompt=                            Space separated list of OpenID prompt options [$PROVIDERS_GOOGLE_PROMPT]

OIDC Provider:
  --providers.oidc.issuer-url=                          Issuer URL [$PROVIDERS_OIDC_ISSUER_URL]
  --providers.oidc.client-id=                           Client ID [$PROVIDERS_OIDC_CLIENT_ID]
  --providers.oidc.client-secret=                       Client Secret [$PROVIDERS_OIDC_CLIENT_SECRET]
  --providers.oidc.resource=                            Optional resource indicator [$PROVIDERS_OIDC_RESOURCE]

Generic OAuth2 Provider:
  --providers.generic-oauth.auth-url=                   Auth/Login URL [$PROVIDERS_GENERIC_OAUTH_AUTH_URL]
  --providers.generic-oauth.token-url=                  Token URL [$PROVIDERS_GENERIC_OAUTH_TOKEN_URL]
  --providers.generic-oauth.user-url=                   URL used to retrieve user info [$PROVIDERS_GENERIC_OAUTH_USER_URL]
  --providers.generic-oauth.client-id=                  Client ID [$PROVIDERS_GENERIC_OAUTH_CLIENT_ID]
  --providers.generic-oauth.client-secret=              Client Secret [$PROVIDERS_GENERIC_OAUTH_CLIENT_SECRET]
  --providers.generic-oauth.scope=                      Scopes (default: profile, email) [$PROVIDERS_GENERIC_OAUTH_SCOPE]
  --providers.generic-oauth.token-style=[header|query]  How token is presented when querying the User URL (default: header)
                                                        [$PROVIDERS_GENERIC_OAUTH_TOKEN_STYLE]
  --providers.generic-oauth.resource=                   Optional resource indicator [$PROVIDERS_GENERIC_OAUTH_RESOURCE]

Help Options:
  -h, --help                                            Show this help message

All options can be supplied in any of the following ways, in the following precedence (first is highest precedence):

  1. Command Arguments/Flags - As shown above
  2. Environment Variables - As shown in square brackets above
  3. File
    1. Use INI format (e.g. url-path = _oauthpath)
    2. Specify the file location via the --config flag or $CONFIG environment variable
    3. Can be specified multiple times, each file will be read in the order they are passed

Option Details

  • auth-host

    When set, when a user returns from authentication with a 3rd party provider they will always be forwarded to this host. By using one central host, this means you only need to add this auth-host as a valid redirect uri to your 3rd party provider.

    The host should be specified without protocol or path, for example:

    --auth-host="auth.example.com"
    

    For more details, please also read the Auth Host Mode, operation mode in the concepts section.

    Please Note - this should be considered advanced usage, if you are having problems please try disabling this option and then re-read the Auth Host Mode section.

  • config

    Used to specify the path to a configuration file, can be set multiple times, each file will be read in the order they are passed. Options should be set in an INI format, for example:

    url-path = _oauthpath
    
  • cookie-domain

    When set, if a user successfully completes authentication, then if the host of the original request requiring authentication is a subdomain of a given cookie domain, then the authentication cookie will be set for the higher level cookie domain. This means that a cookie can allow access to multiple subdomains without re-authentication. Can be specificed multiple times.

    For example:

    --cookie-domain="example.com"  --cookie-domain="test.org"
    

    For example, if the cookie domain test.com has been set, and a request comes in on app1.test.com, following authentication the auth cookie will be set for the whole test.com domain. As such, if another request is forwarded for authentication from app2.test.com, the original cookie will be sent and so the request will be allowed without further authentication.

    Beware however, if using cookie domains whilst running multiple instances of traefik/traefik-forward-auth for the same domain, the cookies will clash. You can fix this by using a different cookie-name in each host/cluster or by using the same cookie-secret in both instances.

  • insecure-cookie

    If you are not using HTTPS between the client and traefik, you will need to pass the insecure-cookie option which will mean the Secure attribute on the cookie will not be set.

  • cookie-name

    Set the name of the cookie set following successful authentication.

    Default: _forward_auth

  • csrf-cookie-name

    Set the name of the temporary CSRF cookie set during authentication.

    Default: _forward_auth_csrf

  • default-action

    Specifies the behavior when a request does not match any rules. Valid options are auth or allow.

    Default: auth (i.e. all requests require authentication)

  • default-provider

    Set the default provider to use for authentication, this can be overridden within rules. Valid options are currently google or oidc.

    Default: google

  • domain

    When set, only users matching a given domain will be permitted to access.

    For example, setting --domain=example.com --domain=test.org would mean that only users from example.com or test.org will be permitted. So [email protected] would be allowed but [email protected] would not.

    For more details, please also read User Restriction in the concepts section.

  • lifetime

    How long a successful authentication session should last, in seconds.

    Default: 43200 (12 hours)

  • logout-redirect

    When set, users will be redirected to this URL following logout.

  • match-whitelist-or-domain

    When enabled, users will be permitted if they match either the whitelist or domain parameters.

    This will be enabled by default in v3, but is disabled by default in v2 to maintain backwards compatibility.

    Default: false

    For more details, please also read User Restriction in the concepts section.

  • url-path

    Customise the path that this service uses to handle the callback following authentication.

    Default: /_oauth

    Please note that when using the default Overlay Mode requests to this exact path will be intercepted by this service and not forwarded to your application. Use this option (or Auth Host Mode) if the default /_oauth path will collide with an existing route in your application.

  • secret

    Used to sign cookies authentication, should be a random (e.g. openssl rand -hex 16)

  • whitelist

    When set, only specified users will be permitted.

    For example, setting [email protected] [email protected] would mean that only those two exact users will be permitted. So [email protected] would be allowed but [email protected] would not.

    For more details, please also read User Restriction in the concepts section.

  • rule

    Specify selective authentication rules. Rules are specified in the following format: rule.<name>.<param>=<value>

    • <name> can be any string and is only used to group rules together
    • <param> can be:
      • action - same usage as default-action, supported values:
        • auth (default)
        • allow
      • domains - optional, same usage as domain
      • provider - same usage as default-provider, supported values:
        • google
        • oidc
      • rule - a rule to match a request, this uses traefik's v2 rule parser for which you can find the documentation here: https://docs.traefik.io/v2.0/routing/routers/#rule, supported values are summarised here:
        • Headers(`key`, `value`)
        • HeadersRegexp(`key`, `regexp`)
        • Host(`example.com`, ...)
        • HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)
        • Method(methods, ...)
        • Path(`path`, `/articles/{category}/{id:[0-9]+}`, ...)
        • PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`)
        • Query(`foo=bar`, `bar=baz`)
      • whitelist - optional, same usage as whitelist`](#whitelist)

    For example:

    # Allow requests that being with `/api/public` and contain the `Content-Type` header with a value of `application/json`
    rule.1.action = allow
    rule.1.rule = PathPrefix(`/api/public`) && Headers(`Content-Type`, `application/json`)
    
    # Allow requests that have the exact path `/public`
    rule.two.action = allow
    rule.two.rule = Path(`/public`)
    
    # Use OpenID Connect provider (must be configured) for requests that begin with `/github`
    rule.oidc.action = auth
    rule.oidc.provider = oidc
    rule.oidc.rule = PathPrefix(`/github`)
    
    # Allow [email protected] to `/janes-eyes-only`
    rule.two.action = allow
    rule.two.rule = Path(`/janes-eyes-only`)
    rule.two.whitelist = [email protected]
    

    Note: It is possible to break your redirect flow with rules, please be careful not to create an allow rule that matches your redirect_uri unless you know what you're doing. This limitation is being tracked in in #101 and the behaviour will change in future releases.

Concepts

User Restriction

You can restrict who can login with the following parameters:

  • domain - Use this to limit logins to a specific domain, e.g. test.com only
  • whitelist - Use this to only allow specific users to login e.g. [email protected] only

Note, if you pass both whitelist and domain, then the default behaviour is for only whitelist to be used and domain will be effectively ignored. You can allow users matching either whitelist or domain by passing the match-whitelist-or-domain parameter (this will be the default behaviour in v3). If you set domains or whitelist on a rule, the global configuration is ignored.

Forwarded Headers

The authenticated user is set in the X-Forwarded-User header, to pass this on add this to the authResponseHeaders config option in traefik, as shown below in the Applying Authentication section.

Applying Authentication

Authentication can be applied in a variety of ways, either globally across all requests, or selectively to specific containers/ingresses.

Global Authentication

This can be achieved by enabling forward authentication for an entire entrypoint, for example, with http only:

--entryPoints.http.address=:80
--entrypoints.http.http.middlewares=traefik-forward-auth # "default-traefik-forward-auth" on kubernetes

Or https:

--entryPoints.http.address=:80
--entryPoints.http.http.redirections.entryPoint.to=https
--entryPoints.http.http.redirections.entryPoint.scheme=https
--entryPoints.https.address=:443
--entrypoints.https.http.middlewares=traefik-forward-auth # "default-traefik-forward-auth" on kubernetes

Note: Traefik prepends the namespace to the name of middleware defined via a kubernetes resource. This is handled automatically when referencing the middleware from another resource in the same namespace (so the namespace does not need to be prepended when referenced). However the full name, including the namespace, must be used when referenced from static configuration (e.g. command arguments or config file), hence you must prepend the namespace to your traefik-forward-auth middleware reference, as shown in the comments above (e.g. default-traefik-forward-auth if your middleware is named traefik-forward-auth and is defined in the default namespace).

Selective Ingress Authentication in Kubernetes

If you choose not to enable forward authentication for a specific entrypoint, you can apply the middleware to selected ingressroutes:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  entryPoints:
    - http
  routes:
  - match: Host(`whoami.example.com`)
    kind: Rule
    services:
      - name: whoami
        port: 80
    middlewares:
      - name: traefik-forward-auth

See the examples directory for more examples.

Selective Container Authentication in Swarm

You can apply labels to selected containers:

whoami:
  image: containous/whoami
  labels:
    - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
    - "traefik.http.routers.whoami.middlewares=traefik-forward-auth"

See the examples directory for more examples.

Rules Based Authentication

You can also leverage the rules config to selectively apply authentication via traefik-forward-auth. For example if you enabled global authentication by enabling forward authentication for an entire entrypoint, you can still exclude some patterns from requiring authentication:

# Allow requests to 'dash.example.com'
rule.1.action = allow
rule.1.rule = Host(`dash.example.com`)

# Allow requests to `app.example.com/public`
rule.two.action = allow
rule.two.rule = Host(`app.example.com`) && Path(`/public`)

Operation Modes

Overlay Mode

Overlay is the default operation mode, in this mode the authorisation endpoint is overlaid onto any domain. By default the /_oauth path is used, this can be customised using the url-path option.

The user flow will be:

  1. Request to www.myapp.com/home
  2. User redirected to Google login
  3. After Google login, user is redirected to www.myapp.com/_oauth
  4. Token, user and CSRF cookie is validated (this request in intercepted and is never passed to your application)
  5. User is redirected to www.myapp.com/home
  6. Request is allowed

As the hostname in the redirect_uri is dynamically generated based on the original request, every hostname must be permitted in the Google OAuth console (e.g. www.myappp.com would need to be added in the above example)

Auth Host Mode

This is an optional mode of operation that is useful when dealing with a large number of subdomains, it is activated by using the auth-host config option (see this example docker-compose.yml or this kubernetes example).

For example, if you have a few applications: app1.test.com, app2.test.com, appN.test.com, adding every domain to Google's console can become laborious. To utilise an auth host, permit domain level cookies by setting the cookie domain to test.com then set the auth-host to: auth.test.com.

The user flow will then be:

  1. Request to app10.test.com/home/page
  2. User redirected to Google login
  3. After Google login, user is redirected to auth.test.com/_oauth
  4. Token, user and CSRF cookie is validated, auth cookie is set to test.com
  5. User is redirected to app10.test.com/home/page
  6. Request is allowed

With this setup, only auth.test.com must be permitted in the Google console.

Two criteria must be met for an auth-host to be used:

  1. Request matches given cookie-domain
  2. auth-host is also subdomain of same cookie-domain

Please note: For Auth Host mode to work, you must ensure that requests to your auth-host are routed to the traefik-forward-auth container, as demonstrated with the service labels in the docker-compose-auth.yml example and the ingressroute resource in a kubernetes example.

Logging Out

The service provides an endpoint to clear a users session and "log them out". The path is created by appending /logout to your configured path and so with the default settings it will be: /_oauth/logout.

You can use the logout-redirect config option to redirect users to another URL following logout (note: the user will not have a valid auth cookie after being logged out).

Note: This only clears the auth cookie from the users browser and as this service is stateless, it does not invalidate the cookie against future use. So if the cookie was recorded, for example, it could continue to be used for the duration of the cookie lifetime.

Copyright

2018 Thom Seddon

License

MIT

traefik-forward-auth's People

Contributors

hesstobi avatar lammensj avatar lelandsindt avatar lolhens avatar lsl avatar mathcantin avatar nicoulaj avatar supersandro2000 avatar sykkro avatar thomseddon avatar thspinto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

traefik-forward-auth's Issues

README examples for Traefik 2

Traefik 2 has finally left beta and is now in general availability! It's probably worth it to add examples on how to use this with Traefik 2 into the README, as its not entirely obvious how to migrate to v2.

I have examples on my blog that I'd be happy to copy paste across if they're actually correct: https://carey.li/2019/10/01/traefik-2-sso-ssl/.

Support for traefik 2.0?

Hi there!

Curious if you plan to support Traefik 2.0? I had everything working with Traefik 1.7 but now when I get redirected to Google, I'm seeing that the destination host name is being passed instead of the host name of the traefik-forward-auth container. Any thoughts on why this might be?

e.g. I have container1 at c1.sub.domain.com which requires auth via auth.sub.domain.com, when I'm redirected to google, I'm seeing:

The redirect URI in the request, https://c1.sub.domain.com/_oauth, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs

Where I believe before it was receiving auth.sub.domain.com? Ideas?

Endless login loop

Hi,

First of all, it is the first time I am using Oauth so I might have done something wrong in my setup.
I am redirected to google for auth but every time I click on my email address (once connected to google), the same google screen is showing up and I am not redirected to my website.

At the moment, I set DOMAIN=gmail.com in my docker-compose.yml as I don't have an address @DOMAIN.COM on google.

Any idea?

Forward-auth log shows
forward-oauth | 2018-10-31T13:42:40.440721148Z 2018/10/31 13:42:40 Set CSRF cookie and redirecting to google login

Traefik log shows (on hitting the URL):
traefik | 2018-10-31T13:45:40.019947588Z time="2018-10-31T13:45:40Z" level=debug msg="Remote error http://forward-oauth:4181. StatusCode: 307"

and it shows this on hitting my email address on google auth webpage:

traefik          | 2018-10-31T13:45:54.929432773Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/roundrobin/rr: begin ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/_oauth\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"state=993f242d01:https://hydra.DOMAIN.COM/\\u0026code=4/hD4PkUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f242d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=b5q0.apps.googleusercontent.com\\u0026as=4uOMLWOVQ\\u0026destination=https%3A%2F%2FauthDOMAIN.COOM\u0026approval_state=!ChQxMHdtX2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHgIfE_SkNq7B213FkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f2e4c48042d01:https://hydra.DOMAIN.COM/\\u0026code=4/hgAMuUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"
traefik          | 2018-10-31T13:45:54.929841936Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/roundrobin/rr: Forwarding this request to URL" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/_oauth\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"state=993f2e4c042d01:https://hydra.DOMAIN.COM/\\u0026code=4/PkUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f2e4cff14042d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=pq0.apps.googleusercontent.com\\u0026as=4OVQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!ChQxMFdtX2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHgIQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f242d01:https://hydra.DOMAIN.COM/\\u0026code=4/hD4PkUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}" ForwardURL="http://172.18.0.11:4181"
traefik          | 2018-10-31T13:45:54.930209893Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/forward: begin ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"172.18.0.11:4181\",\"Path\":\"\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f2d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=1hbb5q0.apps.googleusercontent.com\\u0026as=4uOMLZVQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!ChQxWQlBhbGJCWQ%E2%88%99APNbktkAAAAAW9sDhHgTS3FGyDWs8BWxBCm4HdtX2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHgIfB213FkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f248042d01:https://hydra.DOMAIN.COM/\\u0026code=4/hgAMuldPkUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"
traefik          | 2018-10-31T13:45:54.930525308Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/forward/http: begin ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"172.18.0.11:4181\",\"Path\":\"\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f42d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=ohvq0.apps.googleusercontent.com\\u0026as=4uOMOVQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!ChcTS3FGyDWs8BWxBCm4HdtX2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHFkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f2e4042d01:https://hydraDOMAIN.COM/\\u0026code=4/hgoE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"
traefik          | 2018-10-31T13:45:54.930641362Z time="2018-10-31T13:45:54Z" level=debug msg="Upstream ResponseWriter of type *pipelining.writerWithoutCloseNotify does not implement http.CloseNotifier. Returning dummy channel."
traefik          | 2018-10-31T13:45:54.932439662Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/forward/http: Round trip: http://172.18.0.11:4181, code: 307, Length: 434, duration: 1.606526ms tls:version: 303, tls:resume:true, tls:csuite:c02f, tls:server:hydra.DOMAIN.COM"
traefik          | 2018-10-31T13:45:54.932707222Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/forward/http: completed ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"172.18.0.11:4181\",\"Path\":\"\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f2e448042d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=qpdjq1hbb5q0.apps.googleusercontent.com\\u0026as=4uQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!ChQxkNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHgIfE_SkNz41NQjL1AlzKR5Mq7B213FkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COm\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f2ed548042d01:https://hydra.DOMAIN.COM/\\u0026code=4/hgAMuldpxs8Wy0NOWtxskTUroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"
traefik          | 2018-10-31T13:45:54.932886522Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/forward: completed ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"172.18.0.11:4181\",\"Path\":\"\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=993f2042d01\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=b5q0.apps.googleusercontent.com\\u0026as=4uORWOVQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!CCm4HdtX2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AHgI13FkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=9901:https://hydra.DOMAIN.COM/\\u0026code=4/hgAMroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"
traefik          | 2018-10-31T13:45:54.933021455Z time="2018-10-31T13:45:54Z" level=debug msg="vulcand/oxy/roundrobin/rr: completed ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/_oauth\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"state=99301:https://hydra.DOMAIN.COM/\\u0026code=4/hgAroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"Fragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-GB,en-US;q=0.9,en;q=0.8\"],\"Cookie\":[\"_forward_auth_csrf=99301\"],\"Referer\":[\"https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=bb5q0.apps.googleusercontent.com\\u0026as=4uOVQ\\u0026destination=https%3A%2F%2Fauth.DOMAIN.COM\\u0026approval_state=!Ch2kNd\\u0026oauthgdpr=1\\u0026xsrfsig=AH3FkQ\\u0026flowName=GeneralOAuthFlow\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"auth.DOMAIN.COM\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"188.60.195.90:59429\",\"RequestURI\":\"/_oauth?state=993f201:https://hydra.DOMAIN.COM/\\u0026code=4/hgroE8\\u0026scope=email%20profile%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email\",\"TLS\":null}"

Support Azure AD

I'd like to propose and introduce Azure AD as another supported provider.

Why
Traefik is used widely with Azure Service Fabric. It makes sense to protect its api/dashboard with Azure AD.

How

We can introduce a config entry for the desired provider and have an interface that's supported by both Google and Azure AD providers. We can then inject the desired provider based on the configuration to the auth struct.

Does this make sense?

Whitelist per TFA domain?

Precondition: I have one TFA instance deployed, with for example google auth configured.
i want to secure both domain1 & domain2; but domain1 i would only want to allow [email protected] and for domain2 i want to allow both users. Is this currently possible to use docker compose and inject separate whitelists per container?

command traefik error: field not found, node: auth

docker version:
Docker version 19.03.2, build 6a30dfc

Error:
2019/10/08 07:58:46 command traefik error: field not found, node: auth

How to reproduce:

run cmd docker-compose up -d in example folder. the other two containers started well, but traefik-forward-auth_traefik_1 failed.

looking to incorporate with plexguide

hey been checking out your project and will attempt to intergrate within. my program generates it own keys and etc for the user for gdrive and tdrive authentication and sets them. let me know what you think. apologize, only way to communicate. we use all traefik.

For traefik, the program does the domain challenge and everything with containers all launching correctly. just using the standard authentication right now.

https://github.com/Admin9705/PlexGuide.com-The-Awesome-Plex-Server
https://plexguide.com

[BUG?] redirect_uri always seems to point to the requested domain, regardless of the AUTH_HOST setting

Hello!

I'm having some issues with getting forward-auth working.

I have multiple subdomains, and I'm trying to get the AUTH_HOST parameter set correctly, but regardless of what I set, the requested domain is always passed to google as redirect_uri and it throws an error due to the mismatch.

Any ideas on what I'm doing wrong? The tests are passing A-OK, so i'm stumped.

Thanks!

Tom

My Config:

  traefik-forward-auth:
    image: thomseddon/traefik-forward-auth:latest
    networks:
      - traefik
    environment:
      CLIENT_ID: ${TRAEFIK_AUTH_CLIENT_ID}
      CLIENT_SECRET: ${TRAEFIK_AUTH_CLIENT_SECRET}
      SECRET: ${TRAEFIK_AUTH_COOKIE_SECRET}
      COOKIE_SECURE: "false"
      DOMAIN: ${TRAEFIK_AUTH_DOMAINS}
      AUTH_HOST: ${TRAEFIK_AUTH_AUTH_HOST}
      LOG_LEVEL: debug
    labels:
      traefik.enable: true
      traefik.port: 4181
      traefik.backend: traefik-forward-auth
      traefik.frontend.rule: Host:${TRAEFIK_AUTH_AUTH_HOST}

[auth-host] Almost there, but not quite yet.

What happens is this:

If i remove the SSL redirect on consul (so that it is hosted on HTTP instead) the redirect-url is automatically set to http://auth.mydomain.io/_oauth (e.g. non-ssl)

What am i missing to get the traefik-forward-auth working fully on SSL?

See below my config:

Consul:

  consul-leader:
    image: consul
    environment:
      - CONSUL_BIND_INTERFACE=eth0
      - 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}'
    networks:
      - internal
      - swarm_traefik
    volumes:
      - consul-leader:/consul/data
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 5
      labels:
        - traefik.enable=true
        - traefik.frontend.rule=Host:consul.${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}
        - traefik.port=8500
        - traefik.tags=${DOCKER_TRAEFIK_TAG:-traefik-exposed}
        - traefik.docker.network=swarm_traefik
        # Traefik service that listens to HTTP
        - traefik.redirectorservice.frontend.entryPoints=http
        - traefik.redirectorservice.frontend.redirect.entryPoint=https
        # Traefik service that listens to HTTPS
        - traefik.webservice.frontend.entryPoints=https
        # Security
        - traefik.frontend.headers.SSLRedirect=true
        - traefik.frontend.headers.forceSTSHeader=true
        - traefik.frontend.headers.STSSeconds=315360000
        - traefik.frontend.headers.STSIncludeSubdomains=true
        - traefik.frontend.headers.STSPreload=true
        - traefik.frontend.headers.browserXSSFilter=true
        - traefik.frontend.headers.contentTypeNosniff=true
        - traefik.frontend.headers.frameDeny=true
        # Traefik forward auth
        - traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
        - traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
        - traefik.frontend.auth.forward.trustForwardHeader=true
    command: agent -server -client=0.0.0.0 -bootstrap -ui

Traefik:

  traefik:
    image: traefik:v1.7
    depends_on:
      - consul-leader
    networks:
      - swarm_traefik
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 5
      replicas: ${DOCKER_CORE_TRAEFIK_REPLICAS:-3}
      placement:
        constraints:
          - node.role == manager
        preferences:
          - spread: node.id
      labels:
        - traefik.enable=true
        - traefik.frontend.rule=Host:traefik.${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}
        - traefik.port=8080
        - traefik.tags=${DOCKER_TRAEFIK_TAG:-traefik-exposed}
        - traefik.docker.network=swarm_traefik
        # Traefik service that listens to HTTP
        - traefik.redirectorservice.frontend.entryPoints=http
        - traefik.redirectorservice.frontend.redirect.entryPoint=https
        # Traefik service that listens to HTTPS
        - traefik.webservice.frontend.entryPoints=https
        # Security
        - traefik.frontend.headers.SSLRedirect=true
        - traefik.frontend.headers.forceSTSHeader=true
        - traefik.frontend.headers.STSSeconds=315360000
        - traefik.frontend.headers.STSIncludeSubdomains=true
        - traefik.frontend.headers.STSPreload=true
        - traefik.frontend.headers.browserXSSFilter=true
        - traefik.frontend.headers.contentTypeNosniff=true
        - traefik.frontend.headers.frameDeny=true
        - traefik.frontend.auth.basic.users=${DOCKER_CORE_TRAEFIK_USERNAME?Variable DOCKER_CORE_TRAEFIK_USERNAME not set}:${DOCKER_CORE_TRAEFIK_PASSWORD_HASHED?Variable DOCKER_CORE_TRAEFIK_PASSWORD_HASHED not set}
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
    command: >
      --docker
      --docker.swarmmode
      --docker.watch
      --docker.exposedbydefault=false
      --constraints=tag==${DOCKER_TRAEFIK_TAG:-traefik-exposed}
      --entrypoints='Name:http Address::80'
      --entrypoints='Name:https Address::443 TLS'
      --consul
      --consul.endpoint='consul-leader:8500'
      --acme
      --acme.email=${DOCKER_CORE_TRAEFIK_EMAIL?Variable DOCKER_swarm_traefik_EMAIL not set}
      --acme.storage=traefik/acme/account
      --acme.entryPoint=https
      --acme.httpChallenge.entryPoint=http
      --acme.onhostrule=true
      --acme.acmelogging=true
      --logLevel=INFO
      --accessLog
      --api

Traefik-forward-auth:

  traefik-forward-auth:
    image: funkypenguin/traefik-forward-auth
    environment:
      - CLIENT_ID=${DOCKER_CORE_TRAEFIK_AUTH_CLIENT_ID?Variable DOCKER_CORE_TRAEFIK_AUTH_CLIENT_ID not set}
      - CLIENT_SECRET=${DOCKER_CORE_TRAEFIK_AUTH_CLIENT_SECRET?Variable DOCKER_CORE_TRAEFIK_AUTH_CLIENT_SECRET not set}
      - OIDC_ISSUER=https://keycloak.${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}/auth/realms/master
      - SECRET=${DOCKER_CORE_TRAEFIK_AUTH_SECRET?Variable DOCKER_CORE_TRAEFIK_AUTH_SECRET not set}
      - AUTH_HOST=auth.${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}
      - COOKIE_DOMAINS=${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}
    networks:
      - swarm_traefik
    deploy:
      labels:
        - traefik.enable=true
        - traefik.port=4181
        - traefik.frontend.rule=Host:auth.${DOCKER_TRAEFIK_DOMAIN?Variable DOCKER_TRAEFIK_DOMAIN not set}
        - traefik.tags=${DOCKER_TRAEFIK_TAG:-traefik-exposed}
        - traefik.docker.network=swarm_traefik
        - traefik.backend=traefik-forward-auth

p.s. i know i am running 'funkypenguin's version, but i hope you can give me a v2 thomseddon example after you've implemented custom oauth providers (e.g. keycloak)

Using multiple OIDC issuers or multiple client-id+secret?

Hi!

First off - thanks for writing this excellent package! I'm successfully using a my own fork based on @funkypenguin's fork to allow using with my own OIDC provider (in this case dex).

As I've separated my LAN in to different VLAN segments (e.g. admin services and normal services), I'd like to use be able to give different user groups access to those different services. This would prevent e.g. a use that has access to say Radarr to also access Portainer. For this I guess I would need to set a different OIDC provide and/or different client_id+secret.

It's trivial to just use another instance of traefik-forward-auth with different credentials, but would it make sense to also try and do this with a single traefik-forward-auth instance (using different cookie-names as well, as I'm using the same domainname for all services)?

My questions:

  • would it make sense to use a single traefik-forward-auth for multiple OIDC clients?
  • if so, is there anything being done already to support multiple client_id+secrets w/ traefik-forward auth?

Thanks!

Redirect Loop when trying to use docker-compose auth-host example

I'm having trouble and getting stuck in a redirect loop when trying to set-up an auth-host in the docker-compose file. In your example, there is no "COOKIE_DOMAINS=example.com" in the docker-compose file, but the README states that this is required for an AUTH-HOST. When I add that line, I get stuck in the loop. When I remove it, the login works, but only for hosts that I have configured in the Google Developer Console (e.g. https://host.example.com/_oauth works).

docker-compose excerpt:

  traefik-forward-auth:
    image: thomseddon/traefik-forward-auth
    container_name: oauth
    networks:
      - traefik_proxy
    environment:
      - CLIENT_ID=<client>.apps.googleusercontent.com
      - CLIENT_SECRET=<secret>
      - SECRET=<secret>
      - COOKIE_SECURE=false
      - DOMAIN=example.com
      - AUTH_HOST=auth.example.com
      - COOKIE_DOMAINS=example.com
      - LOG_LEVEL=debug
    # When using an auth host, adding it here prompts traefik to generate certs
    labels:
      - "traefik.enable=true"
      - "traefik.port=4181"
      - "traefik.backend=traefik-forward-auth"
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.rule=Host:auth.example.com"
  traefik:
    hostname: traefik
    image: traefik:latest
    container_name: traefik
    restart: always
    domainname: ${DOMAINNAME}
    networks:
      - viki
      - traefik_proxy
    ports:
      - "80:80"
      - "127.0.0.1:443:443"
    expose:
      - "8080"
    labels:
      - "traefik.enable=true"
      - "traefik.backend=traefik"
      - "traefik.frontend.rule=Host:traefik.${DOMAINNAME}"
      - "traefik.port=8080"
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.STSSeconds=315360000"
      - "traefik.frontend.headers.browserXSSFilter=true"
      - "traefik.frontend.headers.contentTypeNosniff=true"
      - "traefik.frontend.headers.forceSTSHeader=true"
      - "traefik.frontend.headers.SSLHost=example.com"
      - "traefik.frontend.headers.STSIncludeSubdomains=true"
      - "traefik.frontend.headers.STSPreload=true"
      - "traefik.frontend.headers.frameDeny=true"
      # - "traefik.frontend.auth.basic.users=${HTTP_USERNAME}:${HTTP_PASSWORD}"
      - "traefik.frontend.auth.forward.address=https://auth.example.com"
      - "traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User"
      - "traefik.frontend.auth.forward.trustForwardHeader=true"

Looking at the log, it looks like its just going in a circle between google and auth.example.com... and not receiving a redirect_uri.

Is there anything else I can check?

EDIT: Log excerpt:

time="2019-04-18T18:00:32Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:32Z" level=debug msg="Handling request" Headers="map[X-Forwarded-Host:[auth.example.com] X-Forwarded-Server:[traefik.example.com] Cookie:[_forward_auth_csrf=c415a1fc8421bd7a01ad61e8cafa6c4e] Referer:[https://accounts.youtube.com/accounts/SetSID] X-Forwarded-Port:[443] X-Forwarded-Proto:[https] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Accept-Language:[en-US,en;q=0.9] Cache-Control:[max-age=0] X-Forwarded-For:[172.18.0.1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Accept-Encoding:[gzip, deflate, br] Upgrade-Insecure-Requests:[1] Dnt:[1] X-Real-Ip:[172.18.0.1]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:32Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:32Z" level=debug msg="Handling request" Headers="map[X-Real-Ip:[172.18.0.1] Accept-Encoding:[gzip, deflate, br] Dnt:[1] Referer:[https://accounts.youtube.com/accounts/SetSID] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] X-Forwarded-Server:[traefik.example.com] Upgrade-Insecure-Requests:[1] X-Forwarded-For:[172.18.0.1] X-Forwarded-Host:[auth.example.com] X-Forwarded-Port:[443] X-Forwarded-Proto:[https] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Cache-Control:[max-age=0] Cookie:[_forward_auth_csrf=29127a11f27310bd7184cc304d1ff62e] Accept-Language:[en-US,en;q=0.9]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:32Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Handling request" Headers="map[Accept-Encoding:[gzip, deflate, br] Cache-Control:[max-age=0] X-Forwarded-Server:[traefik.example.com] X-Real-Ip:[172.18.0.1] Dnt:[1] Referer:[https://accounts.youtube.com/accounts/SetSID] Upgrade-Insecure-Requests:[1] X-Forwarded-For:[172.18.0.1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Accept-Language:[en-US,en;q=0.9] X-Forwarded-Port:[443] Cookie:[_forward_auth_csrf=5ecbc788d4e49c3fc94820630ebc80fd] X-Forwarded-Host:[auth.example.com] X-Forwarded-Proto:[https]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Handling request" Headers="map[X-Forwarded-Server:[traefik.example.com] X-Real-Ip:[172.18.0.1] Accept-Encoding:[gzip, deflate, br] Dnt:[1] Upgrade-Insecure-Requests:[1] X-Forwarded-Host:[auth.example.com] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Cookie:[_forward_auth_csrf=3f64fb5a64c88816db64cef8becb02e3] X-Forwarded-Proto:[https] X-Forwarded-Port:[443] X-Forwarded-For:[172.18.0.1] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Accept-Language:[en-US,en;q=0.9] Cache-Control:[max-age=0] Referer:[https://accounts.youtube.com/accounts/SetSID]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Handling request" Headers="map[Referer:[https://accounts.youtube.com/accounts/SetSID] X-Forwarded-Host:[auth.example.com] Cache-Control:[max-age=0] Dnt:[1] Upgrade-Insecure-Requests:[1] X-Forwarded-For:[172.18.0.1] X-Forwarded-Proto:[https] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Accept-Language:[en-US,en;q=0.9] X-Forwarded-Port:[443] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Cookie:[_forward_auth_csrf=32dede879133190b879991a92255f2f1] X-Forwarded-Server:[traefik.example.com] X-Real-Ip:[172.18.0.1] Accept-Encoding:[gzip, deflate, br]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Handling request" Headers="map[X-Real-Ip:[172.18.0.1] Referer:[https://accounts.youtube.com/accounts/SetSID] X-Forwarded-For:[172.18.0.1] Dnt:[1] X-Forwarded-Host:[auth.example.com] X-Forwarded-Port:[443] X-Forwarded-Server:[traefik.example.com] Accept-Encoding:[gzip, deflate, br] Cache-Control:[max-age=0] X-Forwarded-Proto:[https] Accept-Language:[en-US,en;q=0.9] Cookie:[_forward_auth_csrf=c0216cec4d2a796b200e9f31858005ae] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3]]" SourceIP=172.18.0.1
time="2019-04-18T18:00:33Z" level=debug msg="Set CSRF cookie and redirecting to google login" SourceIP=172.18.0.1

Error exchanging token

Iโ€™m running an auth host in k8s that previously worked. Lately for no obvious reason, Iโ€™m getting the Following:

level=debug msg=Done source_ip=10.42.0.1
time="2019-07-31T08:20:15Z" level=debug msg="Handling callback" headers="map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-us] Cookie:[_forward_auth_csrf=558dc9a0b4b130ab2f74f0ea55fb6dbe] Referer:[https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id=clientid.apps.googleusercontent.com&as=Y_xJcHb9VHlFceYykYqEjQ&destination=https%3A%2F%2Fsso.domain&approval_state=!ChRabUR0RzNWQ2NVMmRYMkx5MlpXZhIfZzRucGY4OEZhU1lYd0ktM2lWMU9TaWNYYzloeHhCWQ%E2%88%99AJDr988AAAAAXUKgvWMxpg85fNMX4dnSU-J0_KkOpKlC&oauthgdpr=1&xsrfsig=ChkAeAh8TzKpp-u6LkjUWTEJlGSKE_2uGNVMEg5hcHByb3ZhbF9zdGF0ZRILZGVzdGluYXRpb24SBXNvYWN1Eg9vYXV0aHJpc2t5c2NvcGU&flowName=GeneralOAuthFlow] User-Agent:[Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1] X-Forwarded-For:[10.42.0.1] X-Forwarded-Host:[sso.rtd3.me] X-Forwarded-Method:[GET] X-Forwarded-Proto:[https] X-Forwarded-Uri:[/_oauth?state=558dc9a0b4b130ab2f74f0ea55fb6dbe%3Ahttps%3A%2F%2Fdomain.com%2F&code=4%2FlgGSmVxVZ7clqansiGvV-pc0cAEj6Al19nLET9jUWbS6h3KEvrfq72vLLHb46rHOUPYjsjE-TGaDySjH16tjBMg&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&session_state=587dae9bff8596b251d8f5f7d89baf1432e87dfd..a687&prompt=none]]" rule=default source_ip=10.42.0.1
time="2019-07-31T08:20:15Z" level=error msg="Code exchange failed with: Post https://www.googleapis.com/oauth2/v3/token: x509: certificate is valid for domain, not www.googleapis.com" source_ip=10.42.0.1

Which then puts me back into a redirect loop. Any ideas?

trying to get this going

Ok, Ive changed this post quite abit. I figured tons of things out along the way and only one thing left!

If you look at the bottom, you look below; I have the oauth which is suppose to be the auth label; but fails to works. so if I type portainer.domain.com; I get the I need to add to the list, but if I type netdata.domain.com, it works (because it's added below). Basically, I cannot get the auth to work to kick in for everything.

image

FOR THE EXECUTION
`

- name: "Set Known Facts"
  set_fact:
    pgrole: "auth"
    image: "thomseddon/traefik-forward-auth"

- name: "Setting PG Labels"
  set_fact:
    pg_labels:
      traefik.enable: "true"
      traefik.port: "4181"
      traefik.backend: "oauth"
      traefik.frontend.rule: "Host:oauth.domain.com"

- name: "Setting PG ENV
  set_fact:
    pg_env:
      PUID: "1000"
      PGID: "1000"
      CLIENT_ID: "xxxx.apps.googleusercontent.com"
      CLIENT_SECRET: "xxxx"
      SECRET: test
      COOKIE-DOMAINS: domain.com
      COOKIE_SECURE: true
      AUTH_HOST: oauth.domain.com

- name: "Deploying Container - {{pgrole}}"
  docker_container:
    name: "{{pgrole}}"
    image: "{{image}}"
    pull: "yes"
    env: "{{pg_env}}"
    restart_policy: always
    networks:
      - name: plexguide
        aliases:
          - "plexguide"
    state: started
    labels: "{{pg_labels}}"

`

FOR TOML

insecureskipverify = true

logLevel = "WARN"

defaultEntryPoints = ["http", "https"]

[entryPoints]
  [entryPoints.http]
  address = ":80"

  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]
    MinVersion = "VersionTLS12"
    CipherSuites = ["TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_AES_256$
  [entryPoints.monitor]
  address = ":8081"

    [entryPoints.https.auth.forward]
    address = "http://oauth:4181"
    authResponseHeaders = ["X-Forwarded-User"]

[retry]

[acme]
acmeLogging = true
email = "[email protected]"
storage = "/etc/traefik/acme/acme.json"
entryPoint = "https"
  [acme.dnsChallenge]
    provider = "godaddy"
    delayBeforeCheck = 30

[[acme.domains]]
  main = "domain.com"
[[acme.domains]]
  main = "*.domain.com"

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "domain.com"
watch = true
exposedbydefault = false
network = "plexguide"

docker-compose-auth-host.yml correct?

The way the file examples/docker-compose-auth-host.yml is composed, it looks like the whoami container is not yet protected by traefik-forward-auth. Shouldn't the whoami container require these extra labels?

- traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
- traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
- traefik.frontend.auth.forward.trustForwardHeader=true

Forwarded Ip is ignored

If Traefik is configured as LB and with externalTrafficPolicy: Local, the Ip address logged (and i guess used for verification) is a internal cluster ip, instead of the real client ip.

time="2019-02-20T17:29:52Z" level=warning msg="Error validating csrf cookie: Invalid CSRF state value" RemoteAddr="10.244.0.237:58794" csrf=ASDF state=
time="2019-02-20T17:30:45Z" level=error msg="Invalid cookie: Invalid cookie mac" RemoteAddr="10.244.0.237:58794"

Receive "not authorized" after Google Oauth rule

Hi,

I really like the idea of having a centralized authentication for my self-hosted applications. I struggle to set it up though, I use the "overlay" mode and when going to my domain I did get redirected to the google login page. However, after logging in I just get a white page with "Not Authorized" written on top.

What can I do to correct this? Do I need to do any setup to make sure the https://home-service-domain.com/_oauth gets correctly redirected to the traefik-forward-auth container or?

Would really appreciate your help in this, thanks alot!

How to add as frontend rule?

i would like to replace my Basic auth with oauth, is there a frontend rule?

        #- "traefik.frontend.auth.basic=user:super-secret"
        - "traefik.frontend.auth.forward=http://forward-oauth:4181"

Not Authorized error

Hi,

I've just setup traefik-forward-auth docker container for the first time, and after some playing in both overlay and auth-host modes I get the same "Not Authroized" error displayed.

I ran the container up with debug mode and am getting the following error:
Error validating csrf cookie: CSRF cookie does not match state

This is my config (with secrets removed of course):

traefik-forward-auth container:
Traefik-Forward-Auth:
container_name: Traefik-Forward-Auth
hostname: Traefik-Forward-Auth
image: thomseddon/traefik-forward-auth
networks:
IoT:
ipv4_address: 10.1.11.253
environment:
- CLIENT_ID=
- CLIENT_SECRET=
- SECRET=
- COOKIE_DOMAINS=
- COOKIE_SECURE=true
- AUTH_HOST=auth.
- WHITELIST=@
- LOG_LEVEL=debug
- LOG_FORMAT=json
# When using an auth host, adding it here prompts traefik to generate certs
labels:
# Traefik - General
- "traefik.enable=true"
- "traefik.default.port=4181"
- "traefik.frontend.rule=Host:auth."
# Traefik - SSL
- "traefik.frontend.headers.SSLRedirect=true"
- "traefik.frontend.headers.STSSeconds=315360000"
- "traefik.frontend.headers.browserXSSFilter=true"
- "traefik.frontend.headers.contentTypeNosniff=true"
- "traefik.frontend.headers.forceSTSHeader=true"
- "traefik.frontend.headers.SSLHost="
- "traefik.frontend.headers.STSIncludeSubdomains=true"
- "traefik.frontend.headers.STSPreload=true"
- "traefik.frontend.headers.frameDeny=true"
# Traefik - Whitelisting
- "traefik.frontend.auth.forward.address=http://10.1.11.253:4181"
- traefik.frontend.auth.forward.authResponseHeaders = ["X-Forwarded-User"]

whoami container which I'm trying to forward auth as a test:
Whoami:
container_name: Whoami
hostname: whoami
image: containous/whoami
networks:
IoT:
ipv4_address: 10.1.11.251
labels:
# Traefik - General
- "traefik.enable=true"
- "traefik.frontend.entryPoints=http,https"
- "traefik.default.protocol=http"
- "traefik.default.port=80"
- "traefik.frontend.rule=Host:whoami."
# Traefik - SSL
- "traefik.frontend.headers.SSLRedirect=true"
- "traefik.frontend.headers.STSSeconds=315360000"
- "traefik.frontend.headers.browserXSSFilter=true"
- "traefik.frontend.headers.contentTypeNosniff=true"
- "traefik.frontend.headers.forceSTSHeader=true"
- "traefik.frontend.headers.SSLHost="
- "traefik.frontend.headers.STSIncludeSubdomains=true"
- "traefik.frontend.headers.STSPreload=true"
- "traefik.frontend.headers.frameDeny=true"
# Traefik - Whitelisting
- "traefik.frontend.auth.forward.address=http://10.1.11.253:4181"
- traefik.frontend.auth.forward.authResponseHeaders = ["X-Forwarded-User"]

As I am using labels for everything instead of making changes to the treafik.toml file I added the auth.forward.address and auth.forward.authResponseHeaders to the treafik-forward-auth container as I saw something around this in another post when using auth-host mode. Which solved my endless login loop when it wasnt in there.

I have gone through as setup the Google side as per the instructions, and added https://auth./_oauth and https://whoami./_oauth (for when I was testing in overlay mode.

Any ideas, I have tried multiple options around the DOMAIN and WHITELIST options, and multiple google accounts. And all give me the same problem. The error probably suggests its not something with the accounts Im using somwhere else Im guessing?

Thanks in advance.
O

Originally posted by @owendemooy in #20 (comment)

https url-path

Hello,

I'm trying you forwarder and I'm facing and issue with https.
When I call my service, let's say https://service.domain.com, I get a 400 error code saying :
he redirect URI in the request, https://service.domain.com/_oauth, does not match the ones authorized for the OAuth client.

How can I make the url path called with https ?

Regards,
Martinho MOREIRA

Add support for centralised "auth domain"

Problem: If you're using traefik in front of many different hosts/domains, you need to remember to permit each one as a redirect_uri in Google.

Solution: Support a central auth domain, e.g. auth.example.com, following google authorisation the user would be sent to the auth domain, the request would be validated and the user sent back to the original domain.

nice work

i'm looking at integrating this into our project. I STAR'ed, but will provide you feedback when incorporating! nice work, love traefik. we use it current for dns challenge for mass container deployment.

No prompt for user login unless logged out of Google account

If I'm logged in using a different non-whitelisted account using Chrome browser, I get a "Not Authorized" without prompting me to login with the other authorized account. On the other side, if I'm using Chrome with the whitelisted account logged in, I don't get the login consent and get authorized automatically.

Is there an config to force account selection?

It should be possible with: prompt=select_account

I just can't figure out where I can change this.

AUTH-HOST not working

For some reason, Google keeps telling me:
The redirect URI in the request, ..., does not match the ones authorized for the OAuth client

This is my Forward Auth compose:

  core-traefik-forward-auth:
    container_name: core-traefik-forward-auth
    depends_on:
      - core-traefik
    image: thomseddon/traefik-forward-auth
    restart: unless-stopped
    environment:
      - PROVIDERS_GOOGLE_CLIENT_ID=...
      - PROVIDERS_GOOGLE_CLIENT_SECRET=...
      - SECRET=something-random
      - INSECURE_COOKIE=false
      - DOMAIN=docker.mydomain.ext
      - AUTH_HOST=auth.docker.mydomain.ext
      - [email protected]
      - LIFETIME=1800
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik
    labels:
      - traefik.docker.network=traefik
      - traefik.enable=true
      - traefik.frontend.rule=Host:auth.docker.mydomain.ext
      - traefik.port=4181
      - traefik.tags=traefik-exposed
      - traefik.backend=core-traefik-forward-auth

And this is one of my services' compose section:

  network-cupsd:
    container_name: network-cupsd
    image: olbat/cupsd
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=999
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/dbus:/var/run/dbus
      - /dev/bus/usb:/dev/bus/usb
      - network-cupsd-config:/etc/cups
    labels:
      - traefik.docker.network=traefik
      - traefik.enable=true
      - traefik.frontend.rule=Host:cups.docker.mydomain.ext
      - traefik.port=631
      - traefik.tags=traefik-exposed
      - traefik.backend=network-cupsd
      - traefik.protocol=https
      - traefik.passHostHeader=true
      # Security
      - traefik.frontend.headers.SSLRedirect=true
      - traefik.frontend.headers.forceSTSHeader=true
      - traefik.frontend.headers.STSSeconds=315360000
      - traefik.frontend.headers.STSIncludeSubdomains=true
      - traefik.frontend.headers.STSPreload=true
      - traefik.frontend.headers.browserXSSFilter=true
      - traefik.frontend.headers.contentTypeNosniff=true
      - traefik.frontend.headers.frameDeny=true
      # Traefik forward auth
      - traefik.frontend.auth.forward.address=http://core-traefik-forward-auth:4181
      - traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
      - traefik.frontend.auth.forward.trustForwardHeader=true
      # Traefik service that listens on HTTPS
      - traefik.webservice.frontend.entryPoints=https

What am i doing wrong?

Add AccessToken in response headers

I need to do a collateral call to google APIs from my backend to get additional information about the user (full name, profile picture, team, ...). For that, I need to have the access token. Unfortunately, now I only have access to the user's email.

A solution could be to return the access token in the header key X-Forwarded-AccessToken but I think we will have to manage when the access token expires and refresh it with the refresh_token provided by Google. I am not sure the current implementation allows us to easily do that.

What do you think about this?

Example of K8s conf

Hi,

If you're interested, here is an example Kubernetes configuration for traefik-forward-auth using AUTH_HOST:

##
# Secrets to store Google's client secret and the app's secret
##
kind: Secret
apiVersion: v1
metadata:
  name: traefik-forward-auth-secrets
  namespace: kube-system
  labels:
    name: traefik
type: Opaque
data:
  CLIENT_SECRET: --> GOOGLE_CLIENT_SECRET_BASE64_ENCODED 
  SECRET: --> A_RANDOM_SECRET_BASE64_ENCODED 
---

##
# Main deployment
## 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: traefik-forward-auth
  name: traefik-forward-auth
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik-forward-auth
  template:
    metadata:
      labels:
        app: traefik-forward-auth
    spec:
      containers:
        - name: traefik-forward-auth
          image: thomseddon/traefik-forward-auth
          ports:
            - containerPort: 4181
              protocol: TCP
          env:
            - name: CLIENT_ID
              value: XXXXXX.apps.googleusercontent.com
            - name: CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: traefik-forward-auth-secrets
                  key: CLIENT_SECRET
            - name: SECRET
              valueFrom:
                secretKeyRef:
                  name: traefik-forward-auth-secrets
                  key: SECRET
            - name: COOKIE_SECURE
              value: 'true'
            - name: COOKIE_DOMAINS
              value: example.com,example.org
            - name: DOMAINS
              value: example.com,example.org
            - name: AUTH_HOST
              value: auth.example.com
          livenessProbe:
            tcpSocket:
              port: 4181
            initialDelaySeconds: 20
            failureThreshold: 3
            successThreshold: 1
            periodSeconds: 10
            timeoutSeconds: 2
---

##
# Related service
##
kind: Service
apiVersion: v1
metadata:
  name: traefik-forward-auth
  namespace: kube-system
spec:
  selector:
    app: traefik-forward-auth
  ports:
    - port: 80
      targetPort: 4181
      protocol: TCP
---

##
# Ingress for the auth host
##
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: traefik-forward-auth-ingress
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
    ingress.kubernetes.io/auth-type: forward
    ingress.kubernetes.io/auth-url: http://traefik-forward-auth
    ingress.kubernetes.io/auth-response-headers: X-Forwarded-User
spec:
  rules:
    - host: auth.example.com
      http:
        paths:
          - backend:
              serviceName: traefik-forward-auth
              servicePort: 80

And without the AUTH_HOST:

##
# Secrets to store Google's client secret and the app's secret
##
kind: Secret
apiVersion: v1
metadata:
  name: traefik-forward-auth-secrets
  namespace: kube-system
  labels:
    name: traefik
type: Opaque
data:
  CLIENT_SECRET: --> GOOGLE_CLIENT_SECRET_BASE64_ENCODED 
  SECRET: --> A_RANDOM_SECRET_BASE64_ENCODED 
---

##
# Main deployment
## 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: traefik-forward-auth
  name: traefik-forward-auth
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik-forward-auth
  template:
    metadata:
      labels:
        app: traefik-forward-auth
    spec:
      containers:
        - name: traefik-forward-auth
          image: thomseddon/traefik-forward-auth
          ports:
            - containerPort: 4181
              protocol: TCP
          env:
            - name: CLIENT_ID
              value: XXXXXX.apps.googleusercontent.com
            - name: CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: traefik-forward-auth-secrets
                  key: CLIENT_SECRET
            - name: SECRET
              valueFrom:
                secretKeyRef:
                  name: traefik-forward-auth-secrets
                  key: SECRET
            - name: COOKIE_SECURE
              value: 'true'
            - name: DOMAINS
              value: example.com,example.org
          livenessProbe:
            tcpSocket:
              port: 4181
            initialDelaySeconds: 20
            failureThreshold: 3
            successThreshold: 1
            periodSeconds: 10
            timeoutSeconds: 2
---

##
# Related service
##
kind: Service
apiVersion: v1
metadata:
  name: traefik-forward-auth
  namespace: kube-system
spec:
  selector:
    app: traefik-forward-auth
  ports:
    - port: 80
      targetPort: 4181
      protocol: TCP

And here is how to configure an authenticated ingress using annotations (equivalent to Compose / Swarm labels):

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: my-app
  namespace: my-app-namespace
  annotations:
    kubernetes.io/ingress.class: traefik
    ingress.kubernetes.io/auth-type: forward
    ingress.kubernetes.io/auth-url: http://traefik-forward-auth.kube-system.svc.cluster.local
    ingress.kubernetes.io/auth-response-headers: X-Forwarded-User
spec:
  rules:
    - host: my-app.com
      http:
        paths:
          - backend:
              serviceName: my-app
              servicePort: 80

Also, here the command to encode the secrets in base64:

echo -n 'my-great-secret' | base64

Best

email field in cookie is empty

Hi,

I followed the Readme in setting up the forward-auth and the google oauth settings.
Running forward-auth 2.0.1 with traefik 1.7.12 on k8s with the .yml from issue #33.
Everything works fine, except the e-mail based whitelisting, where I am always rejected as unauthorized.
When checking the logs, I noticed that the email field in the cookie is empty:

time="2019-07-12T20:34:12Z" level=debug msg="Handling callback" headers="map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-GB,en;q=0.9,de-DE;q=0.8,de;q=0.7,en-US;q=0.6] Cookie:[_forward_auth_csrf={some_long_string}] Dnt:[1] Referer:[https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id={some_long_string}.apps.googleusercontent.com&as={some_long_string}&destination=https%3A%2F%2Fauth.mydomain.de%3A42443&approval_state={some_long_string}&oauthgdpr=1&xsrfsig={some_long_string}&flowName=GeneralOAuthFlow] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36] X-Forwarded-For:[10.42.0.83] X-Forwarded-Host:[auth.mydomain.de:42443] X-Forwarded-Method:[GET] X-Forwarded-Proto:[https] X-Forwarded-Uri:[/_oauth?state={some_long_string}%3Ahttps%3A%2F%2Fdashboard.mydomain.de%3A42443%2F%5D&code={some_long_string}&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&session_state={some_long_string}&prompt=consent]]" rule=default source_ip=10.42.0.83
time="2019-07-12T20:34:12Z" level=info msg="Generated auth cookie" source_ip=10.42.0.83 user= 
time="2019-07-12T20:34:12Z" level=debug msg="Authenticating request" headers="map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-GB,en;q=0.9,de-DE;q=0.8,de;q=0.7,en-US;q=0.6] Cookie:[_forward_auth={some_long_string}|1563006852|] Dnt:[1] Referer:[https://accounts.google.com/signin/oauth/oauthchooseaccount?client_id={some_long_string}.apps.googleusercontent.com&as={some_long_string}&destination=https%3A%2F%2Fauth.mydomain.de%3A42443&approval_state={some_long_string}&oauthgdpr=1&xsrfsig={some_long_string}&flowName=GeneralOAuthFlow] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36] X-Forwarded-For:[10.42.0.83] X-Forwarded-Host:[dashboard.mydomain.de:42443] X-Forwarded-Method:[GET] X-Forwarded-Proto:[https] X-Forwarded-Uri:[/]]]" rule=default source_ip=10.42.0.83

Any idea what might be the issue?

Getting infinite redirects

I'm trying to setup oauth2 configuration in docker swarm with traefik + traefik-forward-auth. My traefik-forward-auth:v2.0.0 configuration is:

client-id=<...>
client-secret=<...>
secret=<...>
cookie-domain=example.com
domain=example.com
auth-host=auth.example.com
log-level=debug

Service traefik labels configuration:

"traefik.enable": "true",
"traefik.frontend.auth.forward.address": "http://traefik_forward_auth:4181",
"traefik.frontend.auth.forward.authResponseHeaders": "X-Forwarded-User",
"traefik.frontend.auth.forward.trustForwardHeader": "true",
"traefik.frontend.entryPoints": "http,https",
"traefik.frontend.redirect.entryPoint": "https",
"traefik.frontend.rule": "Host: internal-website.example.com",

Debug logs from traefik-forward-auth:

traefik_forward_auth.1.8yhf0jqbh2k4@ip-10-0-12-160    | time="2019-06-26T04:46:23Z" level=debug msg="Set CSRF cookie and redirecting to google login" source_ip=10.255.0.9
traefik_forward_auth.1.8yhf0jqbh2k4@ip-10-0-12-160    | time="2019-06-26T04:46:23Z" level=debug msg=Done source_ip=10.255.0.9
traefik_forward_auth.2.qez8i8b3kxij@ip-10-0-10-223    | time="2019-06-26T04:46:24Z" level=debug msg="Authenticating request" headers="map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[en-US,en;q=0.5] Cache-Control:[no-cache] Cookie:[_forward_auth_csrf=<cookie>] Pragma:[no-cache] Referer:[https://accounts.google.gr/accounts/SetSID] Te:[trailers] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:67.0) Gecko/20100101 Firefox/67.0] X-Forwarded-For:[10.255.0.9] X-Forwarded-Host:[auth.example.com] X-Forwarded-Port:[443] X-Forwarded-Proto:[https] X-Forwarded-Server:[09caed4a73f2] X-Real-Ip:[10.255.0.9]]" rule=default source_ip=10.255.0.9

The google oauth2 uses the domain "auth.example.com/_oauth".

  1. Request to internal-website.example.com/
  2. User redirected to Google login
  3. After Google login, user is redirected to auth.example.com/_oauth

Up to this point it works, I'm able to authenticate to google and get redirected back to auth website.
But then instead of token and CSRF validation, I get redirect again to google and the auth process starts from (1).
I don't see logs of failed redirection or anything like that on the server (traefik-forward-auth) side, it is like a fresh start.

  1. Token, user and CSRF cookie is validated, auth cookie is set to example.com
  2. User is redirected to internal-website.example.com
  3. Request is allowed

Is there anything obvious I'm missing?

Customize whitelist/domain for specific services/endpoints

Is it currently possible to override the whitelist/domain for a particular service?

I have a server based on docker-compose with 35 services. Some of them I want them to be accessible but more people than me while the most part of them I would like them to keep private. Is there anything I can customize via labels or similar for such a case?

If not, is it possible to disable the OAuth2 on certain endpoints?

Add support for reading config parameters from files for use with docker secrets

Would like to be able to provide things like client-id, client-secret, and secret from docker secrets stored as files. Could either load the entire config from a file stored as a docker secret or (preferably) have additional environment variable options like the docker example:

  • CLIENT_ID_FILE
  • CLIENT_SECRET_FILE
  • SECRET_FILE

This would enable the use of secrets in a similar fashion to the example:

environment:
       CLIENT_ID_FILE: /run/secrets/oauth_client_id

Support Strict-Transport-Security

It would be a good feature to have configuration options allowing the enablement of strict transport security headers including the duration, subdomain inclusion flag and the preload flag so that the initial redirect to the google login page sends the Strict-Transport-Security header.

It is only currently possible to send this header after authenticating with Google via traefik configuration.

Limit forward auth to selected domains

Originally asked this on SO: https://stackoverflow.com/questions/55200953/can-i-use-forward-auth-only-for-some-domains-with-traefik

I would like to use traefik with forward auth using an oauth provider. In traefik, forward auth config is tied to an entry point.

However, I only want to apply foward auth to some of the configured domains. Domain configuration is not part of the entrypoint config.

I was wondering how to best solve this, e.g. deploying a "child" traefik instance for selected domains that would have forward auth enabled.

Instead, it would seem easiest to add something like --unauthorized-domains to this image. For any domain or subdomain in this list, traefik-forward-auth would then always return HTTP 200 instead of executing the auth flow.

Would something like this make sense and/or would you accept a PR?

Got your Projected Baked into PlexGuide

Here is the wiki for it: https://github.com/Admin9705/PlexGuide.com-The-Awesome-Plex-Server/wiki/PG-Shield

Also i'll work a youtube video and if you click this, https://plexguide.com/news/7-7-changelog/ there are screen shots at the bottom! Hopefully more stars come your way! put it in the sum and looks like it jumped up 7 within 2 days. People want to use this, so they are 99% of the time going to read the wiki. Let me know if you want to trade github links or ect, plus you can list it as a major project that utilizes your project :D

Timeouts?

Hi,

I've set up traefik-forward-auth (from @funkypenguin's patch). It works great, but in some case I get timeouts where I can't access the hosts behind the Traefik controller. I'm thinking the bottleneck is traefik-forward-auth which is not able to process the request in time? I can't find any logs though that help me diagnose where the problem is. Anyone else experienced timeout or slowness using traefik-forward-auth?

Limit access to specific subdomains

Hello!

I'm looking for a traefik oauth2 solution and came across this great project. I'm trying to figure out if I can put a specific set of subdomains behind google OAuth2. For example:

  • service1.domain.com (no OAuth2)
  • service2.domain.com (redirects for OAuth2)

Ideally, I'd have to use something like labels. I came across issue #26 but I'm not sure how the configuration works.

v2 breaks support for configuration lists on environment variables

I've used environment variables exclusively for configuration rather than files.
This included multiple domains in the DOMAIN environment variable.
The recent push of v2 to the latest tag on docker hub broke my auth (as I had watchtower updating for me) with a log message:
time="2019-06-11T00:40:13Z" level=error msg="Invalid email" email=<redacted valid email> source_ip=<redacted IP>

I think this is because auth.go:ValidateEmail fails as config.Domains has treated multiple domains in a comma separated list as a single domain, so the domain supplied doesn't match. Looking at changes to config.go I wasn't able to see where this change came from - it looks like config.go is new for v2. I'm away from my developer pc so not able to dig further easily.
This change from comma separate lists to repeating single values could impact any setting which had multiple values set via environment variables - as duplicate environment variables aren't possible.

There is no deprecation warning logged on startup for this change of behaviour (I wasn't using DOMAINS as the environment variable which would show this). Maybe I had screwed up my config and been lucky it was working.

I'll need to update my config to an ini file which I didn't notice/realize was an option before, that looks better suited for how I've configured as .

Thanks for your time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.