Enabling CORS in HAProxy
-
Hi all
I'm trying to add some additional configuration in HAProxy to deal with CORS errors, the information is on the link below on HAProxy site. However I'm unable to create a cors.lua and reference it on the firewall so can't progress. I created the file in the shell of the firewall, then in "Global Advanced pass thru" section I added the following line
lua-load /etc/haproxy/cors.lua
That however errors and says the file doesn't exist wherever I try and put the file.
https://www.haproxy.com/blog/enabling-cors-in-haproxy/
Has anyone tried this or any other alternative solutions to enabling CORS in HAproxy on PFsense?
-
The HAPROXY article you linked is great in explaining how it works, but pfsense's implementation is less than clear. At least it took me some guessing, but I am also a novice at best.
I have been messing with this for the last few days. As far as I can see, if you upload a file to the /var/etc/haproxy/, every time you click the "save" and "apply" button the file gets deleted. What I have found is that in the "Files" tab for HAProxy, you add a file there. I called it "cors" type "lua script" and in the text block, you paste the code from "cors.lua" from the HAProxy CORS Lua Library.
This next part is where I am unsure if I am doing this correctly. In the front end you can implement it two ways. Method one; add two actions.
First, action "http-request lua action"
then in the parameters box you can put your lua function. Pfsense's implementation automatically adds the lua. before the function name, so in this case just:
cors "Access-Control-Allow-Methods" "Access-Control-Allow-Origin" "Access-Conrol-Allow-Headers"
So in my example case I put
cors "GET,PUT,POST" "my.website.com" "*"
to whitelist my.website.com and allow any method.Second action, put the response "http-response lua script" with the parameter
cors
See the screenshot below.
the resulting haproxy.cfg adds the following to my front-end:
http-request lua.cors "GET,PUT,POST" "my.website.com" "*" if aclcrt_ExternalWebAccess http-response lua.cors if aclcrt_ExternalWebAccess
Note: note I have a main front-end and several shared front-ends, one having additional rules for ssl client verification which is why i believe it adds the
if aclcrt_ExternalWebAccess
to mine.The other method I believe, is to add it to to the "advanced pass thru" section of your front end instead.
this similarly adds the following to the front end in haproxy.cfg
http-request lua.cors "GET,PUT,POST" "my.website.com" "*" http-response lua.cors
Note, that this does not add the
if aclcrt_ExternalWebAccess
condition.I am unsure which is the right method for implementation. I would love some feedback on this too.
I hope this helps you in finding your solution in implementing CORS in pfsense's HAproxy.Now my issue is that on one of my shared front-ends, i have specific SNIs and back-ends that require client SSL certificates. I am learning that firefox does not like to send client certs by default in preflight and will by default error out when a CORS request is being made between one server to the other requiring client SSL certs upon failure of the TLS handshake.
What I am learning is that in preflight the CORS standard requires the browser to not send credentials by default as noted in the mozzilla documentation and with firefox the moment the TLS handshake fails, the CORS request stops.
Note: Some enterprise authentication services require that TLS client certificates be sent in preflight requests, in contravention of the Fetch specification.
Firefox 87 allows this non-compliant behavior to be enabled by setting the preference: network.cors_preflight.allow_client_cert to true (bug 1511151). Chromium-based browsers currently always send TLS client certificates in CORS preflight requests (Chrome bug 775438).I added the following to my CORS config:
http-request lua.cors "GET,PUT,POST" "https://my.website.com" "Access-Control-Allow-Credentials" http-response lua.cors
It still doesn't work.
My guess, if I am reading the documentation correctly is that simple GET requests are not preflighted and/or if the fetch is not configured to include credentials. So, if a request is made for a resource with credentials, and if this header is not returned with the resource, the response is ignored by the browser and not returned to the web content. I found this note and hope i am interpreting correctly.
Inspecting the code running on the webserver that is attempting to get resources from the second SSL cert protected webserver, it does not include credentials. So i suspect that the only way to do this is to either.
A) change
network.cors_preflight.allow_client_cert
totrue
for firefox and require my users that use firefox to do so.
or
B) ask the developer of the webservice to change his source to use a fetch to{ credentials:"include" }
Lastly, Apologize that I hijacked your post. Yours is the most recent post that mentioned CORS and LUA plugins for pfsense. I hope what I have found helped you and also hope that someone who knows better than me can verify/validate what I have posted in both the LUA/CORS setup and my other problem.
-Skeptic
-
So, since there's little on using the CORS lua plugin on this forum, I wanted to add a few notes and observations that may help others in the future. I apologize if posting a response to my own is not allowed (can't find forum rules), but I wanted to make sure that those who are new at this like me have a better picture.
On my last post I mentioned that my cors plugin didn't work. I figured out why.
For a quick re-cap, I have two web servers. server1 and server2. Both have an authentication scheme (client certificates) in order to access. server2 makes requests from a database in server1, but CORS by default is strict and does not allow authenticated requests unless explicitly told to do so.
This is what I ended up setting in "Advanced pass thru" in my shared front end:
http-request lua.cors "GET,PUT,POST" "https://server1.website.com" "*" http-response lua.cors
This is actually working just fine.
From the last post (near the end) I ended up going with option B.
B) ask the developer of the webservice to change his source to use a fetch to
{ credentials:"include" }
I actually just added the code myself to the fetch function.
The reason this was still not working for my setup is that CORS has to be setup again in server1!
In your web server that needs to be accessed using a Cross Origin Requests, CORS headers need to be set up to allow them. Originally, the web server application that I was running was not capable of setting custom headers. (using a node.js webserver).
Because of this I had to use a different web server that offered more flexibility in allowing to set custom headers. In my case I used Caddy (setup is not really relevant to go into). For whichever web server you opt for to do this, CORS has to be set up properly as well as in HAproxy.
My really crappy analogy to this is something along the lines of double NAT and "port forward" twice. The rules have to be set both in the web proxy and the web server to respond correctly. (sorry if this is a really bad analogy)
Hope this helps someone out.
-Skeptic
-
@skepticnerdguy The Advanced pass thru was exactly what I needed. Thanks!
-
Thanks for the info, helped me too!
I did manage to get the actions working rather than the advanced pass thru, see below for what I needed in my particular case
-
This post is deleted! -
Here's what worked for me. I did have to add the lua script to files, however, see my screen shot for the CORS settings. Once I read the lua documentation I was able to add what I needed to get my CORS data to work properly.
Not that I did remove my domain for privacy. It's .mydomain.com. I used the . to include all subdomains. -