Einen Server abriegeln und eine WAF vor Ihre Anwendung schalten

Ab der ersten Bereitstellung lässt erpc worker SSH nur von Ihrer Adresse zu und verwirft jede andere eingehende Verbindung. Eine [waf]-Tabelle stellt einen filternden Proxy vor Ihre API.
Diese Seite beschreibt ERPC CLI v0.1.0-rc.4, eine Vorabversion.

Die Firewall

Eine Bereitstellung richtet die Firewall des Servers ein, bevor die Anwendung zum ersten Mal startet:
  • SSH nur von firewall.ssh_allow und von der Adresse, von der die Bereitstellung kommt;
  • jede andere eingehende Verbindung wird verworfen, außer run.port von firewall.app_allow; bei einer Anwendung hinter einer WAF tritt der Port der WAF an dessen Stelle, und das nur dort, wo die WAF auf dem Server bereits die Regeln ausführt, die [waf] jetzt vorgibt (unten).
Jede Änderung läuft unter einem Rollback-Timer von 120 Sekunden und wird erst beibehalten, wenn eine neue Verbindung durchkommt, sodass eine fehlerhafte Änderung Sie nicht aussperren kann.
Die Allowlist überdauert allerdings die Adresse, von der aus sie erstellt wurde: Ändert sich Ihre Heimadresse, führt der Weg zurück bei einem ERPC-Server über den ERPC-Support, bei einem eigenen Server über die Konsole des Anbieters. Tragen Sie eine zweite Adresse, von der aus Sie den Server erreichen können (ein Büro, einen VPN-Ausgang), in firewall.ssh_allow ein, bevor Sie sich auf eine Heimadresse verlassen.
Wenn sich Ihre Adresse ändert, fügen Sie jede feste Adresse hinzu, die Ihre Admins verwenden:
bash
erpc worker firewall allow --to ssh 203.0.113.10 198.51.100.7
BefehlWas er tut
erpc worker firewall listZeigt, wer den Server erreichen darf: erpc.toml neben der Tabelle des Servers
erpc worker firewall allow --to ssh|app <addresses>Lässt Adressen zu und wendet das an. SSH wird von einzelnen Adressen zugelassen; ein Netz wird nur mit --to app akzeptiert
erpc worker firewall deny --to ssh|app <addresses>Lässt sie nicht mehr zu
erpc worker firewall syncBringt die Firewall des Servers wieder auf den Stand, den erpc.toml angibt

Eine WAF vor Ihre Anwendung schalten

Fügen Sie erpc.toml eine Tabelle hinzu:
toml
[waf]
port = 8080
erpc worker deploy betreibt dann auf dem Server einen HTTP-Reverse-Proxy in einer eigenen systemd-Unit (erpc-waf-<app>-<env>): als unprivilegierter dynamischer Benutzer ohne Schlüssel, ohne Secret und ohne irgendetwas vom Worker, begrenzt auf 1 GiB Arbeitsspeicher. Er lauscht auf waf.port, liest jede Anfrage, bevor die Anwendung sie liest, lehnt ab, was seine Regeln benennen, und leitet den Rest an die Anwendung auf 127.0.0.1:<run.port> weiter.
  • Die Anwendung bleibt auf dem Loopback. Ihr eigener Port wird nie von außen geöffnet. erpc worker api und der Health-Check erreichen die Anwendung über den Loopback, an der WAF vorbei.
  • Wer sich verbinden darf, bestimmt weiterhin die Liste der Firewall, und der Port der WAF ist die einzige Stelle, an der diese Liste alle zulassen darf:
    sh
    erpc worker firewall allow --to app 0.0.0.0/0     # and ::/0
    Ist niemand eingetragen, lauscht die WAF und niemand wird hereingelassen, und die Bereitstellung meldet das.
  • Der Port wird geöffnet, sobald die WAF auf ihm lauscht, nie vorher. Eine Bereitstellung, deren WAF nicht hochkommt, schlägt fehl und nennt den Grund, während die Anwendung weiterläuft.
  • Wenn Sie [waf] ändern, wird der Port für niemanden Neues geöffnet, bis eine Bereitstellung die neuen Regeln eingesetzt hat.
  • Wenn Sie [waf] aus erpc.toml entfernen und bereitstellen, wird die WAF vom Server entfernt.

WAF-Einstellungen

Nur port ist erforderlich. Alle Schlüssel mit ihren Standardwerten:
toml
[waf]
port = 8080          # the public port, 1024 or above; the app keeps [run] port
methods = ["GET", "POST", "PUT", "DELETE"]
allow_paths = []     # every path
deny_paths = []
max_body_bytes = 1048576
max_header_bytes = 16384
rate = { per_second = 50, burst = 100 }
max_connections_per_address = 32
ban = { after = 100, window_secs = 60, for_secs = 600 }
block_probes = true
header_timeout_secs = 10
body_timeout_secs = 30
upstream_timeout_secs = 30
new_connections = { per_second = 50, burst = 100 }
SchlüsselWas er tutWas abgelehnt wird, erhält
methodsDie weitergeleiteten Methoden, in Großbuchstaben (höchstens 16; nie CONNECT)405, mit Allow
allow_pathsDie weitergeleiteten Pfade; ist keiner eingetragen, gilt jeder Pfad. Ein Muster ist ein einzelner Pfad oder, wenn es auf * endet, alles unter einem Präfix: /api/* ist /api und alles darunter. Verglichen wird mit dem Pfad nach einmaliger Prozent-Dekodierung, unter Beachtung der Groß- und Kleinschreibung404
deny_pathsAbgelehnte Pfade, genauso geschrieben und zuerst geprüft403
max_body_bytesDer größte Anfrage-Body, bis zu 64 MiB413
max_header_bytesDie größte Anfragezeile samt Headern, 1024 bis 65536431
rateAnfragen pro Sekunde von einer Adresse, und wie viele auf einmal, bevor die Rate greift429, mit Retry-After
max_connections_per_addressVerbindungen, die eine Adresse gleichzeitig hältDie Verbindung wird ohne Antwort geschlossen
banNach after blockierten Anfragen innerhalb von window_secs wird die Adresse für for_secs abgelehnt (bis zu 30 Tage)Ihre Verbindungen werden ohne Antwort geschlossen
block_probesLehnt ab, was Scanner anfragen (/.env, /.git, /wp-login.php und Ähnliches)403
header_timeout_secsWie viel Zeit ein Client hat, um den Kopf einer Anfrage zu senden, 1 bis 120. Auch wie lange auf einen Client gewartet wird, der mitten in einem Body stehen geblieben ist oder aufgehört hat, seine Antwort abzunehmen408 für den Kopf; 400 für einen abgebrochenen Body; bei einer nicht abgenommenen Antwort wird die Verbindung geschlossen
body_timeout_secsWie lange der Body einer Anfrage insgesamt dauern darf, 1 bis 600, ohne die Zeit, in der die WAF auf die Anwendung wartet408
upstream_timeout_secsWie viel Zeit die Anwendung hat, um die Verbindung anzunehmen und mit der Antwort zu beginnen, 1 bis 600504; 502, wenn die Anwendung nicht lauscht
new_connectionsDas eigene Limit der Firewall für neue TCP-Verbindungen pro Sekunde von einer Adresse zum Port der WAF; nftables verwirft sie, bevor der Proxy sie sieht. Solange die Adressmenge von nftables voll ist, wird eine Adresse, die nicht darin steht, nicht gezählt, sodass dieses Limit für sie nicht gilt, bis die Menge wieder Platz hat; die eigenen Limits des Proxys (rate, max_connections_per_address, ban) gelten weiterhinDas Paket wird verworfen
rate, max_connections_per_address, ban und new_connections werden mit false ausgeschaltet (ban = false), und ein weggelassener Schlüssel hat seinen Standardwert. erpc worker check sagt vor jeder Bereitstellung, was die [waf]-Tabelle tun wird und was an ihr falsch ist.

Was die WAF ohne Einstellung tut

  • Eine Anfrage, die sich nicht als eine eindeutige HTTP/1-Anfrage lesen lässt, erhält 400, ebenso ein Pfad, der nicht in Normalform ist.
  • Eine Anfrage zum Protokollwechsel (Upgrade) erhält 501.
  • Jede Ablehnung wird auf den Bann angerechnet, und jede Ablehnung beendet ihre Verbindung.
  • Eine Adresse ist eine IPv4-Adresse oder ein IPv6-/64.
  • Die WAF leitet nicht weiter: die Header, die zur Verbindung des Clients mit dem Proxy gehören (Connection und die darin genannten Header, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, TE, Trailer), Expect, Header mit einem Unterstrich im Namen sowie die vom Client selbst gesendeten Forwarded, X-Real-IP und X-Forwarded-Proto. Sie setzt X-Real-IP auf die Adresse, von der die Verbindung kam, und hängt diese Adresse an das Ende von X-Forwarded-For an; nur der letzte Eintrag von X-Forwarded-For ist die Angabe des Proxys.

Sehen, was die WAF tut

BefehlZeigt
erpc worker statusDen Port der WAF, wohin sie weiterleitet, seit wann, und die Zählerstände seitdem
erpc worker firewall listWer den Port der WAF erreichen darf und was blockiert wurde, nach Regel
erpc worker logs --wafJede blockierte Anfrage: die Regel, den Status, die Adresse des Clients, die Methode und die ersten 200 Bytes des Ziels
Eine weitergeleitete Anfrage hinterlässt keine Logzeile, und kein Header oder Body wird je geloggt; die Query einer blockierten Anfrage schon, soweit die 200 Bytes reichen. Was ein Client sendet, kann nicht in Ihr Terminal schreiben: Die WAF schreibt ihr Journal als druckbares ASCII.

Was die WAF nicht tut

  • Kein TLS. Sie spricht auf ihrem Port reines HTTP/1.1.
  • Kein HTTP/2: Darauf antwortet sie mit 400.
  • Kein WebSocket, auch kein anderes Upgrade: 501.
  • Kein Blick in Bodies. Ein Body wird gemessen, nie gelesen. Die Liste der Scanner-Anfragen ist kurz und ein Rauschfilter, keine Garantie: Die Anwendung prüft ihre Eingaben weiterhin.
  • Keine Authentifizierung. Wer die Anwendung aufrufen darf, entscheiden die Anwendung und die Liste der Firewall.
  • Eine Adresse ist ein Client. Clients hinter demselben NAT, Proxy oder CDN teilen sich eine Rate und einen Bann; ein Client mit vielen Adressen hat entsprechend viele Raten.
  • Banne und Zählerstände werden vergessen, wenn die WAF neu startet.
  • Sie merkt sich höchstens 8192 Adressen und hält höchstens 1024 Verbindungen gleichzeitig.
  • Sie lauscht nur auf IPv4, daher erreicht ein IPv6-Eintrag in app_allow noch nichts.
  • Ein Pfad wird als die Bytes verglichen, zu denen er dekodiert. Eine Anwendung, die Pfade lockerer liest (Groß- und Kleinschreibung ignoriert, ;-Parameter, doppelte Dekodierung), kann unter einem Namen erreicht werden, den deny_paths nicht abdeckt. allow_paths hat keine solche Lücke: Was nicht eingetragen ist, wird nicht weitergeleitet.
  • Ein langsamer Leser wird bis zum Ende bedient. Ein Client, der eine Antwort weiter abnimmt, wie langsam auch immer, wird bis zum Ende bedient.
  • Eine Flut kann einen großen Upload abbrechen. Die WAF läuft auf einem einzigen Thread, daher kann eine Flut einen großen Upload mit 408 abbrechen. Eine Anwendung, die große Bodies annimmt, erhöht body_timeout_secs zusammen mit max_body_bytes.
Der Worker-Leitfaden enthält jede Regel, auch wann eine Änderung an app_allow bis zur nächsten Bereitstellung zurückgehalten wird.