I’m attempting to harden a forwarding proxy that currently runs on a standard Trixie deployment with haproxy version 3.0.11-1+deb13u2.
When I try to chroot it, the control processes timeout.
In an attempt to isolate the problem I’ve mocked a simple test system but can’t seem to get the worker process to quit with systemd or socat.
Gemini concluded the client wasn’t listening and has advised me to change the unit file settings:
[Service]
# Pivot to simple to stop waiting for unresponsive notify signals
Type=simple
# Force immediate termination since workers are deaf inside the chroot
KillSignal=SIGKILL
TimeoutStopSec=2s
# Standard Hardening & Capabilities
RuntimeDirectory=haproxy
RuntimeDirectoryMode=0750
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_CHROOT CAP_SETGID CAP_SETUID
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_CHROOT CAP_SETGID CAP_SETUID
# Map the journal socket for visibility
BindReadOnlyPaths=/run/systemd/journal/dev-log:/var/lib/haproxy/dev/log
But a few socat commands to the worker proved it was healthy and responsive but didn’t terminate when sent the quit command.
This is the mock haproxy.cfg:
global
log /dev/log local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
master-worker
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode tcp
timeout connect 5s
timeout client 50s
timeout server 50s
option tcplog
option dontlognull
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend tproxy_test
bind *:8080 transparent
default_backend local_dummy
backend local_dummy
server loopback 127.0.0.1:9999
This is an ongoing test and I’m just reaching out to see if anyone here has a better solution than Gemini