Missing Authorization header with ForwardAuth in Traefik - traefik

I have following traefik setup:
mybackend - golang backend
myauth - dedicated auth backend validating jwt token.
all run with traefik.
I want all requests first pass through myauth backend to validate jwt token / rate limit users before reaching mybackend.
When using this configuration myauth doesn't receive Authorization header containing authorization jwt token.
When I don't use forwardauth middleware Authorization header is there.
Here is the traefik configuration file I have:
version: '3'
services:
reverse-proxy:
image: traefik:v2.0
restart: always
command:
- "--api=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.http.address=:80"
- "--entrypoints.https.address=:443"
- "--certificatesresolvers.mydnschallenge.acme.dnschallenge=true"
- "--certificatesresolvers.mydnschallenge.acme.dnschallenge.provider=digitalocean"
- "--certificatesresolvers.mydnschallenge.acme.email=support#mydomain.com"
- "--certificatesresolvers.mydnschallenge.acme.storage=/acme.json"
environment:
- DO_AUTH_TOKEN=${DO_AUTH_TOKEN}
ports:
- "80:80"
- "443:443"
- "6969:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ../acme/acme.json:/acme.json
mybackend:
image: mybackend
restart: always
depends_on:
- mongo
labels:
- "traefik.enable=true"
# creates new middleware called redirect-to-https
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# creates new router called redirect-https
- "traefik.http.routers.redirect-https.rule=Host(`api.mydomain.com`)"
- "traefik.http.routers.redirect-https.entryPoints=http"
# applies middleware to router
- "traefik.http.routers.redirect-https.middlewares=redirect-to-https"
# creates new router called api_tls
- "traefik.http.routers.api.entryPoints=https"
- "traefik.http.routers.api.tls.certresolver=mydnschallenge"
- "traefik.http.routers.api.rule=Host(`api.mydomain.com`)"
- "traefik.http.services.api.loadbalancer.server.port=8080"
- "traefik.http.routers.api.middlewares=ratelimitme"
- "traefik.http.middlewares.ratelimitme.forwardauth.address=http://myauth:8080"
- "traefik.http.middlewares.ratelimitme.forwardauth.trustforwardheader=true"
- "traefik.http.middlewares.ratelimitme.forwardauth.authresponseheaders=X-Forwarded-User"
myauth:
image: myauth
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.rate_limiting.entrypoints=http"
- "traefik.http.services.rate_limiting.loadbalancer.server.port=8080"
I tried setting new middleware to set custom headers like this:
- "traefik.http.middlewares.frontend1.headers.customresponseheaders.Access-Control-Allow-Methods=POST, GET, PUT, OPTIONS, DELETE"
- "traefik.http.middlewares.frontend1.headers.customresponseheaders.Access-Control-Allow-Origin=*"
- "traefik.http.middlewares.frontend1.headers.customresponseheaders.Access-Control-Allow-Headers=x-requested-with, Content-Type,Authorization"
but it didn't help.
Thanks for any tips / advices.

Add "Authorization" to the authRequestHeader. For example (using kubernetes):
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: api-auth
namespace: kube-system
spec:
forwardAuth:
address: http://api-auth.default.svc/auth/v1/validate
authRequestHeaders:
- "Authorization"
authResponseHeaders:
- "X-Auth-ID"
---

Related

Inconsistent behaviour while achieving stickiness using Kong Ingress controller

I am using Kong ingress controller on EKS.
High level flow:
NLB → Kong ingress controller and proxy(running in the same pod) → k8s service → backend pods
I am trying to achieve stickiness using hash_on cookies configuration on upstream.
I am using session and hmac_auth plugin for generating session/cookie.
1st request from the client: First time when the client sends a message to the NLB, NLB sends the traffic to Kong ingress controller and from there it’s goes to one of the backend pods. This is the first time and so Kong will generate a cookie and send it back in the response to the client.
2nd request from the client: Now second time when client is sending the request it is including the cookie as well it got from the response of 1st request. Now when the request comes to Kong it forwards the request to some other pod, other than the pod it forwarded the request for the first time.
On 3rd, 4th…nth request Kong is forwarding the request to the same pod it forwarded to in the 2nd request.
How can we achieve stickiness for every request ?
My expectation was first time when Kong receives a request from a client it will generate a Cookie and it will put some detail specific to the pod it is sending traffic to and next time whenever the same client sends a request it will send the cookie with it, kong should use the cookie and forward the request to the same pod it forwarded the first time…but this is not happening…I am getting stickiness after 2nd to nth request but not for the 1st request.
`Ingress resource used for defining path:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
konghq.com/strip-path: "true"
name: kong-ingress-bk-srvs
namespace: default
spec:
ingressClassName: kong
rules:
- http:
paths:
- backend:
service:
name: httpserver-service-cip
port:
number: 8084
path: /api/v1/serverservice
pathType: Prefix
- backend:
service:
name: httpserver-service-cip-health
port:
number: 8084
path: /api/v1/healthservice
pathType: Prefix`
`upstream config:
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: stickiness-upstream
upstream:
hash_on: cookie
hash_on_cookie: my-test-cookie
hash_on_cookie_path: /`
`session plugin:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: session-plugin
config:
cookie_path: /
cookie_name: my-test-cookie
storage: cookie
cookie_secure: false
cookie_httponly: false
cookie_samesite: None
plugin: session`
`hmac plugin
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: hmac-plugin
config:
validate_request_body: true
enforce_headers:
- date
- request-line
- digest
algorithms:
- hmac-sha512
plugin: hmac-auth`
`consumer:
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: kong-consumer
annotations:
kubernetes.io/ingress.class: kong
username: consumer-user-3
custom_id: consumer-id-3
credentials:
- kong-cred
`
`Pod service config:(ingress backend service)
apiVersion: v1
kind: Service
metadata:
annotations:
konghq.com/override: stickiness-upstream
konghq.com/plugins: session-plugin,hmac-plugin
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"configuration.konghq.com":"stickiness-upstream"},"labels":{"app":"httpserver"},"name":"httpserver-service-cip","namespace":"default"},"spec":{"ports":[{"name":"comm-port","port":8085,"targetPort":8085},{"name":"dur-port","port":8084,"targetPort":8084}],"selector":{"app":"httpserver"},"sessionAffinity":"ClientIP","sessionAffinityConfig":{"clientIP":{"timeoutSeconds":10000}}}}
creationTimestamp: "2023-02-04T16:44:00Z"
labels:
app: httpserver
name: httpserver-service-cip
namespace: default
resourceVersion: "6729057"
uid: 481b7d8c-1f07-4293-809c-3b4b7dca41e0
spec:
clusterIP: 10.101.99.87
clusterIPs:
- 10.101.99.87
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: comm-port
port: 8085
protocol: TCP
targetPort: 8085
- name: dur-port
port: 8084
protocol: TCP
targetPort: 8084
selector:
app: httpserver
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10000
type: ClusterIP
status:
loadBalancer: {}`

Traefik 2.0 301 Redirect Not Working Load Balancing

I have the below config file that I am using to load balance my application. HTTPS is working fine, but there are some parts of the application that still produce a 302/301 response and the application breaks. I have been able to find a work around with HAProxy, but I cannot seem to make it work with Traefik. As you can tell I have tried a few things below and it either breaks altogether or doens't work.
http:
#region routers
routers:
app-rtr:
entryPoints:
- https
- http
# https:
# address: ":443"
# http:
# address: ":80"
# http:
# redirections:
# entryPoint:
# to: https
# schema: https
rule: "Host(`services.domain.io`)"
middlewares:
# - redirect
# - https-redirectscheme
- middlewares-compress
tls:
certResolver: "cf"
domains:
- main: "services.neotericservices.io"
service: app
#endregion
#region services
services:
app:
loadBalancer:
healthCheck:
path: /health
interval: "10s"
timeout: "5s"
scheme: http
sticky:
cookie: {}
servers:
- url: "http://172.16.9.90:16005"
- url: "http://172.16.9.90:16006"
- url: "http://172.16.9.91:16009"
- url: "http://172.16.9.91:16010"
- url: "http://172.16.9.93:16007"
- url: "http://172.16.9.93:16008"
passHostHeader: true
#endregion
middlewares:
redirect:
redirectRegex:
regex: "^http://*(services.domain.io)(.*)"
replacement: "https://$1$2"
permanent: true
https-redirectscheme:
redirectScheme:
scheme: https
permanent: true

How to configure forward auth in Traefik 2?

I'm migrating an old API to Traefik 2 and I can't get forward auth to work. The configuration below is pretty much the equivalent of what we had with Traefik 1.7, but I keep getting "404 page not found" for everything unless I comment out the entry point middleware as well as the auth labels. The Traefik documentation doesn't seem to explain this in any more detail besides adding the middleware itself and some configuration options.
As I understand it this should do forward auth for the web and websecure entry points to the auth entry point and I assigned the /auth path on the auth entry point to our API container.
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.http]
middlewares = ["auth"]
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.http]
middlewares = ["auth"]
[entryPoints.websecure.http.tls]
[entryPoints.auth]
address = ":7000"
[http.middlewares]
[http.middlewares.auth.forwardAuth]
address = "http://127.0.0.1:7000/auth"
version: '3.8'
services:
proxy:
image: traefik:2.8
volumes:
ports:
- 80:80
- 443:443
- 7000:7000
api:
image: api
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.rule=Host(`api.example.org`)
- traefik.http.services.api.loadbalancer.server.port=8000
- traefik.http.routers.auth.entrypoints=auth
- traefik.http.routers.auth.rule=PathPrefix(`/auth`)
- traefik.http.services.auth.loadbalancer.server.port=8000
I figured out my configuration had 2 issues.
Middleware must be defined using the dynamic configurtation (note the change to auth#file):
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.http]
middlewares = ["auth#file"]
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.http]
middlewares = ["auth#file"]
[entryPoints.websecure.http.tls]
[entryPoints.auth]
address = ":7000"
[providers.file]
filename = "/etc/traefik/dynamic.toml"
[http.middlewares]
[http.middlewares.auth.forwardAuth]
address = "http://127.0.0.1:7000/auth"
Multiple router definitions require explicit service targets:
version: '3.8'
services:
api:
image: api
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.rule=Host(`api.example.org`)
- traefik.http.routers.api.service=api # Required
- traefik.http.services.api.loadbalancer.server.port=8000
- traefik.http.routers.auth.entrypoints=auth
- traefik.http.routers.auth.rule=PathPrefix(`/auth`)
- traefik.http.routers.auth.service=auth # Required
- traefik.http.services.auth.loadbalancer.server.port=8000

"No default certificate, generating one" when a default certificate is provided

This probably a newbie question regarding traefik and the SSL configuration.
I'd like to use my own (self-signed, company, ...) certificates with traefik. I tried to follow the documentation, but I keep on getting the following message:
... level=debug msg="No default certificate, generating one"
My traefik.tomllooks like this:
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.http]
[entryPoints.web.http.redirections]
[entryPoints.web.http.redirections.entryPoint]
to = "websecure"
scheme = "https"
[entryPoints.websecure]
address = ":443"
[log]
level = "DEBUG"
[api]
insecure = true
dashboard = true
[providers.docker]
exposedByDefault = false
[[tls]]
entryPoints = ["websecure"]
[[tls.certificate]]
certFile = "/certs/cert.crt"
keyFile = "/certs/cert.key"
[tls.stores]
[tls.stores.default]
[tls.stores.default.defaultCertificate]
certFile = "/cert/cert.crt"
keyFile = "/cert/cert.key"
and my docker-compose.yml looks like this:
version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.2
ports:
# The HTTP port
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock:ro
- $PWD/shared/traefik/etc/traefik.toml:/etc/traefik/traefik.toml
- $PWD/shared/traefik/ssl:/certs/
whoami:
# A container that exposes an API to show its IP address
image: containous/whoami
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.basic-auth-whoami.basicauth.users=***:***"
- "traefik.http.middlewares.strip-whoami.stripprefix.prefixes=/whoami"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.middlewares=basic-auth-whoami#docker,strip-whoami#docker"
- "traefik.http.routers.whoami.rule=PathPrefix(`/whoami`) && Host(`<mydomain>`)"
- "traefik.http.services.whoami-poc-traefik.loadbalancer.server.port=80"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.redirs.entrypoints=web"
- "traefik.http.routers.redirs.middlewares=redirect-to-https"
- "traefik.http.routers.whoami.tls=true"
I am quite sure this is something trivial but I can't figure it out (both the toml syntax and traefik concepts being a too much to swallow at once).
I finally found out what was not working by following this blog
I had to:
Add file provider for dynamic configuration to my traefik.toml file:
[providers.file]
filename = "/tls-certs.toml"
Add a volume mapping to my docker-compose.yml file:
- $PWD/shared/traefik/etc/tls-certs.toml:/tls-certs.toml
Provide a tls-certs.toml file:
[[tls.certificates]] #first certificate
certFile = "/certs/cert.crt"
keyFile = "/certs/cert.key"

Default router with Traefik

I would like to route traffic on HTTP Headers with Traefik. In case there is no matching rules, I need to route to another service or return a custom status code (426). Is it possible to configure default case for rules ?
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: headers
spec:
entrypoints:
- web
- websecure
routes:
- match: Headers(`X-ROUTE`,`Apache`)
kind: Rule
services:
- name: apache
port: 80
- match: Headers(`X-ROUTE`,`nginx`)
kind: Rule
services:
- name: nginx
port: 80
- else ??
You can add this case to match anything with the lowest priority which is 1.
- match: HostRegexp(`{catchall:.*}`)