Request Header based routing (User Agent) using Ingress in Kubernetes - kubernetes

I am using DB less kong as gateway in kubernetes and the use case i have is to redirect traffic from browser to URL where they can download Electron app and if the traffic is from Electron app it redirects to the front end.
I am using ingress for routing.
Can anyone share an example of how to do it?

You can try to redirect if "user agent" contains the desired "agent" name.
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt-issuer
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
nginx.ingress.kubernetes.io/server-snippet: |
if ($http_user_agent ~* "(Electron)" ) {
rewrite / https://frontendapp.example.com permanent;
}
hosts:
- host: test.exmaple.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: test-tls
hosts:
- test.example.com
This will redirect the call if the user agent contain Electron, otherwise serve the default response, and redirect to https://frontendapp.example.com

Related

How to fix Ingress service not returning any headers?

Context: I have deployed an application on GKE (Google Kubernetes Engine). The application uses an Ingress service as a load balancer and provides external access to the application (API gateway).
Problem: When I try to call the API (the application on GKE) from a React frontend, it keeps returning a CORS error. The full error message is: "Access to XMLHttpRequest at 'http://xx.xxx.xxx.xx/api/auth/accounts/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
My Ingress yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-service
annotations:
nginx.ingress.kubernetes.io/default-backend: ingress-nginx-controller
kubernetes.io/ingress.class: nginx
## tells ingress to check for regex in the config file
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
add_header Access-Control-Allow-Credentials true;
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
# kubernetes.io/ingress.class: nginx
# nginx.ingress.kubernetes.io/enable-cors: "true"
# nginx.ingress.kubernetes.io/cors-expose-headers: "*, Access-Control-Allow-Origin"
spec:
rules:
- host: acme.com
http:
paths:
- pathType: Prefix
path: /api/discussion
backend:
service:
name: fplms-discussionservice-clusterip
port:
number: 7218
- pathType: Prefix
path: /api/auth
backend:
service:
name: fplms-authservice-clusterip
port:
number: 7209
- pathType: Prefix
path: /api/management
backend:
service:
name: fplms-managementservice-clusterip
port:
number: 8083
I have tried every solution I could find, but nothing seems to work, the response never returns with any header.

Kubernetes nginx ingress: Server-side HTTPS enforcement through redirect

I've setup my ingress-controller in aws EKS. I've added cert-manager.io/cluster-issuer: "letsencrypt-staging" for my ingress. The problem is every time the backend sends 307 redirect in http. The ingress controller sends same http to frontend, causing Mixed Block error from the browser.
Here is my sample ingress:
kind: Ingress
metadata:
name: example-nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-staging"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- kube.example.com
secretName: kube-tls
rules:
- host: kube.example.com
http:
paths:
- pathType: Prefix
path: /api/v1/
backend:
service:
name: service-nodeport
port:
number: 8000
According to the documentation, it should have redirect to https by default (link). Is it different for 307 redirect?
Additional Details:
Installing nginx ingress controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.2/deploy/static/provider/aws/deploy.yaml
Installing cert-manager
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.16.1/cert-manager.yaml
setting up clusterissuers and certificate issuing is done as per the documentation
Describe Ingress
Name: example-nginx-ingress
Namespace: dev
Address: a629a[MASKED]-a2f82eec00a54190.elb.ap-south-1.amazonaws.com
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
TLS:
kube-tls terminates kube.example.com
Rules:
Host Path Backends
---- ---- --------
kube.example.com
/api/v1/ svc-nodeport:8000 (192.168.7.44:8001)
/ webapp-nodeport:80 (192.168.4.90:80)
Annotations: cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
Events: <none>
Deployment and service are setup as basic
svc-nodeport is backed by gunicorn (i.e. a python webserver) container and webapp-nodeport is backed by nginx container.
Alternative way I thought
I tried to add location snippet in my ingress, to actually remove the trailing slash (/) from request. But It didn't worked. You can help me on this too.
metadata:
annotations:
nginx.ingress.kubernetes.io/location-snippet: |
location = /api/v1/ {
rewrite api/v1/$1 ^api/v1/(.*)/$ break;
}
It could be the HTTP Strict Transport Security. Try set hsts to false.

ingress rewrite domain www to non-www url

I am trying to redirect my domain 'www.test.example.com' to test.example.com
in ingress i have added annotation
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'www.test.wotnot.io' ) {
rewrite ^/(.*)$ https://app.test.wotnot.io/$1 permanent;
}
it's not working as expected.
For testing i have try this
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'test.example.com' ) {
rewrite ^/(.*)$ https://google.com/$1 permanent;
}
which is working fine.
My site is working on test.example.com and ssl certificate.
Whole ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
certmanager.k8s.io/cluster-issuer: wordpress-staging
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
#nginx.ingress.kubernetes.io/configuration-snippet: |
#if ($host = 'www.test.wotnot.io' ) {
# rewrite ^/(.*)$ https://test.example.io/$1 permanent;
#}
name: wordpress-staging-ingress
spec:
rules:
- host: test.example.io
http:
paths:
- backend:
serviceName: wordpress-site
servicePort: 80
path: /
tls:
- hosts:
- test.example.io
secretName: wordpress-staging
Ingress has an annotation nginx.ingress.kubernetes.io/from-to-www-redirect: "true" which already handle this:
In some scenarios is required to redirect from www.domain.com to
domain.com or vice versa. To enable this feature use the annotation
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
Attention: For HTTPS to HTTPS redirects is mandatory the SSL Certificate defined in the Secret, located in the TLS section of Ingress, contains both FQDN in the common name of the certificate.
It's better that you use it instead of fighting/tweaking the configuration-snippet annotation.

How do I redirect a www url to a no-www url using nginx-ingress-controller?

I am trying to get the url www.example.com to redirect itself to example.com while preserving everything about the original request in k8s 1.11.1
I am attempting to do this using a simple Ingress, and am then using annotations to redirect it.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/permanent-redirect: https://example.com
nginx.ingress.kubernetes.io/ssl-redirect: "True"
name: example-redirect
spec:
tls:
- hosts:
- www.example.com
secretName: example-tls
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example
servicePort: http
The issue here is that I don't want to have any rules/backend. I simply want to redirect www.example.com to example.com using an Ingress, but k8s Ingresses require me to have rules. Are there any workarounds here?
Actually, Ingress resource has strongly defined prerequisites for the relevant API specification. You may exclude rules: field from the general configuration, however backend: should be definitely specified, in the way that Nginx Ingress controller could route network traffic to the target endpoint in case no rules declared or matched.
Whenever you create any specific settings for Nginx Ingress controller either via Annotations or ConfigMaps, both of the options doing the same job of applying some specific configuration to the underlying nginx.conf file which resides on nginx-ingress-controller Pod. It means that Ingress controller applies server {} and location {} blocks into the corresponded Nginx web server Pod for particular host:
server {
server_name www.example.com ;
listen 80;
listen [::]:80;
set $proxy_upstream_name "-";
listen 443 ssl http2;
listen [::]:443 ssl http2;
.............
location / {
set $namespace "default";
set $ingress_name "example-redirect";
set $service_name "example";
set $service_port "http";
set $location_path "/";
......................
}
}
Therefore, I suppose that you can capture nginx.conf file, based on Ingress resource configuration and then apply it independently inside Ingress controller Pod.
I assume that you may consider also to use nginx.ingress.kubernetes.io/from-to-www-redirect: "true" annotation in order to achieve the goal in current scenario.
Following should do:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'www.example.com' ) {
rewrite ^ https://example.com$request_uri permanent;
}
name: example-redirect
spec:
tls:
- hosts:
- www.example.com
secretName: example-tls
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example
servicePort: http

Kubernetes NGINX Ingress configmap 301 redirect

Using an NGINX Ingresss in Kubernetes, I can't see a way to forward my traffic from non-www to www, or to another domain etc on a per-host basis
I've tried looking in configmap docs but can't see what I need. Maybe it can go in the ingress itself?
I've also seen an example using annotations but this seems to be ingress-wide, so I couldn't have specific redirects per host
Indeed a redirect is possible with a simple annotation:
nginx.ingress.kubernetes.io/permanent-redirect: https://www.gothereinstead.com
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
But as you mentioned, it's "Ingress" wide and not configurable per host, per domain or even per path. So you'll have to do it yourself through the ingress.kubernetes.io/configuration-snippet annotation, which gives you a great deal of power thanks to regular expressions:
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: self-made-redirect
annotations:
ingress.kubernetes.io/configuration-snippet: |
if ($host = 'blog.yourdomain.com') {
return 301 https://yournewblogurl.com;
}
if ($host ~ ^(.+)\.yourdomain\.com$) {
return 301 https://$1.anotherdomain.com$request_uri;
}
spec:
rules:
- host: ...
If you are not quite used to NGINX, you'll know more about what's possible in the snippet, particularly what is the $host variable right in the NGINX documentation.
To redirect all traffic regardless of using HTTP or HTTPS from example.com and www.example.com to newdomain.example.com I ended up with the following solution.
In this example I'm also using cert-manager.io to request the certs for www.example.com and example.com.
The redirect is done using the annotation nginx.ingress.kubernetes.io/permanent-redirect
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: redirect-example-to-newdomain
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/permanent-redirect: https://newdomain.example.com
spec:
tls:
- hosts:
- example.com
- www.example.com
secretName: example.com-tls
rules:
- host: example.com
- host: www.example.com
I have problem with annotations server-snippet. When the certificate is renewed, the process crashes. When I remove annotations, renewed certificate is successful. Is there another solution? For example, creating a redirect 301 in separate pod?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
ingress.kubernetes.io/ssl-redirect: "true"
meta.helm.sh/release-name: DOMAIN
meta.helm.sh/release-namespace: DOMAIN
nginx.ingress.kubernetes.io/configuration-snippet: |
location ~ ^/online-web {
return 301 /online;
}
if ($host = 'DOMAIN-alias.cz') {
return 301 https://DOMAIN.cz;
}
if ($host ~ ^(.+)\.DOMAIN-alias\.cz$) {
return 301 https://$1.DOMAIN.cz$request_uri;
}
if ($host = 'DOMAIN-alias-2.cz') {
return 301 https://DOMAIN.cz;
}
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
nginx.ingress.kubernetes.io/server-snippet: |
if ($host ~ "csas.woltair.cz") {
return 301 https://woltair.cz/zakaznik/doporuceni;
}
............
............
- host: csas.woltair.cz
http:
paths:
- backend:
service:
name: woltair-cz-fe
port:
number: 8080
path: /zakaznik/doporuceni
pathType: ImplementationSpecific