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)