Der Autor erklärt, wie die Geschwindigkeitsbegrenzung (Ratenbegrenzung) für HAProxy- Abfragen mit bestimmten IP-Adressen implementiert wird . Das Mail.ru Cloud Solutions- Team hat seinen Artikel übersetzt - wir hoffen, dass Sie damit nicht so viel Zeit und Mühe darauf verwenden müssen, wie Sie es aufwenden mussten.Tatsache ist, dass dies eine der beliebtesten Methoden zum Schutz eines Servers vor DoS-Angriffen ist, es jedoch schwierig ist, im Internet klare Anweisungen zur spezifischen Konfiguration zu finden. Durch Versuch und Irrtum zwang der Autor HAProxy, die Häufigkeit von Anforderungen in einer Liste von IP-Adressen zu begrenzen, die in Echtzeit aktualisiert wird.Für die Konfiguration von HAProxy sind keine Vorkenntnisse erforderlich, da alle erforderlichen Schritte im Folgenden beschrieben werden.Open Source und kostenlos HAProxy ist ein leicht zugänglicher Load Balancer und Proxy-Server. In den letzten Jahren ist es sehr beliebt geworden, weil es eine hohe Leistung mit einem Minimum an Ressourcen bietet. Im Gegensatz zu alternativen Programmen bietet die gemeinnützige Version von HAProxy Community Edition genügend Funktionen für einen zuverlässigen Lastausgleich.Dieses Programm ist zunächst ziemlich schwer herauszufinden. Sie verfügt jedoch über eine sehr sorgfältige und detaillierte technische Dokumentation . Der Autor sagt, dass dies die detaillierteste Dokumentation unter allen Open-Source-Programmen ist, die er jemals verwendet hat.Hier ist eine Schritt-für-Schritt-Anleitung.Konfigurieren eines Load Balancers
Um Zeit zu sparen und sich nicht von der Einrichtung der Infrastruktur ablenken zu lassen, nehmen Sie die Docker- und Docker Compose- Images und starten Sie die Hauptkomponenten schnell.Die erste Aufgabe besteht darin, die Arbeitsinstanz des HAProxy-Load-Balancers mit mehreren Apache-Backend-Servern zu erhöhen.Klonen Sie das Repository
$ git clone git@github.com:stargazer/haproxy-ratelimiter.git
$ cd haproxy-ratelimiter
Sie können Installationsparameter anzeigen Dockerfile
und docker-compose.yml
anzeigen. Ihre Diskussion würde den Rahmen dieses Artikels sprengen. Lassen Sie uns daher auf die Tatsache eingehen, dass sie eine funktionierende HAProxy-Instanz namens loadbalancer
zwei Backend-Server api01
und erstellt haben api02
. Um HAProxy zu konfigurieren, verwenden wir zunächst die Datei haproxy-basic.cfg
und wechseln dann zu haproxy-ratelimiting.cfg
.Der Einfachheit halber wurde die Konfigurationsdatei haproxy-basic.cfg
auf das Nötigste reduziert und von Überschüssen befreit. Schauen wir es uns an:defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend proxy
bind *:80
use_backend api
backend api
balance roundrobin
server api01 api01:80
server api02 api02:80
In diesem Abschnitt wird festgelegt frontend proxy
, dass HAProxy Port 80 überwacht und alle Anforderungen an den Serverpool api
im Backend weiterleitet .KATEGORIE backend api
gibt an Backend - Pool api
mit zwei Back - End - Servern api01
und api02
und die entsprechenden Adressen. Der Server für die Bearbeitung jeder eingehenden Anforderung wird vom Lastausgleichsalgorithmus ausgewählt roundrobin
, dh die beiden verfügbaren Server werden nacheinander verwendet.Lassen Sie uns alle drei unserer Container starten
$ sudo docker-compose up
Jetzt haben wir einen Container loadbalancer
, der Anforderungen an zwei Backends api01
und Server umleitet api02
. Wir werden eine Antwort von einem von ihnen erhalten, wenn wir in die Adressleiste eingeben http://localhost/
.Es ist interessant, die Seite mehrmals zu aktualisieren und die Protokolle anzuzeigen docker-compose
.api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 09 +0000] "GET / HTTP / 1.1" 200 45
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 10 +0000] "GET / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 10 +0000] "GET / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -
api01_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -
api02_1 | 192.168.192.3 - - [08 / Jan / 2019: 11: 38: 11 +0000] "GET / HTTP / 1.1" 304 -
Wie Sie sehen können, verarbeiten zwei Server api
nacheinander Anforderungen.Wir haben jetzt eine HAProxy-Instanz mit einer sehr einfachen Lastausgleichskonfiguration und wir haben eine Vorstellung davon, wie es funktioniert.Fügen Sie ein Limit für die Anzahl der Anforderungen hinzu
Um die Anzahl der Anforderungen an den Load Balancer zu begrenzen, müssen Sie die Konfigurationsdatei in der HAProxy-Instanz ändern. Stellen Sie sicher, dass der Container loadbalancer
die Konfigurationsdatei verwendet haproxy-ratelimiter.cfg
.Ändern Sie einfach die Docker-Datei, um die Konfigurationsdatei zu ersetzen.FROM haproxy:1.7
COPY haproxy-ratelimiter.cfg /usr/local/etc/haproxy/haproxy.cfg
Grenzen setzen
Alle Einstellungen werden in der Konfigurationsdatei registriert haproxy-ratelimiter.cfg
. Lass es uns sorgfältig studieren.defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend proxy
bind *:80
# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0
# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt
use_backend api
backend api
balance roundrobin
server api01 api01:80
server api02 api02:80
backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)
HAProxy bietet eine Reihe von Grundelementen auf niedriger Ebene, die mehr Flexibilität bieten und für eine Vielzahl von Anwendungsfällen geeignet sind. Seine Zähler erinnern mich oft an das akkumulative Register (Addierer) in der CPU. Sie speichern Zwischenergebnisse, verwenden unterschiedliche Semantiken als Eingabe, aber am Ende sind sie nur Zahlen. Um alles gut zu verstehen, ist es sinnvoll, am Ende der Konfigurationsdatei zu beginnen.Tabelle Abuse
backend Abuse
stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)
Hier haben wir ein Dummy-Backend namens Abuse
("Missbrauch") eingerichtet. Fiktiv, weil es nur für Stick-Tabellen verwendet wird, auf die sich der Rest der Konfiguration mit Namen beziehen kann Abuse
. Eine Stick-Tabelle ist eine im Prozessspeicher gespeicherte Tabelle, in der Sie für jeden Datensatz die Lebensdauer bestimmen können.Unsere Tabelle hat folgende Eigenschaften:type ip
: Anfragen werden in der Tabelle nach IP-Adresse als Schlüssel gespeichert. Anfragen von derselben IP-Adresse beziehen sich daher auf denselben Datensatz. Dies bedeutet im Wesentlichen, dass wir IP-Adressen und zugehörige Daten verfolgen.
size 100K
: Die Tabelle enthält maximal 100.000 Datensätze.
expire 30m
: Die Aufbewahrungsdauer für Datensätze beträgt 30 Minuten Inaktivität.
store gpc0,http_req_rate(10s)
: Der Zähler gpc0
und die Anzahl der IP-Adressanforderungen für die letzten 10 Sekunden werden mit Einträgen gespeichert . Mithilfe der Hilfe können gpc0
wir verfolgen, wie oft die IP-Adresse bei Missbrauch bemerkt wird. Tatsächlich bedeutet ein positiver Zählerwert, dass die IP-Adresse bereits als verdächtig markiert ist. Nennen wir diesen Zähler abuse indicator
.
Im Allgemeinen Abuse
können Sie anhand der Tabelle verfolgen, ob die IP-Adresse als verdächtig markiert ist und wie häufig Anfragen von dieser Adresse aktuell sind. Daher haben wir eine Historie von Aufzeichnungen sowie Echtzeitinformationen.Fahren wir nun mit dem Abschnitt fort frontend proxy
und sehen, was dort neu ist.ACL-Funktionen und -Regeln
frontend proxy
bind *:80
# ACL function declarations
acl is_abuse src_http_req_rate(Abuse) ge 10
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
acl abuse_cnt src_get_gpc0(Abuse) gt 0
# Rules
tcp-request connection track-sc0 src table Abuse
tcp-request connection reject if abuse_cnt
http-request deny if abuse_cnt
http-request deny if is_abuse inc_abuse_cnt
use_backend api
Zugriffssteuerungslisten (Access Control Lists, ACLs) sind Funktionsdeklarationen, die nur aufgerufen werden, wenn die Regel festgelegt ist.Schauen wir uns alle drei ACL-Einträge genauer an. Beachten Sie, dass alle explizit auf eine Tabelle verweisen Abuse
, in der IP-Adressen als Schlüssel verwendet werden. Daher gilt jede Funktion für die Anforderungs-IP-Adresse:acl is_abuse src_http_req_rate(Abuse) ge 10
: Die Funktion wird is_abuse
zurückgegeben, True
wenn die aktuelle Anforderungsfrequenz größer oder gleich zehn ist.
acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0
: Die Funktion wird inc_abuse_cnt
zurückgegeben, True
wenn der Inkrementwert gpc0
größer als Null ist. Da der Anfangswert gpc0
Null ist, gibt diese Funktion immer zurück True
. Mit anderen Worten, es erhöht den Wert abuse indicator
und signalisiert im Wesentlichen Missbrauch von dieser IP-Adresse.
acl abuse_cnt src_get_gpc0(Abuse) gt 0
: Die Funktion wird abuse_cnt
zurückgegeben, True
wenn der Wert gpc0
größer als Null ist. Mit anderen Worten, er sagt, wenn diese IP-Adresse bereits bei Missbrauch entdeckt wurde.
Wie bereits erwähnt, sind ACLs einfach Deklarationen, dh Funktionsdeklarationen. Sie gelten nicht für eingehende Anforderungen, bis eine Regel ausgelöst wird.Es ist sinnvoll, die im selben Abschnitt definierten Regeln zu betrachten frontend
. Die Regeln werden nacheinander auf jede eingehende Anforderung angewendet - und führen die Funktionen über die soeben definierte ACL aus.Mal sehen, was jede Regel tut:tcp-request connection track-sc0 src table Abuse
: Fügt der Tabelle eine Abfrage hinzu Abuse
. Da der Schlüssel die IP-Adresse in der Tabelle ist, wird diese Regel zur Liste der IP-Adressen hinzugefügt.
tcp-request connection reject if abuse_cnt
: TCP-, IP- , abuse. , TCP- IP-.
http-request deny if abuse_cnt
: , IP- . IP-, abuse.
http-request deny if is_abuse inc_abuse_cnt
: , is_abuse
inc_abuse_cnt
True
. , , IP- , IP- .
Im Wesentlichen führen wir zwei Arten von Überprüfungen ein: in Echtzeit und in der Blacklist aus dem Abfrageverlauf. Die zweite Regel lehnt alle neuen TCP-Verbindungen ab, wenn die IP-Adresse bei Missbrauch festgestellt wurde. Die dritte Regel verbietet den Dienst von HTTP-Anforderungen für eine IP-Adresse aus der schwarzen Liste, unabhängig von der aktuellen Häufigkeit von Anforderungen von dieser Adresse. Die vierte Regel stellt sicher, dass HTTP-Anforderungen von einer IP-Adresse sofort abgelehnt werden, sobald der Schwellenwert für die Anforderungshäufigkeit überschritten wurde. Daher funktioniert die zweite Regel hauptsächlich bei neuen TCP-Verbindungen, die dritte und vierte bei bereits eingerichteten Verbindungen, wobei die erste eine historische Prüfung und die zweite eine Echtzeitprüfung ist.Probieren wir den Filter in Aktion aus!
Jetzt können wir unsere Container wieder zusammenbauen und starten.$ sudo docker-compose down
$ sudo docker-compose build
$ sudo docker-compose up
Der Load Balancer sollte vor den beiden Backend-Servern gestartet werden.Leiten wir unseren Browser an http://localhost/
. Wenn wir die Seite ein Dutzend Mal schnell aktualisieren, überschreiten wir den Schwellenwert von zehn Anfragen in einem Intervall von zehn Sekunden - und unsere Anfragen werden abgelehnt. Wenn wir die Seite weiterhin aktualisieren, werden neue Anforderungen sofort abgelehnt - noch bevor die TCP-Verbindung hergestellt wurde.Fragen
Warum sind maximal zehn Anfragen pro zehn Sekunden zulässig?
Die Tabelle Abuse
bestimmt http_req_rate(10s)
, dh die Häufigkeit von Anforderungen wird in einem Fenster von zehn Sekunden gemessen. Eine Funktion is_abuse
aus der ACL wird True
mit einer Anforderungsrate von ≥ 10 innerhalb des angegebenen Intervalls zurückgegeben. Missbrauch wird daher als Häufigkeit von Anfragen von zehn oder mehr Anfragen in zehn Sekunden angesehen.In diesem Artikel haben wir beispielsweise beschlossen, eine Untergrenze festzulegen, um die Überprüfung der Funktion des Begrenzers zu vereinfachen.Was ist der Unterschied zwischen den Verbindungsregeln für http-Anfragen und TCP-Anfragen?
Aus der Dokumentation :http-request: Die http-request-Anweisung definiert eine Reihe von Regeln, die auf der Netzwerkebene 7 gelten. [OSI-Modell]
Aus der Dokumentation :TCP-Anforderungsverbindung: Ausführen einer Aktion für eine eingehende Verbindung in Abhängigkeit von einer Bedingung auf der Netzwerkschicht 4
HTTP-, TCP-?
Stellen Sie sich vor, HTTP-Anforderungen an den Server senden mehrere TCP-Verbindungen von derselben IP-Adresse. Die Häufigkeit von HTTP-Anforderungen überschreitet schnell die Schwellenwerte. Dann tritt die vierte Regel in Kraft, die Anforderungen verwirft und die IP-Adresse auf die schwarze Liste setzt.Jetzt ist es durchaus möglich, dass HTTP-Verbindungen von derselben IP-Adresse offen bleiben (siehe dauerhafte HTTP-Verbindung ) und die Häufigkeit von HTTP-Anforderungen unter den Schwellenwert gefallen ist. Die dritte Regel garantiert das fortgesetzte Blockieren von HTTP-Anforderungen, da diese abuse indicator
auf dieser IP ausgelöst werden.Angenommen, nach einigen Minuten versucht dieselbe IP, TCP-Verbindungen herzustellen. Sie werden sofort gelöscht, da die zweite Regel gilt: Sie sieht die gekennzeichnete IP-Adresse und trennt die Verbindung sofort.Fazit
Zunächst kann es schwierig sein, die Begrenzung der Verarbeitungsgeschwindigkeit von Anforderungen mit HAProxy zu verstehen. Um alles richtig zu machen, benötigen Sie ein ziemlich "niedriges" Denken und eine Reihe nicht intuitiver Aktionen. Die Dokumentation in diesem Teil ist wahrscheinlich zu technisch und leidet unter dem Fehlen grundlegender Beispiele. Wir hoffen, dass dieser Leitfaden das Manko ausgleicht und allen, die diesen Weg einschlagen möchten, die Richtung zeigt.Was noch zu lesen :- Wie fehlertolerante Architektur in der Mail.ru Cloud Solutions-Plattform implementiert wird .
- Top 10 Kubernetes Tricks und Tipps .
- Unser Telegrammkanal zur digitalen Transformation .