HAProxy Proxy Protokoll Apache Ubuntu 18.04

HAProxy im mode tcp und der Kombination Ubuntu 18.04 LTS mit Apache als Backend Server hat einen entscheidenden Nachteil, wenn damit die ursprüngliche Client IP im Apache Logfile aufgezeichnet werden soll. Um dies zu bewerkstelligen ist das Proxy Protokoll zu verwenden. Allerdings ist die Unterstützung des HAProxy Proxy Protokolls in den Apache erst mit der Version 2.4.30 erfolgt. Ein auf GitHub entwickeltes Apache Modul mod-proxy-protocol wurde wie dort beschrieben in das Modul mod_remoteip des Apache Projektes gemerged.

In Ubuntu 18.04 LTS steht der Apache allerdings nur in der Version

:~# apache2 -v
Server version: Apache/2.4.29 (Ubuntu)
Server built:   2018-04-25T11:38:24

zur Verfügung und in diesem ist das Module mod_remoteip nicht mit der beschriebenen Proxy Protokoll Unterstützung enthalten.

:~# a2enmod remoteip
Enabling module remoteip.
To activate the new configuration, you need to run:
  systemctl restart apache2.service

:~# vim sites-enabled/000-default.conf
[...]
  RemoteIPProxyProtocol On
[...]

:~# apache2ctl configtest
AH00526: Syntax error on line 8 of /etc/apache2/sites-enabled/000-default.conf:
Invalid command 'RemoteIPProxyProtocol', perhaps misspelled or defined by a module not included in the server configuration
Action 'configtest' failed.
The Apache error log may have more information.

Ein Ausweg kann sein, das Modul mod_remoteip aus der stabilen Apache Version, zur Zeit 2.4.33, selbst zu kompilieren und einzubinden. Den Source Code des Modules kann man sich aus dem kompletten Download des Apache httpd-<version>.tar.gz oder entsprechd des SVN herausholen. Der Code findet sich unter dem Pfad.

./modules/metadata/mod_remoteip.c

Zum Kompilieren müssen die Apache Developer-Tools installiert sein. Dies sollte evtl. auf einer eigenen Ubuntu 18.04 LTS VirtualBox VM geschehen. Damit ist sichergestellt, dass das Original Modul nicht überschrieben wird.

:~# apt-get install apache2-dev
[...]

Kompilieren des Moduls mittels apxs2.

:~# apxs2 -c -i mod_remoteip.c
/usr/share/apr-1.0/build/libtool  --mode=compile --tag=disable-static x86_64-linux-gnu-gcc -prefer-pic -pipe -g -O2 -fstack-protector-strong -Wformat -Werror=format-security  -Wdate-time -D_FORTIFY_SOURCE=2   -DLINUX -D_REENTRANT -D_GNU_SOURCE  -pthread  -I/usr/include/apache2  -I/usr/include/apr-1.0   -I/usr/include/apr-1.0 -I/usr/include  -c -o mod_remoteip.lo mod_remoteip.c && touch mod_remoteip.slo
libtool: compile:  x86_64-linux-gnu-gcc -pipe -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -DLINUX -D_REENTRANT -D_GNU_SOURCE -pthread -I/usr/include/apache2 -I/usr/include/apr-1.0 -I/usr/include/apr-1.0 -I/usr/include -c mod_remoteip.c  -fPIC -DPIC -o .libs/mod_remoteip.o
/usr/share/apr-1.0/build/libtool  --mode=link --tag=disable-static x86_64-linux-gnu-gcc -Wl,--as-needed -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now    -o mod_remoteip.la  -rpath /usr/lib/apache2/modules -module -avoid-version    mod_remoteip.lo
libtool: link: rm -fr  .libs/mod_remoteip.la .libs/mod_remoteip.lai .libs/mod_remoteip.so
libtool: link: x86_64-linux-gnu-gcc -shared  -fPIC -DPIC  .libs/mod_remoteip.o    -Wl,--as-needed -Wl,-Bsymbolic-functions -Wl,-z -Wl,relro -Wl,-z -Wl,now   -Wl,-soname -Wl,mod_remoteip.so -o .libs/mod_remoteip.so
libtool: link: ( cd ".libs" && rm -f "mod_remoteip.la" && ln -s "../mod_remoteip.la" "mod_remoteip.la" )
/usr/share/apache2/build/instdso.sh SH_LIBTOOL='/usr/share/apr-1.0/build/libtool' mod_remoteip.la /usr/lib/apache2/modules
/usr/share/apr-1.0/build/libtool --mode=install install mod_remoteip.la /usr/lib/apache2/modules/
libtool: install: install .libs/mod_remoteip.so /usr/lib/apache2/modules/mod_remoteip.so
libtool: install: install .libs/mod_remoteip.lai /usr/lib/apache2/modules/mod_remoteip.la
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /usr/lib/apache2/modules
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/lib/apache2/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the '-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the 'LD_RUN_PATH' environment variable
     during linking
   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to '/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
chmod 644 /usr/lib/apache2/modules/mod_remoteip.so

Das so entstandene Binary sollte unter anderem Namen auf die „produktiv“ Maschine kopiert werden.

:~# mv /usr/lib/apache2/modules/mod_remoteip.so mod_remoteip_2433.so
:~# scp mod_remoteip_2433.so /usr/lib/apache2/modules/

Damit ist sichergestellt, dass das Modul bei einem apt-get update/upgrade Lauf niemals überschrieben wird.

Einbinden des selbskompilierten Modules in die Apache Konfiguration.

:~# cd /etc/apache2
:~# vim mods-available/remoteip_2433.load
LoadModule remoteip_module /usr/lib/apache2/modules/mod_remoteip_2433.so

:~# a2enmod remoteip_2433
Enabling module remoteip_2433.
To activate the new configuration, you need to run:
  systemctl restart apache2.service

:~# apache2ctl configtest
Syntax OK

:~# systemctl restart apache2.service

Der Vorteile des Proxy Protokolls liegt nun darin, dass die zugreifenden Client IPs über den HAProxy im mode tcp an den Apache übermittelt werden und diese in die Logfiles der Apache Backend Server mit aufgenommen werden können. Dazu ist noch eine kleine Erweiterung am Logfile Format um ein %a vorzunehmen.

:~# vim apache2.conf
[...]
LogFormat "%a %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined

In der HAProxy Konfiguration wird nun ebenfalls das Proxy Protokoll per send-proxy eingeschaltet.

:~# vim /etc/haproxy/haproxy.cfg
[...]
frontend frontend227
        description Frontent 227
        mode tcp
        option tcplog
        bind 192.168.202.227:80
        default_backend backend227

backend backend227
        description Backend 227
        mode tcp
        server web01 192.168.56.227:80 send-proxy check

:~# haproxy -f /etc/haproxy/haproxy.cfg -c
Configuration file is valid

:~# systemctl restart haproxy

Testzugriff per curl oder Browser und die Kontrolle der entsprechenden Logfiles der HAProxy und Apache Backend Servers.

:~$ curl http://192.168.202.227/

:~# tail -f /var/log/haproxy.log
May 13 19:54:17 haproxy01 haproxy[1848]: 192.168.202.246:50191 [13/May/2018:19:54:17.923] frontend227 backend227/web01 1/0/2 229 -- 2/1/0/0/0 0/0

:~# tail -f /var/log/apache2-227/access.log
192.168.202.246 192.168.56.225 - - [13/May/2018:19:54:18 +0200] "GET / HTTP/1.1" 200 229 "-" "curl/7.47.0"

Die 192.168.202.246 ist die zugreifende IP des Client.