Openshift 3.11 header based routing - haproxy

I'm trying to implement a header based routing on Openshift 3.11.
I mean, I want HAProxy to route requests to a certain service based on header presence and value rather than hostname. The header value would be set in the route configuration.
I know this is possible with HAProxy, but I don't know how to do this.
I followed a piece of advice I found here but it seems the configuration has changed and it doesn't work anymore.
Any suggestion would be welcome. I have an alternative, which would be to put a 2nd proxy that would do the work, but this would not be elegant at all...

OK, I managed to make it work properly. But it wasn't the documentation that helped.
The piece of code showed in the link I posted in the question is to put under the following configuration parts :
frontend public (http proxy)
frontend fe_sni (https proxy with custom certificates)
frontend fe_no_sni (https proxy with default certificate)
Also, the piece of code was old and didn't contain the actual variable names.
Here is one that, for every route:
looks for a route annotation named haproxy.router.openshift.io/tenant-id
create 2 acls checking for the value of a cookie named tenant-id and if the host is the expected one (the host value is configurable with the route annotation haproxy.router.openshift.io/tenant-hostname
checks if the 2 acls return true and if so makes the http request to the service behind the route
# Custom snippet for balancing through HTTP headers
{{- range $cfgIdx, $cfg := .State }}
{{- if (ne (index $cfg.Annotations "haproxy.router.openshift.io/tenant-id") "") }}
acl custom_header_{{index $cfg.Annotations "haproxy.router.openshift.io/tenant-id"}} cook(tenant-id) {{index $cfg.Annotations "haproxy.router.openshift.io/tenant-id"}}
acl configured_host_{{index $cfg.Annotations "haproxy.router.openshift.io/tenant-id"}} hdr(host) {{index $cfg.Annotations "haproxy.router.openshift.io/tenant-hostname"}}
use_backend be_edge_http:{{$cfgIdx}} if configured_host_{{index $cfg.Annotations "haproxy.router.openshift.io/tenant-id"}} custom_header_{{index $cfg.Annotations "haproxy.router.openshift.io/tenant-id"}}
{{- end }}
{{- end }}

Related

frappe.get_url return http:// but not https://

I am using frappe v14, however, when I use frappe.get_url in jinja2, it return me http://xxxx, but not https://xxxxx, may I know if I miss any setup. I am using https://xxxx for visiting
You may have setup ssl manually (not through bench) for your site. You can add a rule in your NGINX config to auto upgrade requests (if you have https setup).
Another way is to debug get_url and figure out which key is missing to be set in the site_config so that Frappe can handle the rest for you.
ref: Adding a redirect rule in NGINX

Ingress session-cookie-path setting regular express in Ingress Session Cookie; resulting in user logout

I have created an ingress controller configuration with following path definitions:
paths:
- path: (USA)/my-app/(.*)$
...............
- path: (UK)/my-app/(.*)$
The problem happening here is when I don't set the following annotation;
nginx.ingress.kubernetes.io/session-cookie-path
I get regular expression in INGRESSCOOKIE path as:
cookie-name: INGRESSCOOKIE --------cookie-path: /(USA)/my-app/(.*)$
This is coming from the given path i.e. /(USA)/my-app/(.*)$.
As a result this response cookie from Ingress doesn't go back to Ingress for any subsequent request for http://USA/my-app/?id=1. (as HTTP request path differs from path in INGRESSCOOKIE)
And because of this HTTP request at times hit a different upstream server and user logs out; as session id in request is generated by a different server managed through the same load balancer.
I then tried setting annotation as:
nginx.ingress.kubernetes.io/session-cookie-path= /$1/my-app
But $1 doesn't actually resolve here; probably we cant give expressions in session-cookie-path.
Is there anything I am not doing in a right way here? Or, I should try something else to achieve session affinity.
Thanks
I know this is pretty old but wanted to share my view anyway.
For your issue, you might want to try the following annotation: nginx.ingress.kubernetes.io/use-regex
Please remove "session-cookie-path" from annotations as Session Cookie Paths doesn't support regex
For more information, please visit below links:
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#use-regex
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#cookie-affinity

How can I fetch request URI in ingress configuration-snippet?

I want to read the request URI(excluding hostname and request params) and forward it in a custom header to an upstream server. I have been through several blogs where they have mentioned to use $request_uri but its not working.
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header RequestURI $request_uri
May I know which language is used to write scripts in annotation snippets? And is there is any list of variables which are by-default provided by ingress controller that we can use inside annotations?
Thanks
which language is used to write scripts in annotation snippets?
There are no special language, the format is the Nginx configuration format.
Everything you put there will be added to a location section related to your Ingress route in an Nginx configuration generated by Ingress controller.
is there is any list of variables which are by-default provided by ingress controller that we can use inside annotations?
Here is a list of embedded Nginx variables.

Traefik redirect from one host to another

We decided to move from the subdomain structure to one root domain with path prefixes, but we got many old URLs on the internet. So is there any way to add a redirect from the old URL to the new one?
For example,
We got subdomain test.example.com switched to example.com/test, I can access correctly site with the string in docker-swarm YAML file
traefik.frontend.rule: Host:example.com;PathPrefixStrip:/test
but when I'm trying to add to Traefik config redirects like:
[http.middlewares]
[http.middlewares.test-redirectregex.redirectRegex]
regex = "^https://(*).example.com/)"
replacement = "^https://example.com/${1}"
Traefik says that it doesn't know where to forward this request
If I'm trying to add:
traefik.frontend.rule: Host:test.example.com,example.com;PathPrefixStrip:/test
Traefik adds a prefix to both hosts. Is there any way to resolve this without adding a second reverse proxy?
Assuming that you are using Traefik 2.1, you can use the below middleware for Traefik
[http.middlewares]
[http.middlewares.blog-redirect.redirectRegex]
regex = "^(https?://)(.*).example.com/(.*)$"
replacement = "${1}example.com/${2}/${3}"
permanent = true
The important step to activate the above middleware is to add the below label on the corresponding router and service. For instance, if you a a blog service and you defined a blog router for it, then you need to add the below table to the services
traefik.http.routers.blog.middlewares=blog-redirect
In addition, your route rule should look like the below rule to be able to handle both domains (or you define multiple routes per service)
- traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/test`) || Host(`api.example.com``)
in this post, you can find more info about traffic and redirection

kubernetes ingress controller not forwarding request headers

I am working on a kubernetes cluster and problem faced is:
From UI/browser, I can see it is sending a request header called "request_id" please refer to image:
But while checking on backend it is unavailable. While searching through internet, I could see that people are talking about adding following entry to Ingress object:
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header request_id "$req_id";
But it is generating a new value for this and not passing value submitted by browser.
Any ideas, what might be missing here?
If you want to pass a custom header to your backend, you need to use this kind of annotation:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Request-Id: $request_id
In your configuration you are using the variable $req_id, but you need to pass the variable sent by UI/browser.
Basically, ingress-nginx-controller drops any request headers that contains "_" in them. You can find various threads which discuss this issue like,
Why HTTP servers forbid underscores in HTTP header names
So, I just enabled ingress controller to pass such request headers. This can be done by adding following entry to configmap "nginx-configuration"
data:
enable-underscores-in-headers: "true"
IMO, this is a much clean solution as there could be many applications that might use "_" in request headers.