K8s -> nginx Ingress: SSO - authentication

I have a service that has HTTP Basic Auth. In front of it I have nginx Ingress, who also has basic-auth. How can I attach Authorization header with the credentials after Sign In with the Ingress, to achieve Single-Sign-On?
This is the configuration of my Ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-realm: Authentication Required
nginx.ingress.kubernetes.io/auth-secret: kibana-user-basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
name: kibana-user
namespace: {{.Release.Namespace}}
spec:
tls:
- secretName: kibana-tls
hosts:
- {{.Values.ingress.user.host}}
rules:
- host: {{.Values.ingress.user.host}}
http:
paths:
- backend:
serviceName: kibana-logging
servicePort: {{ .Values.kibana.service.internalPort }}
path: /

You could use the annotation nginx.ingress.kubernetes.io/configuration-snippet: proxy_set_header Authorization $http_authorization; to forward the Authorization header to the back end service.
The Ingress resource should looks like this
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-realm: Authentication Required
nginx.ingress.kubernetes.io/auth-secret: kibana-user-basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/configuration-snippet: "proxy_set_header Authorization $http_authorization;"
name: kibana-user
namespace: {{.Release.Namespace}}
spec:
tls:
- secretName: kibana-tls
hosts:
- {{.Values.ingress.user.host}}
rules:
- host: {{.Values.ingress.user.host}}
http:
paths:
- backend:
serviceName: kibana-logging
servicePort: {{ .Values.kibana.service.internalPort }}
path: /

I guess that you can propagate Authorization header within nginx.ingress.kubernetes.io/auth-response-headers annotation:
nginx.ingress.kubernetes.io/auth-response-headers: Authorization
Or, alternative way you can achieve the same approach by applying proxy_set_header inside the target Ingress location via configuration snippet annotation as described here:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Authorization "Basic base64 encode value";

Related

Add custom response header traefik ingress on K3S

How does one add a custom response header to traefik ingress on a K3S ?
I have followed the official doc and a few answers from stackoverflow. But none seems to work.
Here is my ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: traeffic-custom-response-header
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/custom-response-headers: Bypass-Tunnel-Reminder:true
ingress.kubernetes.io/custom-response-headers: Bypass-Tunnel-Reminder:true
spec:
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: scc-worker
port:
number: 8000
I am running a local K3S cluster on my PC for testing.
And I am not able to add custom response header.
Ok, I solved this issue by adding middleware and then configuring it in my Ingress Controller Configuration
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: add-bypass-tunnel-header
namespace: mynamespace
spec:
headers:
customResponseHeaders:
Bypass-Tunnel-Reminder: "true"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: traeffic-custom-request-header
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: mynamespace-add-bypass-tunnel-header#kubernetescrd
traefik.ingress.kubernetes.io/custom-response-headers: Bypass-Tunnel-Reminder:true
ingress.kubernetes.io/custom-response-headers: Bypass-Tunnel-Reminder:true
spec:
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: scc-worker
port:
number: 8000
Here add-bypass-tunnel-header is a middle ware being created
And then adding it to traefik ingress by traefik.ingress.kubernetes.io/router.middlewares: mynamespace-add-bypass-tunnel-header#kubernetescrd annotation

Nginx ingress with oauth proxy and CORS

I have two services in Kubernetes which are exposed through nginx controller. Service a wants to invoke content on domain b but at the same time both services need to be authenticated through Google using the oauth-proxy service.
So I have managed to enable CORS and a can invoke b without any issues. But the problem is when I include the authentication as well, I am constantly getting:
Access to manifest at 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=<obscured>.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fa.example.com%2Foauth2%2Fcallback&response_type=code&scope=profile+email&state=<obscured>manifest.json' (redirected from 'https://a.example.com/manifest.json') from origin 'https://a.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here are the ingresses:
Service a
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
name: a
spec:
rules:
- host: a.example.com
http:
paths:
- backend:
service:
name: a-svc
port:
number: 8080
path: /
pathType: Prefix
tls:
- hosts:
- a.example.com
secretName: a-tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
labels:
k8s-app: oauth2-proxy
name: a-oauth
spec:
rules:
- host: a.example.com
http:
paths:
- backend:
service:
name: oauth2-proxy
port:
number: 4180
path: /oauth2
pathType: Prefix
tls:
- hosts:
- a.example.com
secretName: a-oauth-tls
Service b
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
name: b
spec:
rules:
- host: b.example.com
http:
paths:
- backend:
service:
name: b-svc
port:
number: 8080
path: /
pathType: Prefix
tls:
- hosts:
- b.example.com
secretName: b-tls
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0
labels:
k8s-app: oauth2-proxy
name: b-oauth
spec:
rules:
- host: b.example.com
http:
paths:
- backend:
service:
name: oauth2-proxy
port:
number: 4180
path: /oauth2
pathType: Prefix
tls:
- hosts:
- b.example.com
secretName: b-oauth-tls
Obviously, there is only one difference between these two and that is the cors annotations nginx.ingress.kubernetes.io/enable-cors: "true" in the service b ingresses.
I am not sure of what is causing the issue but I am guessing that the authentication done against Google in service a is not being passed to the CORS request so that the service b can also be authenticate with the same token/credentials.
What am I doing wrong and how can I resolve this?
Based on the documentation, it looks like you lack of annotations for using HTTP.
Try to add fragment like this in service configuration file:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Access-Control-Allow-Origin: $http_origin";
But it can be a problem with CORS. In such case you should add the following line:
--cors-allowed-origins=["http://*"]
to /etc/default/kube-apiserver or /etc/kubernetes/manifests/kube-apiserver.yaml file (depending on the location your kube-apiserver configuration file).
After that restart kube-apiserver.
See also this similar question.
So, it turns out that the whole Kubernetes and Nginx config was correct, so the solution was implementing the usage of the saved cookie on client side when invoking a CORS request to the second service.
Essentially, this was already answered here: Set cookies for cross origin requests
Excerpt from the answer:
Front-end (client): Set the XMLHttpRequest.withCredentials flag to
true, this can be achieved in different ways depending on the
request-response library used:
jQuery 1.5.1 xhrFields: {withCredentials: true}
ES6 fetch() credentials: 'include'
axios: withCredentials: true

Route incoming traffic with ingress master/minion

Greetings fellow humans,
i am trying to route all traffic incoming to my cluster with the following annotation:
nginx.ingress.kubernetes.io/auth-url: http://my-auth-service/
I followed the tutorials and i still have not achieved to route every request to my auth module. I am following a strategy of master-minion. When I check the constructed nginx file the annotation is not found.
I tried as well something like this in one of my minon ingress files
auth_request /auth;
auth_request_set $auth_service $upstream_http_auth_service;
proxy_pass $request_uri
proxy_set_header X-foo-Token $auth_service;
I am using the following ingress controller version
Image: nginx/nginx-ingress:1.8.1
Ports: 80/TCP, 443/TCP, 9113/TCP, 8081/TCP
Host Ports: 0/TCP, 0/TCP, 0/TCP, 0/TCP
Samples:
Master ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: master-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.org/mergeable-ingress-type: "master"
kubernetes.io/ingress.global-static-ip-name: <cluster-ip>
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/auth-url: http://my-auth-service/
spec:
tls:
- hosts:
- app.myurl.com
secretName: secret-tls
rules:
- host: app.myurl.com
Minion ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: pod-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.org/mergeable-ingress-type: "minion"
# nginx.ingress.kubernetes.io/auth-url: http://my-auth-service/
# nginx.ingress.kubernetes.io/auth-snippet: |
# auth_request /new-auth-service;
# auth_request_set $new_auth_service $upstream_http_new_auth_service;
# proxy_pass $request_uri
# proxy_set_header X-foo-Token $new_auth_service;
nginx.org/rewrites: "serviceName={{ .Values.serviceName }} rewrite=/"
spec:
rules:
- host: {{ .Values.clusterHost }}
http:
paths:
- path: /{{ .Values.serviceName }}/
backend:
serviceName: {{ .Values.serviceName }}
servicePort: 80
so i was able to make it work. First of all, the urls provided by matt-j helped be a lot to figure out a solution.
Turns out that i was using nginx-stable for my ingress controller, as in the documentation here suggested, i needed to use the new ingress controller version. i followed the instructions for a full reset, since i am working on my staging env. (for production i might go with a 0 downtime approach). Once installed, I ran into an known issue which is related to the webhooks, similar error can be seen here. Basically one solution for overcoming this error is to delete the validatingwebhookconfigurations. Finally I applied the ingress config and made some adjustments to use the proper annotations, which made the magic.
NOTE: I ran into an issue regarding of how forwarding the auth request to my internal cluster service, to fix that i am using the FQDN of kubernetes pod.
NOTE 2: I removed the concept of master minion, since they the merging in kubernetes/ingress-nginx happens automatically more info here
Here are the fixed samples:
MAIN INGRESS
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: master-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/ingress.global-static-ip-name: <PUBLIC IP>
spec:
rules:
- host: domain.com
CHILD INGRESS
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ .Values.serviceName }}-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/auth-url: http://<SERVICE NAME>.<NAMESPACE>.svc.cluster.local # using internal FQDN
spec:
rules:
- host: {{ .Values.clusterHost }}
http:
paths:
- path: /{{ .Values.serviceName }}(/|$)(.*)
backend:
serviceName: {{ .Values.serviceName }}
servicePort: 80

Traefik 2.2 http to https redirect

I'm following the guide and I'm able to access my website via HTTP and HTTPs however redirect is not working for me, any ideas on what might be wrong?
# IngresRoute
---
kind: IngressRoute
apiVersion: traefik.containo.us/v1alpha1
metadata:
name: whoami
namespace: default
spec:
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: :443
routes:
- match: Host(`hello.mydomain.io`)
kind: Rule
services:
- name: whoami
port: 80
tls: {}
I use Docker compose, so might not be spot on for you. But suggestion is to add a scheme redirect middleware to your dynamic config file.
http:
middlewares:
https_redirect:
redirectScheme:
scheme: https
permanent: true
Or just add the middleware to your service if you don't have access to the Traefik configs.
I prefer the dynamic config, because then you can register it on any service as required using https_redirect#file.
You do need a router per entrypoint though, using this method. And register the middleware on only the http router.
I'm sure there are other, better ways. But if you need some apps automatically redirecting and some not this is the best solution I've found thusfar.
I have a working configuration which uses Ingress objects instead of IngressRoute , but I hope this will help some people :
Thus, here is a working configuration :
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect
namespace: some_namespace
spec:
redirectScheme:
scheme: https
permanent: true
and
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wordpress
namespace: your_app_namespace
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.middlewares: some_namespace-redirect#kubernetescrd
spec:
tls:
- secretName: your_certificate
hosts:
- www.your_website.com
rules:
- host: www.your_website.com
http:
paths:
- path: /
backend:
service:
name: your_service
port:
number: 80
pathType: ImplementationSpecific
So the trick is to :
define a Middleware object (in any namespace you want, but that may be in the same one as your app)
reference it in traefik.ingress.kubernetes.io/router.middlewares with the syntax <NAMESPACE>-<NAME>#kubernetescrd (where NAMESPACE and NAME are those of the Middleware object)

how to config traefik 2.2 forward url and remove keywords

I want to forward my request using treafik 2.2 and config my ingress like this:
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: soa-illidan-forward
namespace: dabai-pro
selfLink: /apis/extensions/v1beta1/namespaces/dabai-pro/ingresses/soa-illidan-forward
uid: b0778435-4fff-4e78-b85f-a534833b73e0
resourceVersion: '322554'
generation: 1
creationTimestamp: '2020-06-07T11:04:43Z'
spec:
rules:
- host: manage.example.net
http:
paths:
- path: /service
backend:
serviceName: zuul-service
servicePort: 8088
status:
loadBalancer: {}
but the forward still using the key word service and forward to backend, how to remove the keywards service when forward request? I also tried this:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: pro-manage-route
namespace: dabai-pro
spec:
entryPoints:
- web
routes:
- match: Host(`manage.example.net`)
kind: Rule
services:
- name: be-illidan-frontend
port: 80
- match: Host(`manage.example.net`) && PathPrefix(`/service`)
kind: Rule
services:
- name: zuul-service
port: 8088
but still not work. and this is my request path:
https://manage.example.net/service/illidan/report/user/captcha
and I want forward to backend zuul-service's url is /illidan/report/user/captcha. not /service/illidan/report/user/captcha.
just using traefik StripPrefix middleware, for example:
http:
middlewares:
test-stripprefix:
stripPrefix:
prefixes:
- "/foobar"
- "/fiibar"
for more detail, read the traefik docs.