--- title: "13. Security Considerations" linkTitle: "13. Security" weight: 370 description: "Privilege isolation, attack surface, Linux capabilities, and secure operation" icon: fa-solid fa-shield-halved module: [HAPROXY] categories: [Task] aliases: - /haproxy/management/security/ - /docs/haproxy/management/security/ - /haproxy/security/ upstream_link: "https://docs.haproxy.org/3.4/management.html" upstream_name: "HAProxy 3.4 Management Guide" upstream_ref: "v3.4.4, chapter 13" --- HAProxy is designed to run with very limited privileges. The standard way to use it is to isolate it into a chroot jail and to drop its privileges to a non-root user without any permissions inside this jail so that if any future vulnerability were to be discovered, its compromise would not affect the rest of the system. In order to perform a chroot, it first needs to be started as a root user. It is pointless to build hand-made chroots to start the process there, these ones are painful to build, are never properly maintained and always contain way more bugs than the main file-system. And in case of compromise, the intruder can use the purposely built file-system. Unfortunately many administrators confuse "start as root" and "run as root", resulting in the uid change to be done prior to starting haproxy, and reducing the effective security restrictions. HAProxy will need to be started as root in order to: - adjust the file descriptor limits - bind to privileged port numbers - bind to a specific network interface - transparently listen to a foreign address - isolate itself inside the chroot jail - drop to another non-privileged UID HAProxy may require to be run as root in order to: - bind to an interface for outgoing connections - bind to privileged source ports for outgoing connections - transparently bind to a foreign address for outgoing connections Most users will never need the "run as root" case. But the "start as root" covers most usages. A safe configuration will have: - a chroot statement pointing to an empty location without any access permissions. This can be prepared this way on the UNIX command line: ```shell # mkdir /var/empty && chmod 0 /var/empty || echo "Failed" ``` and referenced like this in the HAProxy configuration's global section: ```text chroot /var/empty ``` - both a uid/user and gid/group statements in the global section: ```text user haproxy group haproxy ``` - a stats socket whose mode, uid and gid are set to match the user and/or group allowed to access the CLI so that nobody may access it: ```text stats socket /var/run/haproxy.stat uid hatop gid hatop mode 600 ``` ## 13.1. Linux capabilities support {#section-13-1} Since version v2.9 haproxy supports Linux capabilities. If the binary is compiled with USE_LINUX_CAP=1, it is able to preserve capabilities given in 'setcap' keyword during switching from root user to a non-root. Since version v3.1 haproxy also checks if capabilities given in 'setcap' keyword were set in its binary file Permitted set by administrator (capget syscall). If this a case it performs transition of these capabilities in its process Effective set (capset syscall), while running as a non-root user. This was done to avoid all potential use cases when haproxy starts and runs as root: transparent proxy mode, binding to privileged ports. 'setcap' keyword supports following network capabilities: - cap_net_admin: transparent proxying, binding socket to a specific network interface, using set-mark action; - cap_net_raw (subset of cap_net_admin): transparent proxying; - cap_net_bind_service: binding socket to a specific network interface; - cap_sys_admin: creating socket in a specific network namespace. Haproxy never does the transition of these capabilities from its Permitted set to the Effective, if they are not listed as 'setcap' argument. See more information about 'setcap' keyword and supported capabilities in the chapter 3.1 Process management and security in the Configuration guide. Administrator may add needed capabilities in the haproxy binary file Permitted set with the following command: Example: ```haproxy # setcap cap_net_admin,cap_net_bind_service=p /usr/local/sbin/haproxy ``` Added capabilities will be seen in process Permitted set after its start. If the same capabilities are the arguments of 'setcap' keyword, they could be also seen in the process Effective set. This could be check with the following command: Example: ```haproxy # grep Cap /proc//status ``` CapInh: 0000000000000000 CapPrm: 0000000000001400 CapEff: 0000000000001400 CapBnd: 000001ffffffffff CapAmb: 0000000000000000 See more details about setcap and capabilities sets in Linux man pages (capabilities(7)). In some use cases like transparent proxying or creating socket in a specific network namespace, configuration file parser detects that cap_net_raw or cap_sys_admin or some other supported capabilities are needed. Then, during the initialization stage, haproxy process checks, if these capabilities could be put in its Effective set. If it's not possible due to capget or capset syscall failure (restrictions set on syscalls by some security modules like SELinux, Seccomp, etc), process emits diagnostic warnings (start with -dD). Due to support of many different platforms with different system settings, it's impossible for the parser to deduce from the configuration file, if binding to privileged ports will be done. So, in the case of insufficient privileges (run as non-root) process will terminate only with an alert message like below. It's up to a user to recheck its configuration and haproxy binary capabilities set. Example: ```shell $ haproxy -dD -f haproxy.cfg ... [ALERT] (96797): Binding [haproxy.cfg:36] for frontend fe: cannot bind socket (Permission denied) for [0.0.0.0:80] [ALERT] (96797): [haproxy.main()] Some protocols failed to start their listeners! Exiting. ```