Hello,
when using oauth2-proxy in conjuction with traefik, it "works" but fails to redirect to the originating URL.
ForwardAuth with 401 errors middleware
The Traefik v2ForwardAuth
middleware allows Traefik to authenticate requests via the oauth2-proxy's/oauth2/auth
endpoint on every request, which only returns a 202 Accepted response or a 401 Unauthorized response without proxying the whole request through. For example, on Dynamic File (YAML) Configuration:
Src: Overview | OAuth2 Proxy
Apparently the issue lays with traefik
not forwarding the proper URL so that the user gets redirected to the original intended URL if I understand correctly.
Has anyone found a way around this ? (the example in oauth2-proxy
seems to just be intended to show-case the bug).
Thanks in advance for your help.
my current implementation is the following:
POC service :
whoami-monitoring:
image: "traefik/whoami"
container_name: "whoami-monitoring"
networks:
- internal
- docker-proxy-internal
labels:
traefik.enable: true
traefik.docker.network: traefik-proxy
traefik.http.routers.whoami-web.rule: Host(`whoami.${DOMAIN?err}`) && PathPrefix(`/foo`)
traefik.http.routers.whoami-web.priority: 90
traefik.http.routers.whoami-web.middlewares: oauth-chain
traefik.http.routers.whoami-web.entrypoints: websecure
traefik.http.routers.whoami-web.service: whoami-web
traefik.http.services.whoami-web.loadbalancer.server.port: 80
traefik.http.routers.whoami-jump.rule: Host(`whoami.${DOMAIN?err}`) && PathPrefix(`/bar`)
traefik.http.routers.whoami-jump.priority: 80
traefik.http.routers.whoami-jump.middlewares: restrict-chain
traefik.http.routers.whoami-jump.entrypoints: websecure
traefik.http.routers.whoami-jump.service: whoami-jump
traefik.http.services.whoami-jump.loadbalancer.server.port: 80
oauth2 service :
oauth2:
#image: quay.io/pusher/oauth2_proxy:${OAUTH2_PROXY_VERSION}
image: quay.io/oauth2-proxy/oauth2-proxy:v7.2.1
container_name: "oauth"
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--tries=1", "--spider", "http://oauth:4180/ping"]
interval: 60s
timeout: 10s
labels:
ai.ix.expose: 'true'
traefik.enable: 'true'
traefik.http.middlewares.oauth-verify.forwardAuth.address: http://oauth:4180/oauth2/auth
traefik.http.middlewares.oauth-verify.forwardAuth.trustForwardHeader: 'true'
traefik.http.middlewares.oauth-verify.forwardAuth.authResponseHeaders: X-Auth-Request-User,X-Auth-Request-Email,Set-Cookie,X-Auth-User,X-Secret
traefik.http.middlewares.oauth-signin.errors.service: oauth@docker
traefik.http.middlewares.oauth-signin.errors.status: '401'
traefik.http.middlewares.oauth-signin.errors.query: /oauth2/sign_in
traefik.http.routers.oauth.entrypoints: websecure
traefik.http.routers.oauth.rule: Host(`oauth.${DOMAIN?err}`) || PathPrefix(`/oauth2`)
traefik.http.routers.oauth.tls.certResolver: myresolver
traefik.http.routers.oauth.service: oauth@docker
traefik.http.services.oauth.loadbalancer.server.port: '4180'
environment:
# https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#environment-variables
OAUTH2_PROXY_PROVIDER: gitlab
OAUTH2_PROXY_GITLAB_GROUP: ${OAUTH2_PROXY_GITLAB_GROUP}
OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID?err}
OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET?err}
OAUTH2_PROXY_COOKIE_DOMAINS: ${DOMAIN?err}
OAUTH2_PROXY_COOKIE_REFRESH: '1h'
OAUTH2_PROXY_COOKIE_SECURE: 'false'
OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET?err}
OAUTH2_PROXY_COOKIE_HTTPONLY: 'true'
OAUTH2_PROXY_COOKIE_NAME: '_oauth2_proxy'
OAUTH2_PROXY_EMAIL_DOMAINS: '*'
OAUTH2_PROXY_FOOTER: '-'
OAUTH2_PROXY_HTTP_ADDRESS: '0.0.0.0:4180'
OAUTH2_PROXY_PASS_BASIC_AUTH: 'false'
OAUTH2_PROXY_PASS_USER_HEADERS: 'true'
OAUTH2_PROXY_REVERSE_PROXY: 'true'
OAUTH2_PROXY_SET_AUTHORIZATION_HEADER: 'true'
OAUTH2_PROXY_SET_XAUTHREQUEST: 'true'
OAUTH2_PROXY_WHITELIST_DOMAINS: '.${DOMAIN?err}'
OAUTH2_PROXY_REDIRECT_URL: "https://oauth.${DOMAIN}/oauth2/callback"
networks:
- internal
- docker-proxy-internal
traefik:
image: traefik:latest
container_name: "traefik"
command:
- --log.level=DEBUG
- --api.dashboard=true
- --api.insecure=true
# Do not expose all Docker services by default
- --providers.docker=true
- --providers.docker.exposedbydefault=false
#- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- --providers.docker.endpoint=tcp://proxy:2375
- --providers.docker.network=traefik-proxy
# DNS Challenge (domain.tld and *.domain.tld DNS zones are defined there) : hetzner
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- --certificatesresolvers.myresolver.acme.email=postmaster@${SERVER_HOSTNAME}
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.myresolver.acme.dnschallenge=true
- --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
- --certificatesresolvers.myresolver.acme.dnschallenge.provider=hetzner
- --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=helium.ns.hetzner.de,hydrogen.ns.hetzner.com,oxygen.ns.hetzner.com
# HTTPS : port 443, with letsencrypt certificates provided by myresolver
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls=true
- --entrypoints.websecure.http.tls.certResolver=myresolver
#- --entrypoints.websecure.http.tls.domains[0].main=${SERVER_HOSTNAME}
#- --entrypoints.websecure.http.tls.domains[0].sans=*.${SERVER_HOSTNAME}
- --entrypoints.websecure.http.tls.domains[0].main=${CERT_DOMAIN}
- --entrypoints.websecure.http.tls.domains[0].sans=*.${CERT_DOMAIN}
- --entrypoints.websecure.http.tls.domains[1].main=${SERVER_HOSTNAME}
- --entrypoints.websecure.http.tls.domains[1].sans=*.${SERVER_HOSTNAME}
# staging letsencrypt (no quotas, but self signed certificates), comment to move to prod
#- --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
#- "--providers.docker.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
# Redirect HTTP (web) to HTTPS (websecure)
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
# Expose prometheus metrics on port 8082 (rerouted by labels)
- --metrics.prometheus=true
- '--metrics.prometheus.buckets=0.1,0.3,1.2,5.0'
- --metrics.prometheus.addrouterslabels=true
- --metrics.prometheus.addServicesLabels=true
- --metrics.prometheus.addEntryPointsLabels=true
- --entryPoints.metrics.address=:8082
- --metrics.prometheus.entryPoint=metrics
- --metrics.prometheus.manualrouting=true
- --accesslog=true
# entrypoint for mezos through load-balancers on ${trustedIPs}
- --entryPoints.mainnet-mezos-lb.address=:39090
#- --entryPoints.mainnet-mezos-lb.proxyProtocol.insecure
- --entryPoints.mainnet-mezos-lb.proxyProtocol.trustedIPs=${trustedIPs}
- --entryPoints.mainnet-mezos-lb.http.tls=false
# entrypoint for graphic-proxy through load-balancers on ${trustedIPs}
- --entryPoints.mainnet-graphic-proxy-lb.address=:49090
#- --entryPoints.mainnet-graphic-proxy.proxyProtocol.insecure
- --entryPoints.mainnet-graphic-proxy-lb.proxyProtocol.trustedIPs=${trustedIPs}
- --entryPoints.mainnet-graphic-proxy-lb.http.tls=false
# Writing Logs to a File
# - "--log.filePath=/logs/traefik.log"
# Writing Logs to a File, format = common or json
#- "--log.format=common"
# Acepted log levels = DEBUG, PANIC, FATAL, ERROR, WARN, and INFO
- "--log.level=DEBUG"
#- "--tracing=true"
- "--pilot.token=${traefik_pilot_token}"
environment:
- HETZNER_API_KEY=${traefik_DNS_cert_Hetzner_API_Key:-notset}
restart: always
ports:
- "80:80"
- "443:443"
- "39090:39090"
- "49090:49090"
#- "8080:8080" default for dashboard, routed to https with labels
#- "8082:8082" set for prometheus, rerouted to http with labels
volumes:
- traefik-letsencrypt:/letsencrypt
- traefik-logs:/logs
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- internal
- docker-proxy-internal
labels:
#"traefik.frontend.rule: HostRegexp(`{catchall:.*}`)"
traefik.enable: true
# prometheus exporter
traefik.http.routers.traefikmetrics.rule: Host(`traefik-metrics.${SERVER_HOSTNAME}`)
traefik.http.routers.traefikmetrics.entrypoints: websecure
traefik.http.routers.traefikmetrics.service: prometheus@internal
traefik.http.services.traefikmetrics.loadbalancer.server.port: 8082
traefik.http.routers.traefikmetrics.tls.certresolver: myresolver
traefik.http.routers.traefikmetrics.middlewares: restrict-chain
# traefik dasboard
traefik.http.routers.api.rule: Host(`traefik.${SERVER_HOSTNAME}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
traefik.http.routers.api.entrypoints: websecure
traefik.http.routers.api.service: api@internal
traefik.http.services.api.loadbalancer.server.port: 8080
traefik.http.routers.api.tls.certresolver: myresolver
traefik.http.routers.api.middlewares: oauth-chain
traefik.http.middlewares.default-compress.compress: 'true'
traefik.http.middlewares.default-http.redirectScheme.scheme: https
traefik.http.middlewares.default-http.redirectScheme.permanent: 'true'
traefik.http.middlewares.default-https.chain.middlewares: default-compress
traefik.http.middlewares.oauth-chain.chain.middlewares: default-https,oauth-signin,oauth-verify
traefik.http.middlewares.restrict-chain.chain.middlewares: default-https,ip-whitelist
traefik.http.middlewares.ip-whitelist.ipwhitelist.sourcerange: "127.0.0.1/32, ${monitoring_server_ip}"