I have to write and check with remote API for each request coming into my haproxy server. Is there a way to send a request with parameters to an API endpoint and based on the response of the endpoint to select a backend.
So I’ve found that this is possible using LUA so I’ll post some sample code if anyone is interested.
Yes, please do.
ok, so I’ve got it pretty much working but I’m having a problem getting the value of the web service. I’ve tried a few different libraries and rebuilding haproxy / lua / luarocks from scratch and still issues.
Pretty straightforward code and the url is valid.
local stream = assert(http_request.new_from_uri(api_call):go())
local body = assert(stream:get_body_as_string())
[ALERT] 164/081414 (14527) : Lua sample-fetch ‘forensiq’: runtime error: /root/haproxy_build/forensiq.lua:93: attempt to call a nil value (method ‘get_body_as_string’) from /root/haproxy_build/forensiq.lua:93 C function line 2.
and using the http.get method, I get this message.
[ALERT] 164/082838 (14788) : Lua sample-fetch ‘forensiq’: runtime error: /root/haproxy_build/forensiq.lua:92: attempt to index a nil value (global ‘http’) from /root/haproxy_build/forensiq.lua:92 C function line 2.
http.get(api_call, nil, function(code, data)
if (code ~= 200) then
print("HTTP request failed")
else
print(code, data)
end
end)
I found it’s pretty easy. Here’s the basics on how I did it. I’m always open to improvements.
In the global section you load the lua script
lua-load check_fraud.lua
and then in the front end section I had this.
frontend frontend-http-https
bind :80
bind :443 ssl crt /etc/haproxy/ssl
default_backend backend-default
backend backend-default
option forwardfor
http-request deny if { lua.check_fraud 0 }
http-response set-header X-Detection passed
server web-1 www.website.com:443 check ssl verify none
and in the check_fraud.lua file
core.register_fetches("check_fraud", function(txn)
-- load up the libraries
local http_util = require "http.util" -- for dict_to_query
local io = require("io")
local https = require("ssl.https")
local ltn12 = require("ltn12")
local json = requires("json")
-- local variables
local api_root = "https://website.com/services/check"
local now = os.date("*t")
local parameters = {}
local clientip = txn.f:src()
local risk_tolerance = 85
parameters["client_key"] = "asdf123asdf"
parameters["request_type"] = "click"
parameters["ip_address"] = clientip
parameters["click_time"] = string.format("%d-%02d-%02d %02d:%02d:%02d",now["year"],now["month"],now["day"],now["hour"],now["min"],now["sec"])
parameters["path"] = txn.f:path()
parameters["referrer"] = txn.sf:req_fhdr("host")
parameters["ua"] = txn.sf:req_fhdr("User-Agent")
parameters["output"] = "JSON"
local api_call = api_root .. "?" .. http_util.dict_to_query(parameters)
result, statuscode, content = https.request(api_call)
local fraud_data = json:decode(result)
fraud = fraud_data.items[1]
if fraud.riskScore < risk_tolerance then
return 1
else
return 0
end
end)