Extracting params from the Referer Header field in HAProxy - haproxy

I understand that I can use url_param / urlp to extract the query parameters from the URL that is requested, in HAProxy.
However, I need similar function for extracting parameters from the URL sent as HTTP Header field Referer. I guess url_param is only available for the requested URL, and not possible to use for HTTP Header values? If so, what other options do I have? I need to retrieve the value from query parameter and send it as specific HTTP Header to the backend server.

Sharing my solution (although Im not sure this is the most efficient and accurate way). I solved it with Regex.
# Example HTTP Referer: http://myexample.com/users?user-id=12345
# ACL
acl is_uid_in_hdr_referer hdr_sub(Referer) -i user-id
# Set value from query param "user-id" from Referer header to custom header "user-id"
http-request set-header user-id %[req.hdr(Referer),regsub(.+?user-id=,,g)] if is_uid_in_hdr_referer

Related

Istio - Dynamic request routing based on header-values

Dynamic request routing based on header-values
For our QA environment we need to configure a special kind of routing for the incoming (Ingress), but also for the outgoing (Egress) requests. So for outgoing requests the rule should evaluate a header value with a regex and capture a value from the header and build with that value the URL where the request should be redirected. The value in the header is dynamically changed, so the redirect URL can not be hardcoded.
For example if the outgoing requests goes to services-master.anydomain.com, but there's a header value forwarded-for-feature with the value verbu-1234 the request should be redirected services-verbu-1234.anydomain.com.
For incoming requests it's a similar condition. If the origin points to webapp-verbu-1234.anydomain.com, but the request goes to services-master.anydomain.com the regex should extract verbu-1234 from the origin domain and replace master in the URL with the extracted value.
I know, that it's possible to use a regex to match header values, but I'm not sure, if it's possible to use captured values from a match to influence the target URL, at least I couldn't find that in the documentation.
I don't think this is possible
But if your QA system knows the features available, and you need to do that in Istio, you might try creating a VirtualService for each feature. And multiple VirtualServices would be merged by Istio...

AWS Api Gateway Setting the header value to a default value using http Integration

I am using AWS API Gateway and I want to set my Integration type to http. I have the integrated url as https:// xxxxxx.com which takes a header "apikey". I am not expecting the end user to pass the header rather I want to set the apikey to some constant value.
I see that there is a way to force the user to make him pass the header(by making header required under the Method Request section. However, I want to set it to default.
For example in all the requests which are internally calling the URL inside the API gateway should pass the header value as "12345".
You can add/remove/override headers with an Integration Request Mapping Template.
In the API Gateway console, chose the relevant api/resourece/method. Go to Integration Request > Mapping Templates and chose your Content-Type (if requests are going to be received without a Content-Type header, set the Content-Type for the mapping template to application/json, which is the default behaviour).
Then in the actual mapping template add the following:
{
#set($context.requestOverride.header.apikey= "testMe")
}
This will add (or overwrite if it already exists) a header called apikey with the value "testMe" to all http requests downstream.
If you take this route, then you will need to also map over any other headers, path parameters, query parameters or body that you wish to pass through.
You could loop through the headers and query parameters like this.
## First set the header you are adding
#set($context.requestOverride.header.apikey= "testMe")
## Loop through all incoming headers and set them for downstream request
#foreach($param in $input.params().header.keySet())
#set($context.requestOverride.header[$param]= $input.params().header.get($param))
#if($foreach.hasNext) #end
#end
## Loop through all incoming query parameters and set them for downstream request
#foreach($param in $input.params().querystring.keySet())
#set($context.requestOverride.querystring[$param]= $input.params().querystring.get($param))
#if($foreach.hasNext) #end
#end
As you need to ensure that the header apikey is set to a default value, you should set the override for apikey before looping through the rest of the headers as only the first override will take effect.
The relevant AWS documentation can be found here.
The other alternative would be to point your API Gateway at a Lambda and make the call from the Lambda instead.
Firstly thanks to #KMO for his help. The following is the solution:-
Enable Http Proxy Integration.
Add the headers apikey=xxxx and Accept-Encoding=identity under the same Integration
Request -> Http Headers.
Under Settings -> Binary Media Types set the following as separate Binary Media Types
'*', */*. I mean as two different lines.This step is needed to resolve the Gzip action while returning the response.
Add the Query parameter country in the URL Query String Parameters section.
In the Integration Request map the country parameter to ctry by adding the value under mapped from as method.request.querystring.country. This will ensure that the query parameter country you passed in the main URL will be fed to the downstream url as parameter ctry.
The advantage of this apporoach is that, even if you override the header apikey, the one set under the Http Headers will take the precedence.

HA proxy, how to add dynamic header to incoming request based on request URI

We need to add a header to incoming requests processed by HAproxy. However, each header needs to be composed of uri elements.
If the request is "http://myserver/system/apple/watch"
the header needs to be "Host:applewatch.com" where .com is static.
I am aware of "set-header" command, I just need to extract the second and the third URI elements via REGEX, string them together, and add static field .com.
Is there a way to save a URI element to a variable via regex and then reuse this variable as a header part?
Thanks you.
You can do something like this:
http-request set-header ASDF %[path,word(2,/)]%[path,word(3,/)].com
or
http-request set-header ASDF %[path,regsub(^/system/,''),regsub(/,''),regsub($,'.com')]

Haproxy check if only key exists

I am using haproxy as a load balancer. I have a specific condition for some criteria.
I need to make sure that the query params of logout should starts with http or https. If the query param value is not starting with http or https I simply need to deny the request.
I have checked so many condition but it doesn't seems to work for me.
I've tried the following
acl url_param1 urlp_reg(logout) ^(http|https)://.*$
http-request deny if url_param1
The above command will block all the URL's even if the URL doesn't have the logout key in URL.
I need to allow if the URL doesn't have logout param in URL. I just want to blok only if the logout parameter value doesn't starts with http/https.
Suggest me the condition for this.
Your description of how this behaves does not make sense -- as written, it should deny if the parameter exists and does begin with http(s).
The correct logic is this:
http-request deny if { url_param(logout) -m found } !{ urlp_reg(logout) ^(http|https)://.*$ }
Deny the request if the parameter exists and the parameter does not begin with http(s)://.

How Can I modify a request header value from A to B by using Haproxy

Currently we are using Haproxy as a software loadbalancer.
I have an assignment, where I need to inspect each and request coming into my application and I need to look for a specific header (let's say Accept header) and I need to modify the value of header from A --> B.
Could you please guide me how can I do this by using HAPROXY.
Regards,
-Srini.
To replace one request header with another, example:
Accept: application/json # existing value
Accept: application/xml # desired value
Test the current value then set a header with the desired header.
http-request set-header Accept application/xml if { hdr(accept) -m str application/json }
Using http-request set-header removes any/all existing headers with the same name, which is what you would wanrtin this case. Using -m str specifies a case-sensitive string match on the value. Header name matching is always case-insensitive.
http://cbonte.github.io/haproxy-dconv/1.6/configuration.html#4-http-request