Objective
I use HAProxy to serve multiple SSL/TLS enabled sites with HAProxy doing SSL termination. The sites serve regular HTTP while users see proper HTTPS sites (with free certificates from LetsEncrypt). My objective was to provide HTTP Basic Authentication as a second layer of protection for certain applications like NextCloud (DropBox clone) or Gitea (GitHub clone).
Challenges
I wanted to provide HTTP Basic Auth over specific services (not all which is much easier) which didn’t natively support them like Gitea. Secondly, I wanted it to be transparent to the underlying Application. Thirdly, I didn’t want to provide plain-text passwords in haproxy.cfg.
Solution
After few iterations I arrived at a simple solution to the problem. The steps are:
- Create users with encrypted passwords
- Add users to haproxy.cfg
- Force authentication for specific sites on frontend
- Remove authorization on backend
Create users with encrypted passwords
To create encrypted passwords, you need a tool called mkpasswd which is available with whois, so you need to install it first (one time activity):
sudo apt install whois
Create password as shown below (replace Password with your actual Password):
mkpasswd -m sha-512 Password
Copy the encrypted password generated by the tool (mkpasswd).
Add users to haproxy.cfg
You can add multiple user lists as well as user groups (beyond the scope of this guide) to haproxy. Let’s create an user list named AuthUsers (as an example):
userlist AuthUsers
user Username1 password $6$d./LYD0vplX$XoPWiTQfhNt4g4NRcU/toFiV89xhW524abcdfg
user Username2 password $6$d./LYD0vplX$XoPWiTQfhNt4g4NRcU/toFefghxhW524abcdfg
Replace Username1, Username2 with your actual user names and the corresponding encrypted password as the last argument in the line.
You can add as many users as you want.
Force authentication for specific sites only
Let’s say we want to force authentication for these two sites (in frontend section):
acl host_example1 hdr(host) -i example1.com acl host_example1 hdr(host) -i example2.com
Below this we force them to be authenticated:
acl authorized http_auth(AuthUsers) http-request auth realm Example1 if host_example1 !authorized http-request auth realm Example2 if host_example2 !authorized
Use backend only when properly authenticated:
use_backend example1 if host_example1 authorized use_backend example2 if host_cexample2 authorized
Remove authentication header from backend
HAProxy for some strange reason sends this Authorization header to backend which sends certain servers in a loop. it is advisable to remove it.
backend example1 http-request set-header X-Client-IP %[src] server example1 example1:3000 check http-request del-header Authorization backend example2 http-request set-header X-Client-IP %[src] server example2 example2:3000 check http-request del-header Authorization
Now restart the haproxy server and voila!
2 replies on “Guide: HAProxy HTTP Basic Authentication for specific sites (SSL Termination)”
It seems like you might have some formatting issues with this line:
aclhost_example1hdr(host) -iexample1.comaclhost_example1hdr(host) -iexample2.com
Also I’m not following what “Example1” is in this line:
http-request auth realm Example1 if host_example1 !authorized
I’m assuming case matters and I don’t see where that word shows up anywhere else with identical case. Can you clarify. Otherwise I think this is putting me on the right path and the information is helpful.
Thanks for the catch. The code block of WordPress was creating this mess. I changed it to pre tag and it looks fine now. Please check and let me know.