Kubernetes Google OAuth2 Sign In - kubernetes

I'm trying to figure this out for a while and can't seem to find an answer anywhere. Maybe someone here will have an idea.
I have deployed an application on Kubernetes Cluster (in GCP). The Application is pretty much a micro-service type of app under a single domain. What I'm trying to achieve at the moment is to have a domain-wide-authentication via Google and OAuth2 protocol.
So I have a main app under the main domain https://example.com and pretty much every single path under that domain will be a separate K8s Service + Deployment. So it's a different set of containers for https://example.com/foo and different for https://example.com/bar and obviously different set of containers for the main https://example.com. I don't want to "connect" each individual App to Google due to two reasons:
Would require for me that each app has the OAuth2 Protocol implemented, and
A token granted by one app would be invalid for the other one, so it would require the user to log in each time he/she changes the URL, kind bad UX if you ask me
So, I'm trying to set up in the Kubernetes Cluster an Nginx Ingress Controller that would facilitate authentication and validate all incoming requests before they would reach any of the backend apps. This is where the problem lies...
I've managed to set up OAuth2 Proxy in my Nginx Ingress Controller and the user can log in. The whole OAuth2 Flow works. HOWEVER, the user is not forced to log in. The user can navigate to the https://example.com but he/she won't be required to have an Authentication cookie granted after successful login via Google.
Here is my YAML config for Ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/force-ssl-redirect: "true"
name: example-com-ingress
namespace: default
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
rules:
- host: example.com
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: http-proxy
path: /oauth2
- backend:
serviceName: example-com-nginx-service
servicePort: 80
path: /
Any ideas anyone?

Make sure that while configuring oauth2 proxy you set your cookie domain (set --cookie-domain=example.com to allow the cookie to be read).
You have to also add the whitelist-domain feature while configuring oauth2 proxy:
--whitelist-domain=example.com
Then have to create ingress' obects:
1. Expose endpoint /oauth2, look at the example below:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: oauth2-proxy
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: 4180
path: /oauth2
tls:
- hosts:
- example.com
secretName: example-com-tls
2. Then create ingress for your application:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-com-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
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/force-ssl-redirect: "true
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
tls:
- hosts:
- example.com
secretName: example-com-tls
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: example-com-nginx-service
servicePort: 80
It is clearly to create two separate ingresses, but you can also create just one with two defined backends as you wanted.
Take a look here: nginx-ingress-controller-oauth2, oauth2-dynamic-callbacks, oauth2-proxy.
Once again make sure that you have follow this instruction: external-OAUTH-authentication.

Related

How to ByPass Traffic directly to Backend from K8S NGINX Ingress Controller

OAUTH2 is used for authentication and the OAUTH2 proxy is deployed in Kubernetes. When a request is received by the NGINX Ingress controller, it always routes the traffic to OAUTH proxy. The requirement is when the request contains a specific header (For example: abc) then those requests should be routed directly to the backend. Those shouldn't be routed to OAUTH proxy. Can this be done using some sort of an annotation in NGINX Ingress controller? Can we by pass those traffic going to OAUTH2?
You may want to have a look at https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary
Let's say you have a normal Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-backend
spec:
ingressClassName: nginx
rules:
- host: XXX
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 80
Set the header name and value for your desired backend on a second Ingress, with canary enabled.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-backend-header
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: sample-header
nginx.ingress.kubernetes.io/canary-by-header-value: abc
spec:
ingressClassName: nginx
rules:
- host: XXX
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-with-header
port:
number: 80
Now, every request with sample-header: abc routes to the second ingress/service. Any other value, e. g. sample-header: test, will route to the first ingress/service.

Traefik - Middleware redirectRegex doesn't work

I have a simple website running in my Kubernetes cluster and exposed to the Internet using Traefik. My Ingress object looks like this (the only things I've changed here are the name and domain names):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging
kubernetes.io/ingress.class: traefik
name: my-cool-website
namespace: default
spec:
rules:
- host: my-cool-website.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-cool-website
port:
number: 80
- host: www.my-cool-website.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-cool-website
port:
number: 80
tls:
- hosts:
- my-cool-website.com
- www.my-cool-website.com
secretName: my-cool-website-tls
This works. It allows me to access the site either from my-cool-website.com or from www.my-cool-website.com. But what I'd like to have happen is that if someone visits the former, that Traefik automatically redirects them to the latter. I found a couple of guides online that recommended creating a Traefik middleware, so I did just that, but unfortunately it doesn't work as intended. Here is my middleware definition:
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: my-cool-website-force-www
spec:
redirectRegex:
regex: ^https?://my-cool-website.com/(.*)
replacement: https://www.my-cool-website.com/${1}
And then I add the following annotation back to the ingress object:
traefik.ingress.kubernetes.io/router.middlewares: my-cool-website-force-www
But as soon as I do that, it breaks my web app. By that I mean, when that annotation is applied, instead of serving my website, I start seeing a generic nginx page that looks like this when I try to access the domain (and also it does not do the redirect):
I have to assume this Hello World page is being served by Traefik as some sort of generic default page, as it definitely does not originate from my pod. So that tells me something about this middleware (or perhaps how I'm calling it with the annotation) isn't working. What am I missing?
I figured it out, by port-forwarding to the Traefik Dashboard and looking at the service there. It was showing an error for the middleware not found. I then clicked over to the middlewares and realized that they end up with a longer canonical name. So in my annotation I had to change the reference from my-cool-website-force-www to default-my-cool-website-force-www#kubernetescrd and then everything worked.

how to setup yaml ingress in google cloud with redirect

I’m setting up an environment in Google Cloud with an ingress and load balancers.
I know how to setup hosts and paths to it but I can't figure out how to setup when a user goes to a specific site http://example.com/ I want him to redirect to http://example.com/en.
Note:
http => https
/ => /en
UPDATED
I added app-root: /en (but it doesn't do anything).
This is my current yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: gce
kubernetes.io/ingress.global-static-ip-name: our-frontend-static-ip
networking.gke.io/managed-certificates: example-certificate
appgw.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/app-root: /en
name: example-ingress
namespace: default
spec:
rules:
- host: anotherexample.com
http:
paths:
- backend:
serviceName: anotherexample-service
servicePort: 80
- host: example.com
http:
paths:
- path: /nl
backend:
serviceName: example-nl-service
servicePort: 80
- path: /en
backend:
serviceName: example-en-service
servicePort: 80
So, there are 2 hosts in my yaml and I want: when the url is correct for 1 of the hosts: example.com it must go to example.com/en (this is for Multilanguage purposes)
We can change the settings in the loadbalancer ban after the sync from the ingress in changes it back.
Kubernetes supports multiple Ingress Controllers which are different from each other. For example, you are trying to use the Ingress GCE and there is also a popular Nginx Ingress.
The main problem in your use case is that the Ingress GCE is not supporting rewrites. An on-going feature request regarding that can be found here.
To be able to use the rewrites you will need to deploy the Nginx Ingress Controller and switch annotation in your yaml from:
kubernetes.io/ingress.class: "gce"
to:
kubernetes.io/ingress.class: "nginx"
The sources that will help you out with this are as follows:
Installation Guide
Rewrite
An example

Kubernetes fanout ingress but with the root domain serving the client

I'm having trouble getting my client container talking to the API container, I was hoping to use a fanout ingress as so:
foo.bar.com/api - routes to API container
foo.bar.com - routes to client container
My setup does render the client no problem, but all calls to the API result in 404s - so it's obviously not working. I think the 404 behaviour is a red herring, it's probably looking for Angular routes that match /api and can't find any, I don't think the routing is even happening. My Ingress yaml is below, I can share any other parts of the config if needed. Any pointers much appreciated!
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: foo-bar
name: foo-bar-ingress
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
tls:
- hosts:
- foo.bar.com
secretName: tls-secret-prod
rules:
- host: foo-bar.com
http:
paths:
- backend:
serviceName: server
servicePort: 3000
path: /api
- backend:
serviceName: client
servicePort: 80
path: /
As suggested by #HelloWorld in the comments, checking the api server routes revealed the issue to be misconfigured routing in the server not the ingress rules.

Wildcard SSL certificate with subdomain redirect in Kubernetes

I've configured my Kubernetes to use one wildcard SSL certificate to all my apps using cert-manager and letsencrypt, now the problem is that I can't configure subdomain redirects cause Ingress is kinda "stiff". Here's how I'm trying to achieve this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-wildcard-ingress
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
certmanager.k8s.io/acme-challenge-type: dns01
certmanager.k8s.io/acme-dns01-provider: azuredns
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: "domain.com"
http:
paths:
- path: /
backend:
serviceName: some-service
servicePort: 3000
- host: somesub.domain.com
http:
paths:
- path: /
backend:
serviceName: some-other-service
servicePort: 80
- host: othersub.domain.com
http:
paths:
- path: /
backend:
serviceName: one-more-service
servicePort: 8080
- host: "*.domain.com"
http:
paths:
- path: /
backend:
serviceName: default-service-to-all-other-non-mapped-subdomains
servicePort: 8000
tls:
- secretName: domain-com-tls
hosts:
- "*.domain.com.br"
The problem is that Ingress ignores the declared subdomain redirects just because they're not listed in the "tls:hosts" section. And if I do put them there, it tries to issue the SSL certificate using the wildcard and the other subdomains as well in the same cert, which causes the issuer to refuse the order, saying the obvious: "subdomain.domain.com and *.domain.com are redundant"
Is there any other way that I can declare those redirects and force them to use my SSL wildcard certificate?
Well, for anyone who's having this kind of trouble, I've managed to solve it (not the best solution, but it's a start). For this, I'll be using cert-manager and letsencrypt.
First, I've created a ClusterIssuer to issue for my certs with letsencrypt:
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-dns
spec:
acme:
dns01:
providers:
- azuredns:
clientID: MY_AZURE_CLIENT_ID
clientSecretSecretRef:
key: client-secret
name: azure-secret
hostedZoneName: mydomain.com
resourceGroupName: MY_AZURE_RESOURCE_GROUP_NAME
subscriptionID: MY_AZURE_SUBSCRIPTION_ID
tenantID: MY_AZURE_TENANT_ID
name: azuredns
email: somemail#mydomain.com
privateKeySecretRef:
key: ""
name: letsencrypt-prod-dns
server: https://acme-v02.api.letsencrypt.org/directory
Then I've created a fallback ingress to all my subdomains (this one will be the cert generator):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
certmanager.k8s.io/acme-challenge-type: dns01
certmanager.k8s.io/acme-dns01-provider: azuredns
certmanager.k8s.io/cluster-issuer: letsencrypt-prod-dns
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
name: wildcard-ingress
namespace: some-namespace
spec:
rules:
- host: '*.mydomain.com'
http:
paths:
- backend:
serviceName: some-default-service
servicePort: 80
path: /
tls:
- hosts:
- '*.mydomain.com'
- mydomain.com
secretName: wildcard-mydomain-com-tls
Notice that I've declared at the TLS section the wildcard AND the absolute paths, so the cert will be valid for the URLs without subdomains too.
At this point, any requests to your domain, will be redirected to "some-default-service" with SSL(cert-manager will issue for a new cert as soon as you create the fallback ingress. This can take a while once cert-manager dns01 issuer is not mature yet), great!!!
But, what if you need to redirect some specific subdomain to another service? No problem (since they're running on the same namespace), all you have to do is to create a new ingress to your subdomain, pointing it to your existing wildcard-mydomain-com-tls cert secret:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/force-ssl-redirect: "false"
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
name: somesubdomain-ingress
namespace: some-namespace
spec:
rules:
- host: somesubdomain.mydomain.com
http:
paths:
- backend:
serviceName: some-other-service
servicePort: 8080
path: /
tls:
- hosts:
- somesubdomain.mydomain.com
secretName: wildcard-mydomain-com-tls
Easy peasy lemon squeezy!!! Now your somesubdomain.mydomain.com overrides your fallback rule and sends the user to another app. The only thing you should notice here is that the secret is valid only for "some-namespace" namespace, if you need to use this cert in another namespace, you could:
Copy the secret from namespace "some-namespace" to "other-namespace". If you do this, remember that cert-manager will NOT renew this cert automatically for "other-namespace", so, you'd have to copy the secret again, every time your cert expires.
Recreate the fallback ingress to every namespace you have, so you'd have a new cert for each of them. This approach is more ingress verbose, but, it's fully automatic.
I guess that's it. Hope someone out there can benefit from this info.
Cheers
So the best course of action here is probably to just not use ingress-shim to manage your Certificate resource.
Instead, you can manually create a Certificate resource and then reference the secret it produces in all of your ingresses.
We are exploring options to workaround this limitation in ingresses at the moment, however there has so far not been any progress!