App-Äffchen

Wer kennt das nicht? Da hast Du einen schönen neuen Loadbalancer vor Deine Proxies gebaut und dann flanscht Dir der Kollege seine Web Applikation da dran, die überhaupt nicht funktioniert, weil der Kollege, der die gebaut hat und seit 5 Jahren in Rente ist, die für den Internet Explorer 4 optimiert hat und das Ding so kaputt ist, dass der Loadbalancer Verbindungsanfragen selbst mit accept-invalid-http-request einfach verwirft.

Und natürlich sagt das Marketing, dass das Super Business Critical ist und eigentlich gestern schon hätte laufen müssen und deswegen schon Management Attention hat (schlotter) und was das jetzt schon wieder mit dieser Security wäre und überhaupt kann das mit den Standards ja nicht stimmen, denn vorher ging ja alles.

Also was machste? Load Balancer umkonfigurieren auf TCP Modus (OSI Layer 4), dann macht der keine HTTP-Konformitäts-Prüfungen mehr sondern reicht den Mist einfach durch.

Alla hopp.

Problem an der Stelle: Der Loadbalancer schreibt, weil im TCP Modus, die Quell-Adresssen des aufrufenden Systems nicht mehr in den HTTP Header (X-Forwarded-For), damit greifen auch die ganzen IP-basierten ACLs an den Backend Systemen nicht mehr, denn die sehen ja nur noch die Loadbalancer-Adresse.

Proxy Protocol

Netterweise hat der Willy Tarreau sich da mal Gedanken gemacht und was entwickelt, das sie Proxy Protocol genannt haben.

Im HAproxy Blog ist das schön erklärt, wie das funktioniert, wenn man sich nicht durch die Spezifikation wühlen möchte.

Ist aber auch eigentlich ziemlich simpel: Im Prinzip wird beim Aufbau der Verbindung zwischen Proxy (oder Loadbalancer) und Backend System ein zusätzliches Paket (in der Dokumentation steht verwirrenderweise “Header”) eingefügt, in dem die Quell-Adresse des Initiators der Verbindung sowie die Original-Ports drin stehen. That’s it.

Beispiel

In diesem Beispiel ist das Frontend ein Haproxy Load Balancer, Backend sind zwei Squid Proxies, über die die Verbindung zum Zielsystem erfolgt. Wichtig: Das Proxy Protocol muss an beiden Komponenten (Balancer und Proxy) konfiguriert und aktiviert sein, ansonsten kommt GAR KEINE Kommunikation mehr zustande.

Konfiguration am Loadbalancer

[...Default-Zeugs]

frontend loba
        bind 192.168.10.13:8080
        mode tcp
        option tcplog
        default_backend proxies

backend proxies
        balance source
        hash-type consistent
        mode tcp
        option tcp-check
        tcp-check connect port 3128
        source 192.168.168.10.13
        server proxy1 192.168.12.31:3128 check send-proxy check-send-proxy
        server proxy2 192.168.12.32:3128 check send-proxy check-send-proxy

Das Einzige, was man mal abgesehen vom offensichtlichen mode tcp machen muss, um Proxy Protocol zu aktivieren, ist jeweils ein send-proxy in die Backend-Zeilen zu schreiben und check-send-proxy wenn eine port Direktive verwendet wird, weil sonst die Checks nicht mehr funktionieren.

Konfiguration Squid proxy

Am Squid Proxy (Backend) müssen die Direktiven require-proxy-header und proxy_protocol_access allow gesetzt werden. Bei letzterer definiert man in der ACL die Quell-Adressen des Loadbalancers.

Die ACL für den Proxy Protocol Access sollte man nicht auf “all” setzen, es sei denn, man hat andere Sicherheitsmechanismen am Start, wie zum Beispiel eine Firewall, die nur Verbindungen zwischen Loadbalancer und Proxies erlaubt.

http_port 192.168.12.31:3128 require-proxy-header
acl loba src 192.168.168.10.13
proxy_protocol_access allow loba

Dies hat den Effekt, dass man zwar im Tcpdump am Squid nur die Quell-Adresse des Loadbalancers sieht, im Log aber die “richtigen” Quelladressen auftauchen, die somit auch in ACLs verwendet werden können.

A propos tcpdump: Wenn man das mal troubleshooten muss, findet man die Proxy Protocol Pakete zwischen dem ACK und dem ersten GET/CONNECT. Nach Zeichenkette “PROXY” (Uppercase) suchen.

Mission complete. 😏

Links zur Dokumentation: