HAProxy: omiting auth for URI not working - haproxy

I need to be able to omit authentication for a specific URI using haproxy but using the following config file is not working. When accessing whatever.server/app/my-app, I still get asked to provide login credentials.
global
maxconn 4096
daemon
userlist myUsers
user someUser insecure-password somePass
defaults
mode http
log 127.0.0.1 local1 debug
option httplog
frontend all
bind 0.0.0.0:80
timeout client 86400000
default_backend www_backend
acl is_websocket hdr(Upgrade) -i WebSocket
acl is_webapp path_beg /app
acl is_my_app path_beg /app/my-app
acl auth_ok http_auth(myUsers)
http-request auth unless auth_ok or is_websocket or is_my_app
use_backend webapp_backend if is_webapp
backend www_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For
option httpclose
timeout server 1800000
timeout connect 4000
server server1 localhost:81 weight 1 maxconn 1024 check
backend webapp_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For
option httpclose
timeout server 1800000
timeout connect 4000
server server1 localhost:8800 weight 1 maxconn 1024 check
I'm using haproxy v1.4
EDIT
Also tried
http-request allow if is_my_app
http-request auth unless auth_ok or is_websocket
but it's allowing all URLs without authentication

Acls can be negated as mentioned here https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#7.2
acl url_static path_beg /app/my-app
acl AuthOkay_Web http_auth(myUsers)
http-request auth realm AuthYourself if !isOptions !url_static !AuthOkay_Web
Also explained at https://serverfault.com/a/874742/297275

Related

Dynamic server name and header in HAProxy

I’m looking for the equivalent of this backend code block below for requests to www.example.com and example.com.
http-response set-header X-Target example.com
server web-servers site.example.com:80 check
I take all the requests to www.example.com but I want to serve them to site.example.com using haproxy. There are several variations of example.com so I would like to have a list of allowed domains and then if they're allowed I would like to have a backend code block like below where I could use %[req.hdr(Host)] as the value in the http-response X-Target statement.
http-response set-header X-Target %[req.hdr(Host)]
server web-servers site.%[req.hdr(Host),regsub(^www.,,)]:80 check
HA-Proxy version 2.1.4-273103-54 2020/05/07 - https://haproxy.org/
I’m getting this error when I try haproxy -c -f haproxy.test
[root#pm-prod-haproxy05 haproxy]# haproxy -c -f haproxy.test
[ALERT] 259/180932 (16116) : parsing [haproxy.test:40]: ‘http-response set-header’: sample fetch may not be reliably used here because it needs ‘HTTP request headers’ which is not available here.
[ALERT] 259/180932 (16116) : Error(s) found in configuration file : haproxy.test
[root#pm-prod-haproxy05 haproxy]#
I've also tried this:
http-request set-header X-Target %[req.hdr(Host)]
http-request set-header X-Hostname %[req.hdr(Host),regsub(^www.,site.,)]
http-request web-server do-lookup(hdr(X-Hostname))
server web-servers web-server:80 check
This is my full configuration.
global
log 127.0.0.1 local2 debug
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
daemon
stats socket /var/lib/haproxy/stats
defaults
mode http
option httplog
log global
option dontlognull
option http-server-close
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend frontend-http
bind *:80
bind *:443
acl redirect path_beg -i /rd
use_backend backend-tracking if redirect
default_backend backend-default
backend backend-default
option forwardfor
http-response set-header X-Publishing-system website
http-response set-header X-Target %[req.hdr(Host)]
server web-servers site.%[req.hdr(Host),regsub(^www.,,)]:80 check
backend backend-tracking
option forwardfor
http-response set-header X-Publishing-system redirect
http-request set-uri %[url,regsub(^/rd,/,)]
server web-hp www.trackingplatform.com:80 check
About Header manipulation
As the ALERT message say you can't use request header in the response. You should replace the following line.
Wrong line
http-response set-header X-Target %[req.hdr(Host)]
Right Line
http-request set-header X-Target %[req.hdr(Host)]
The Backend-Server should not remove this header. If you not want to send the Backend-Server the 'X-Target' host header then can you use a session variable to save the host header from the request to the response phase.
http-request set-var(txn.my_host) req.hdr(host),lower
http-response set-header X-Target %[var(txn.my_host)]
In the documentation are the set-var and set-header directive quite good explained.
http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4-http-request
About the server manipulation
This line could not work because haproxy tries to resolve the target server at start time.
server web-servers site.%[req.hdr(Host),regsub(^www.,,)]:80 check
In newer version of haproxy. like 2.1, can you dynamically resolve and set the destination hosts.
http://cbonte.github.io/haproxy-dconv/2.1/configuration.html#4.2-http-request%20do-resolve
I assume you want to change the host header for the target server that the right virtual server is used.
My suggestion to solve your issue is to change the host header and set the server name to a resolvable address.
backend backend-default
option forwardfor
http-response set-header X-Publishing-system website
http-request set-header X-Target %[req.hdr(Host)]
http-request replace-header Host ^www(.*) site.\1
http-request set-header X-NewTarget %[req.hdr(Host),regsub(^www.,,)]
server web-servers site.example.com:80 check
This backend config is only syntax checked.
About dynamic backend server
The server should be resolved dynamically.
For that solution is at least HAProxy 2.0 necessary.
I copy here some parts of the doc http-request do-resolve for this answer.
You will need to add a section resolvers to your config
resolvers mydns
# use here your prefered DNS Servers
nameserver local 127.0.0.53:53
nameserver google 8.8.8.8:53
timeout retry 1s
hold valid 10s
hold nx 3s
hold other 3s
hold obsolete 0s
accepted_payload_size 8192
frontend frontend-http
bind *:80
bind *:443
# define capture buffer for backend
declare capture request len 60
acl redirect path_beg -i /rd
use_backend backend-tracking if redirect
default_backend backend-default
# ... some more backends
backend backend-default
option forwardfor
http-response set-header X-Publishing-system website
http-request set-header X-Target %[req.hdr(Host)]
# replace www with site in host header
http-request replace-header Host ^www(.*) site.\1
# if necessary set X-NewTarget header
http-request set-header X-NewTarget %[req.hdr(Host),regsub(^www.,,)]
# do dynamic host resolving for dynamic
# server destination for
# the replaced Host Header above
http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower
# print the resolved IP in the log
http-request capture var(txn.myip) id 0
# rule to prevent HAProxy from reconnecting to services
# on the local network (forged DNS name used to scan the network)
# add the IP Range for the destination host here
http-request deny if { var(txn.myip) -m ip 127.0.0.0/8 10.0.0.0/8 }
http-request set-dst var(txn.myip)
server clear 0.0.0.0:0
Please take care about the note in the documentation
NOTE: Don't forget to set the "protection" rules to ensure HAProxy won't be used to scan the network or worst won't loop over itself...

How to link frontend to backend when the path request are different?

I have an Haproxy set with https offloadin, and I'm trying to correctly point the requests made to frontend to it's corresponding backend, but bumped into some obstacles.
I have a backend server on http://:9000/abc (NOT in root of the webserver) and when I set a frontend with https:///abc the pointing works as expected and I see the login page.
But I also have another backend server, which is on http://:8888 (IN the root of webserver, it makes it's own redirect to http://:8888/def) and I want it to be accessible by https:///def. But in this case the pointing doesn't work.
How can I make https:///def point to http://:8888 ? Heres is my .cfg
Using HAproxy 1.7
# Automaticaly generated, dont edit manually.
# Generated on: 2019-01-28 13:59
global
maxconn 1000
stats socket /tmp/haproxy.socket level admin
uid 80
gid 80
nbproc 1
hard-stop-after 15m
chroot /tmp/haproxy_chroot
daemon
tune.ssl.default-dh-param 2048
server-state-file /tmp/haproxy_server_state
listen HAProxyLocalStats
bind 127.0.0.1:2200 name localstats
mode http
stats enable
stats refresh 10
stats admin if TRUE
stats show-legends
stats uri /haproxy/haproxy_stats.php?haproxystats=1
timeout client 5000
timeout connect 5000
timeout server 5000
frontend shared-frontend-merged
bind 200.129.168.14:443 name 200.129.168.14:443 no-sslv3 ssl crt-list /var/etc/haproxy/shared-frontend.crt_list
mode http
log global
option http-keep-alive
option forwardfor
acl https ssl_fc
http-request set-header X-Forwarded-Proto http if !https
http-request set-header X-Forwarded-Proto https if https
timeout client 30000
acl aclcrt_shared-frontend var(txn.txnhost) -m reg -i ^ifamcmc\.ddns\.net(:([0-9]){1,5})?$
acl ACL1 var(txn.txnpath) -m sub -i abc
acl ACL2 var(txn.txnpath) -m sub -i def
http-request set-var(txn.txnhost) hdr(host)
http-request set-var(txn.txnpath) path
use_backend glpi_ipvANY if ACL1
use_backend ciweb_ipvANY if ACL2
frontend http-to-https
bind 200.129.168.14:80 name 200.129.168.14:80
mode http
log global
option http-keep-alive
timeout client 30000
http-request redirect scheme https
backend abc_ipvANY
mode http
id 102
log global
timeout connect 30000
timeout server 30000
retries 3
option httpchk OPTIONS /
server abc 10.100.0.30:9000 id 103 check inter 1000
backend def_ipvANY
mode http
id 104
log global
timeout connect 30000
timeout server 30000
retries 3
option httpchk OPTIONS /
server def 10.100.0.40:8888 id 105 check inter 1000
I expect that access to https:///def correctly points to the backend at http://:8888
https://<my.address.com>/abc ------> http://<internal_ip>:9000/abc (OK)
https://<my.address.com>/def ------> http://<internal_ip_2>:8888 (NOT OK)
Have your HAProxy system do initially forwarding based on ports, and then wildcards on your directory.
Please see below:
frontend a-frontend-conf
# Declare an ACL using path_beg (Path Begins)
acl path_images path_beg /images
# Use backend server1 if acl condition path_images is fulfilled
use_backend server1 if path_images
backend server1
[...]
Source: https://serverfault.com/questions/659793/haproxy-how-to-balance-traffic-within-directory-reached

Why does HAProxy show that a server's check URL is a 404 when running curl on this URL is successful?

I'm setting up HAProxy to load-balance a resource between 3 back-ends. Here is the HAProxy config : (In the following snippets I replaced the actual domain name by example.net)
global
log 127.0.0.1 local2
log-send-hostname
maxconn 2000
pidfile /var/run/haproxy.pid
stats socket /var/run/haproxy.sock mode 600 level admin
stats timeout 30s
daemon
# SSL ciphers
...
defaults
mode http
option forwardfor
option contstats
option http-server-close
option log-health-checks
option redispatch
timeout connect 5000
timeout client 10000
timeout server 10000
...
frontend front
bind *:443 ssl crt /usr/local/etc/haproxy/front.pem
reqadd X-Forwarded-Proto:\ https if { ssl_fc }
stats uri /haproxy?stats
option httpclose
option forwardfor
default_backend back
balance source
backend back
balance roundrobin
option httpchk GET /healthcheck HTTP/1.0
server server1 xxx.xxx.xxx.xxx:80 check inter 5s fall 2 rise 1
server server2 yyy.yyy.yyy.yyy:8003 check backup
server mysite example.net:80 check backup
The issue is the following: even though the first 2 servers respond correctly, the domain-based one always shows as a 404:
What is counter-intuitive to me is that if I use curl to access this same healthcheck, I get an HTTP 200 (like I would expect to see in the HAProxy stats) :
curl -I http://example.net/healthcheck
HTTP/1.1 200 OK
When I ping my site, I get:
# ping example.net
PING example.net (217.160.0.195) 56(84) bytes of data.
64 bytes from 217-160-0-195.elastic-ssl.ui-r.com (217.160.0.195): icmp_seq=1 ttl=50 time=45.7 ms
Is it because the IP of my domain is shared with other domains (1&1 shared hosting) that HAProxy can't access it? Why is that and how to make HAProxy reach it correctly?

Redirecting URL using HAProxy

Im trying to direct the following URL https://register.company.xzy to https://register.company.xzy/register/supplier?code=
My haproxy config has acls in it for some existing subdomains and has been working well but i cant see to get this to work:
frontend https
bind 10.10.2.150:443 ssl crt /etc/apache2/ssl/star.company.xyz.pem
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto:\ https
acl www.company.xyz hdr(host) -i www.company.xyz
acl portal.company.xyz hdr(host) -i portal.company.xyz
acl live.company.xyz hdr(host) -i live.company.xyz
acl register.company.xyz hdr(host) -i register.company.xyz
use_backend website_live_servers if www.company.xyz
use_backend website_live_servers if portal.company.xyz
use_backend application_live_servers if live.company.xyz
use_backend register_live_servers if register.company.xyz
backend application_live_servers
mode http
cookie SERVERID insert indirect nocache
server server1 server1.company.xyz:80 check cookie $1
backend register_live_servers
mode http
cookie SERVERID insert indirect nocache
server server2 server2.company.xyz:80 check cookie $1
backend website_live_servers
mode http
cookie SERVERID insert indirect nocache
server server3 server3.company.xyz:80 check cookie $1
server server3 server3.company.xyz:80 check cookie $2
Any ideas or guidance?
Well what you need is to rewrite URL
http-request set-path <fmt> [<condition>]
http-request set-query <fmt> [<condition>]
OR rewrite complete URI
http-request set-uri <fmt> [<condition>]
rewriting url path

HaProxy (cannot bind socket, select test failed)

Hello everyone,
Im working about an high availbility project, I had to put in production an haproxy for some applications. Everything was ok after some basics tests but I had some errors and cant fix it. Does someone have some ideas ?
here is the test
# /usr/sbin/haproxy -d -f /etc/haproxy/haproxy.cfg
Available polling systems :
sepoll : pref=400, test result OK
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result FAILED
Total: 4 (3 usable), will use sepoll.
Using sepoll() as the polling mechanism.
[ALERT] 174/160258 (22038) : Starting proxy mysql: cannot bind socket
[ALERT] 174/160258 (22038) : Starting proxy http: cannot bind socket
There is my file haproxy.cfg
global
log 127.0.0.1 local0 notice
user haproxy
group haproxy
maxconn 32000
ulimit-n 65536
defaults
log global
option dontlognull
retries 2
timeout connect 3000
timeout server 5000
timeout client 5000
option redispatch
listen mysql
bind *:3306
mode tcp
option tcplog
balance roundrobin
option mysql-check user haproxy_check
server mysql1 10.83.83.167:3306 check
server mysql2 10.83.83.168:3306 check
server mysql3 10.83.83.169:3306 check
listen http
mode http
bind *:80
stats enable
stats uri /stats
stats auth admin:HaProxy2014
acl app1_cluster_acl hdr_beg(host) -i app1
acl app2_cluster_acl hdr_beg(host) -i app2
acl mysql_cluster_acl hdr_beg(host) -i mysql
use_backend app1_cluster if app1_cluster_acl
use_backend app2_cluster if app2_cluster_acl
use_backend mysql_cluster if mysql_cluster_acl
backend app1_cluster
mode http
cookie SERVERID insert indirect nocache
option forwardfor header X-Real-IP
option http-server-close
option httplog
balance roundrobin
server serv1 10.83.83.203:80 check cookie serv1
server serv2 10.83.83.204:80 check cookie serv2
backend app2_cluster
mode http
cookie SERVERID insert indirect nocache
option forwardfor header X-Real-IP
option http-server-close
option httplog
balance roundrobin
server serv1 10.83.83.187:80 check cookie serv1
server serv2 10.83.83.188:80 check cookie serv2
backend mysql_cluster
mode http
cookie SERVERID insert indirect nocache
option forwardfor header X-Real-IP
option http-server-close
option httplog
balance roundrobin
server mysql1 10.83.83.167:80 check cookie serv1
server mysql2 10.83.83.168:80 check cookie serv2
server mysql3 10.83.83.169:80 check cookie serv2
I get the same error if there is already a mysql or http service running on my load balancer in addition to ruuning on the back ends.
For example if nginx/apache is already running on my load balancer.
$ netstat -anp | grep ":80"
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN 3646/nginx
And i try to start my load balancer with bind *:80 i get a similar error.
$ haproxy -d -f /etc/haproxy/haproxy.cfg
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result FAILED
Total: 3 (2 usable), will use epoll.
Using epoll() as the polling mechanism.
[ALERT] 195/001456 (1903) : Starting frontend www: cannot bind socket [0.0.0.0:80]
If you need to have a mysql or http instance listening on 127.0.0.1 then you can specify the ip of another interface in the bind call.
bind: 10.0.0.20:80
With the latest version of haproxy you can now even use variables.
bind ${LB1}:80
And export these from the haproxy startup script or /etc/default/haproxy
export LB1="10.0.0.20"
Otherwise perhaps there is an issue with your haproxy startup scripts.