Blocken mit dem Linux-Agenten
Der Community-Feed im Kernel und die Adressen, die dieser Host selbst sperrt: die zwei Arten von Set und ihre Lebensdauern, wie eine lokale Sperre entsteht und endet, die Eskalation mit echten Zahlen, die Kette im Kernel, die zwei Schalter mode und ban.enabled, und wie eine Sperre oder alles aufgehoben wird.
Der Community-Feed
Das ist der Teil, den die Seite Blockierung auf Netzwerkebene als Shell-Skript beschreibt. Der Agent macht dasselbe, und die Teile, die man beim Selberschreiben leicht falsch macht, sind schon erledigt: ein bedingter Abruf pro Liste, damit eine unveränderte Liste nichts kostet, eine Größenprüfung, bevor etwas live geht, ein atomarer Tausch, damit es nie ein Zeitfenster mit leerem Set gibt, und portgebundene Regeln, damit ein Web-Angreifer niemanden von SSH aussperrt.
| Liste | Kernel-Set | Ports, auf die die Regel greift |
|---|---|---|
ssh | rip-ssh, rip-ssh-v6 | aus lists.ssh.ports |
mail | rip-mail, rip-mail-v6 | 25, 465, 587, 110, 995, 143, 993 |
web | rip-web, rip-web-v6 | 80, 443 |
ftp | rip-ftp, rip-ftp-v6 | 21 |
edge | rip-edge, rip-edge-v6 | jeden Port, mit Absicht |
group | rip-group, rip-group-v6 | jeden Port, siehe unten |
Wie oft der Feed geholt wird, hängt von Ihrem Tarif ab, und das entscheidet der Server,
nicht der Agent. Auf einem lizenzierten Server ist das Intervall ab Professional alle
15 Minuten bei einer Mindest-Confidence von 75, auf Contributor stündlich bei 90. Business
und Enterprise verhalten sich wie Professional. Der Agent fragt, welche Werte für diesen Host
gelten, und folgt der Antwort. Ein Upgrade wirkt also, ohne dass jemand eine Datei bearbeitet. Die
Antwort wird bis zu 24 Stunden zwischengespeichert, nur ein offener Zustand api_key,
license oder reputation lässt ihn bei jedem Durchlauf neu fragen. Ein
Tarifwechsel kommt also spätestens nach einem Tag auf dem Host an. Es gibt keinen Konfigurationsschlüssel für das Intervall, und ein Schlüssel, den Sie
dafür erfinden, beendet den Agenten mit Exit 2.
Darüber liegen zwei weitere Regeln. Eine Liste, die vor weniger als 15 Minuten geholt wurde, wird
nicht erneut geholt, denn so lange hält der Server sie im Cache. sync von Hand zu
starten ist damit immer erlaubt und nie schädlich. Und jeder Abruf ist bedingt: eine unveränderte
Liste antwortet mit 304 und kostet eine Anfrage und keine Übertragung, und deshalb ist ein kurzes
Intervall für beide Seiten günstig.
Die Gruppenliste
Ein Key in einer Gruppe erhält eine sechste Liste, als json mit dem Community-Feed abgerufen. Jede
Adresse wird auf jedem Port in den Sets rip-group und rip-group-v6
verworfen, unabhängig davon, welchen Dienst dieser Host anbietet. Ein Key in keiner Gruppe ändert
nichts: das Set bleibt leer, und status zeigt group=none.
Die Whitelist der Gruppe, sofern sie eine trägt, wird in derselben Anfrage gelesen und nach
/var/lib/reportedip-agent/group-whitelist geschrieben, im Format von
whitelist.conf mit jeder Notiz als Kommentar. Bearbeiten Sie diese Datei nicht von
Hand, der nächste Sync schreibt sie neu. Sie wird im selben Sync-Lauf an allen drei Stellen
angewendet, an denen eine Whitelist wirkt: im Kernel-Whitelist-Set, im Filter jeder Liste und im
Report-Gate des Watchers, eine weitere Ebene neben der eigenen whitelist.conf dieses
Hosts und seiner Auto-Whitelist. Ein Key, der seine Gruppe verlässt, verliert die Datei mit dem
nächsten Sync.
whitelist list und status zeigen die Einträge der Gruppe auf Zeilen, die
mit group: markiert sind, samt Notiz. status nennt außerdem die Gruppe und
ihre Größe neben der Kontozeile und zeigt die Anzahl der Einträge der Gruppenliste unter den Listen
wie bei jeder anderen. Siehe Gruppen für das, was eine Gruppe ist, die
Tarifgrenzen, die Whitelist und den Webhook auf der Portalseite.
Blocken
Der Agent schreibt zwei sehr verschiedene Dinge in den Kernel, und wer von fail2ban kommt, verwechselt sie in der ersten Woche meistens. Sie haben verschiedene Quellen, verschiedene Lebensdauern und verschiedene Schalter, es lohnt sich also, das einmal richtig zu trennen.
Zwei Arten von Set, zwei Lebensdauern
| Community-Blacklist | Lokale Funde | |
|---|---|---|
| Sets | rip-ssh, rip-mail, rip-web, rip-ftp, rip-edge, rip-group, und je ein -v6-Set dazu | rip-local und rip-local-v6 |
| Woher die Adressen kommen | Von jedem Melder der Community, gefiltert über Ihr confidence | Nur aus den eigenen Logs dieses Hosts |
| Wie ein Eintrag hineinkommt | Das ganze Set wird bei jedem Feed-Durchlauf ersetzt | Jeweils eine Adresse, wenn ein Schwellwert erreicht ist |
| Wie ein Eintrag verschwindet | Mit dem nächsten Tausch, wenn der Feed sie nicht mehr führt | Der Kernel lässt ihn ablaufen, wenn sein eigenes Timeout um ist |
| Timeout pro Eintrag | keines | ja, das ist das ganze Konzept |
| Schalter | mode | ban.enabled, und mode darüber |
| Braucht eine Lizenz | ja, das ist der bezahlte Teil | nein |
Wie eine lokale Sperre entsteht und wie sie endet
Eine Sperre entsteht, wenn der Zähler eines Detektors für eine Adresse den Schwellwert ihrer Ereignisquelle überschreitet. Was dann passiert, in dieser Reihenfolge:
- Die Whitelist wird zuerst geprüft, bevor überhaupt etwas anderes gefragt wird. Eine Adresse auf
der Whitelist hinterlässt gar keine Spur, Sie finden also Ihren eigenen Management-Bereich nie in
reportedip-agent ban listund fragen sich, ob er geblockt war. Die Prüfung sagt, welche Schicht gegriffen hat: ein eingebauter reservierter Bereich, eine der eigenen Adressen dieses Hosts, oder Ihre Datei. - Der Bann-Speicher,
/var/lib/reportedip-agent/bans.json, wird nach der Sperrzeit gefragt. Er hält die Adresse, wann die Sperre abläuft, wie viele Sperren ins Gedächtnisfenster fielen, wann die letzte begann, die Quelle und die Kategorien. Die Datei wird vor dem Kernel-Eintrag geschrieben, ein Absturz direkt nach dem Kernel-Schreiben kann also nicht den Datensatz verlieren, der die Sperre wieder aufhebt. - Die Adresse kommt mit dieser Zeit als Timeout pro Eintrag in
rip-local. Der Kernel lässt sie ablaufen. Es gibt keinen Aufräum-Timer, keinen Cronjob und keine Entsperr-Warteschlange, und genau deshalb hinterlässt ein abgestürzter oder entfernter Agent keine dauerhafte Sperre. - Eine Zeile geht ins Log, mit der Adresse, der Sperrzeit, der Quelle, der Zahl der Sperren dieser Adresse im Fenster, dem Abstand zwischen Logzeile und Kernel-Eintrag und den zwei Befehlen, mit denen man das rückgängig macht.
Eine laufende Sperre wird nie verkürzt. Kommt ein neuer Treffer für eine Adresse, die schon gesperrt
ist, passiert nichts: es ist auch keine Eskalation, denn die Eskalation zählt Sperren und nicht
Treffer, genau wie das Recidive-Jail, das sie ersetzt. Eine Adresse, die schon geblockt ist, kann
nicht noch einmal geblockt werden. Diese Regel hält auch die Übergangszeit sauber, in der der Agent
einen Angriff zweimal sieht, einmal als rohe Zeile aus auth.log und einmal als
Bann-Zeile aus fail2ban.log.
Eine nachgespielte Logzeile erzeugt ebenfalls keine Sperre. Ein Treffer, dessen Zeitstempel nicht neuer ist als die letzte Sperre dieser Adresse, ist ein Replay nach einem harten Stopp und kein neues Vergehen, und der Meldepfad hat denselben Schutz in seiner Dedup-Datei.
Der Zustand überlebt mehr als einen Neustart. Mit ban.enabled: true vergleicht jeder
Sync-Lauf bans.json mit dem, was der Kernel wirklich hält, und stellt das Fehlende mit der Restzeit wieder her:
- Nach einem Reboot sind das alle, denn weder ein ipset-Timeout noch das Set selbst
überlebt einen Reboot. Deshalb ist der Sync-Dienst für
multi-user.targetaktiviert und läuft nach jedem Firewall-Dienst. - Im normalen Betrieb sind es die Einträge, die etwas aus dem Set entfernt hat: ein
firewall-cmd --reload, eincsf -r, einipset flush. Einträge, die der Kernel noch hat, bleiben unangetastet, die Lücke ist also ein Teil eines Sync-Intervalls und nicht der Rest der Sperre. Das Log sagt ausdrücklich, wenn Einträge unter laufenden Sperren fehlten, denn das heißt, dass etwas das Set unter dem Agenten bearbeitet hat. - Ein abgelaufener Datensatz kommt nie zurück. Der Angreifer von gestern ist kein Grund, heute jemanden abzuschneiden.
- Die Whitelist wird bei jeder Wiederherstellung neu geprüft. Sie kann gewachsen sein, während der Host außer Betrieb war, und eine Adresse, die Sie gestern auf die Whitelist gesetzt haben, darf nicht durch einen Datensatz vom Vortag wieder geblockt werden.
Eskalation, mit echten Zahlen
Die erste Sperre dauert time_minutes. Jede Wiederholung innerhalb des
Gedächtnisfensters multipliziert sie mit escalate, und max_time_minutes
deckelt sie. Mit den Standardwerten (30 Minuten, Multiplikator 4, Obergrenze eine Woche) geht eine
Adresse, die immer wiederkommt, so:
| Sperre | Rechnung | Dauer |
|---|---|---|
| 1. | time_minutes | 30 Minuten |
| 2. | 30 × 4 | 2 Stunden |
| 3. | 120 × 4 | 8 Stunden |
| 4. | 480 × 4 | 32 Stunden |
| 5. | 1920 × 4 | 128 Stunden, fünf Tage und acht Stunden |
| 6. und weiter | wären 512 Stunden, gedeckelt | 7 Tage, der Wert von max_time_minutes |
Die Kette im Kernel
Mit dem ipset-Backend besitzt der Agent genau eine Kette, rip-blacklist, und einen
Sprung dorthin. Ein Sync baut die Kette neu, sobald ihr Fingerabdruck (Config und Kette, wie der
Kernel sie ausgibt) abweicht, ihr Inhalt ist also immer das, was die Config sagt. Sonst lässt er die
Kette stehen, damit die Paketzähler weiterzählen. Der Sprung wird nur an Position 1 von
INPUT eingefügt, wenn er nicht schon da ist.
# What a sync builds, in this order:
iptables -N rip-blacklist
iptables -F rip-blacklist
iptables -A rip-blacklist -m set --match-set rip-whitelist src -j RETURN
iptables -A rip-blacklist -m set --match-set rip-local src -j DROP
iptables -A rip-blacklist -p tcp --dport 22 \
-m set --match-set rip-ssh src -j DROP
iptables -A rip-blacklist -p tcp -m multiport --dports 25,465,587,110,995,143,993 \
-m set --match-set rip-mail src -j DROP
iptables -A rip-blacklist -p tcp -m multiport --dports 80,443 \
-m set --match-set rip-web src -j DROP
iptables -A rip-blacklist -m set --match-set rip-edge src -j DROP
iptables -A rip-blacklist -m set --match-set rip-group src -j DROP
# Only with a scan source in the config: a SYN to a port this host
# does not listen on is logged, at most ten a minute. Listening ports
# and the passive range of a running FTP server return first, then any
# port a socket listens on at this very moment.
iptables -N rip-blacklist-scan
iptables -A rip-blacklist-scan -p tcp -m multiport --dports 21,22,25,80,443,40110:40210 -j RETURN
iptables -A rip-blacklist-scan -p tcp -m socket --nowildcard -j RETURN
iptables -A rip-blacklist-scan -m limit --limit 10/min --limit-burst 20 \
-j LOG --log-prefix "rip-scan: "
iptables -A rip-blacklist -p tcp --syn -j rip-blacklist-scan
iptables -I INPUT 1 -j rip-blacklist
Die Whitelist ist die erste Regel und springt zurück, sie ist nicht die letzte Regel.
Ein RETURN vor allem anderen heißt, dass eine Adresse auf der Whitelist die Kette
verlässt, bevor irgendein Set befragt wird, sie steht also über jeder Sperre, auch über einer, die
schon in rip-local liegt. Das macht whitelist add zu einem funktionierenden
Weg aus einer Aussperrung, ohne Sync und ohne Neustart. Eine Whitelist am Ende wäre eine Liste von
Ausnahmen, die zu spät kommen, und auf einem Host, auf dem Sie sich ausgesperrt haben, ist „zu spät“
das ganze Problem.
Die Regel für lokale Sperren hat keine Portbindung, denn ein Host, der Ihren
Mailserver angegriffen hat, hat auf Port 22 auch nichts zu suchen. Die Regeln für ssh,
mail, web und ftp sind portgebunden, eine Adresse auf der Web-Liste wird also auf 80 und 443 verworfen und erreicht SSH
weiterhin. Das ist Absicht: eine geteilte Adresse, ein Carrier-NAT oder ein übernommener Proxy auf der
Web-Liste darf keinen Administrator von der Maschine aussperren. Nur edge und group greifen
auf jeden Port: bei edge ist das die Bedeutung der Kategorie dahinter, bei
group der Sinn einer geteilten Sperre.
Mit dem nftables-Backend ist die Form dieselbe, nur nativ: eine Tabelle inet reportedip,
eine Kette, die mit Priorität -10 und Policy accept in input hängt, zuerst die zwei
return-Regeln der Whitelist, dann rip-local, dann die Feed-Listen mit ihren
Portbindungen. Die Whitelist-Sets sind Intervall-Sets, damit sie CIDR-Bereiche halten können; die
lokalen Sets tragen das Timeout-Flag, das beide Werkzeuge am Set verlangen, bevor ein Element
überhaupt ein Timeout tragen darf.
In mode: log werden dieselben Regeln gebaut, und das Urteil ist eine ratenbegrenzte
Logzeile (sechs pro Minute, mit dem Präfix rip-<list>:) statt
DROP. Alles andere ist gleich, und deshalb ist der Log-Modus eine echte Probe und keine
Simulation.
mode und ban.enabled sind zwei Schalter
Das ist das häufigste Missverständnis, es bekommt also seinen eigenen Absatz. mode
entscheidet, was die Regeln tun. ban.enabled entscheidet, ob Ihre eigenen Funde
überhaupt je ein Eintrag werden. Ab Werk sind beide an (mode: drop,
ban.enabled: true). Wer ban.enabled: false setzt, hat mit
mode: drop die Community-Liste durchgesetzt und von seinen eigenen Funden nichts.
mode | ban.enabled | Community-Liste | Ihre eigenen Funde |
|---|---|---|---|
log | false | Greift und loggt, nichts wird verworfen | Werden an die Community gemeldet, lokal nicht geblockt |
log | true | Greift und loggt | Werden in rip-local erfasst und sind in ban list sichtbar, geloggt statt verworfen |
drop | false | Wird verworfen | Nur gemeldet. Das ist ein völlig sinnvoller Dauerzustand. |
drop | true | Wird verworfen | Wird ebenfalls verworfen, mit Eskalation. Die vollständige Konfiguration. |
off | egal | Nichts im Paketpfad: der Sprung wird entfernt; bei ipset bleibt die Kette mit ihren Regeln, bei nftables wird die Kette gelöscht | Im Speicher erfasst, ohne Wirkung |
off ist der Notschalter und ist darin ehrlich. Es entfernt, was die Kette in den
Paketpfad hängt, bis zu fünfmal, um doppelte Sprünge zu erwischen, und bricht laut ab, wenn ein
Sprung überlebt, denn „off“ zu sagen und weiter zu verwerfen ist schlimmer als ein Fehler. Bei
nftables wird die Kette selbst gelöscht. Die Sets behalten in beiden Backends ihre Einträge, ein
Zurückschalten braucht also keinen vollen Download.
Eine Sperre von Hand ignoriert beide Schalter mit Absicht: reportedip-agent ban add
funktioniert auch bei ban.enabled: false, denn das ist eine bewusste Handlung eines
Operators, so wie fail2ban-client set banip es war. Die Whitelist gilt weiterhin, und
auf einem Host ohne Firewall-Backend verweigert der Befehl den Dienst.
Von log auf drop wechseln
# 1. What would have been dropped? The rules already match in
# log mode, so ask the kernel log.
journalctl -k --since "24 hours ago" | grep -c "rip-"
journalctl -k --since "24 hours ago" | grep -o "rip-[a-z]*:" | sort | uniq -c
# 2. Is anything of yours in there? Check every source address
# against your whitelist before you switch.
reportedip-agent whitelist list
# 3. Switch, and rebuild the rules.
sed -i "s/^mode: log/mode: drop/" /etc/reportedip-agent/config.yaml
reportedip-agent sync
reportedip-agent status
# 4. Only now the second switch, if you want it.
# ban.enabled: true, then restart the daemon.
systemctl restart reportedip-agent.service
reportedip-agent ban list
Nachsehen, was wirklich im Kernel steht
reportedip-agent status ist die Zusammenfassung, und es liest sowohl die State-Dateien
als auch den laufenden Kernel, damit man beides vergleichen kann. Wo die zwei sich widersprechen, ist
der Kernel die Wahrheit, und status sagt das: ein Datensatz ohne Kernel-Eintrag ist eine Sperre, die
nicht wirkt.
# The agent's own view
reportedip-agent status
reportedip-agent ban list
# ipset backend, straight from the kernel
ipset list -t rip-ssh # header and entry count only
ipset list rip-local # entries, each with its timeout
iptables -S rip-blacklist
iptables -L INPUT -n --line-numbers | head
# nftables backend
nft list table inet reportedip
nft list set inet reportedip rip-local
In ban list ist die Spalte kernel das, was der Kernel noch auf der Uhr hat,
und record das, was bans.json erwartet. Ein Strich unter
kernel neben einem laufenden Datensatz heißt, die Sperre wirkt nicht und der nächste
Sync stellt sie wieder her. Eine Zeile, deren Datensatz none sagt, existiert nur im
Kernel, also hat jemand ipset oder nft von Hand benutzt, oder der Speicher
ist verloren gegangen: sie läuft trotzdem ab, aber kein Reboot bringt sie zurück.
Eine Sperre aufheben, und alles zurückbauen
reportedip-agent whitelist add <address> wirkt also sofort und
steht über jeder Sperre, auch über einer, die schon im Set liegt. Der Befehl schreibt die Datei
und das laufende Kernel-Set in einem Schritt und braucht weder Sync noch Neustart.
# Lift one ban and forget its history. The next detection starts
# from a first offence rather than escalating on top of a verdict
# you disagreed with.
reportedip-agent unban 203.0.113.45
# Never ban and never report this address or range, from now on.
reportedip-agent whitelist add 203.0.113.0/24 "customer office"
# Ban by hand. Works even with ban.enabled: false. A time given
# here is the time, not the first step of an escalation.
reportedip-agent ban add 203.0.113.45
reportedip-agent ban add 203.0.113.45 1440
# Stop blocking without uninstalling: no jump, the sets keep their entries.
sed -i "s/^mode: .*/mode: off/" /etc/reportedip-agent/config.yaml
reportedip-agent sync
# Remove the agent from the packet path completely (ipset backend).
iptables -D INPUT -j rip-blacklist; iptables -F rip-blacklist; iptables -X rip-blacklist
ip6tables -D INPUT -j rip-blacklist; ip6tables -F rip-blacklist; ip6tables -X rip-blacklist
for s in $(ipset list -n | grep "^rip-"); do ipset destroy "$s"; done
# nftables backend
nft delete table inet reportedip
unban und whitelist add nehmen beide das Sync-Lock, der
Wiederherstellungsschritt eines laufenden Syncs kann also nicht zurücklegen, was Sie gerade aufheben.
Einen Eintrag aus der Whitelist-Datei zu entfernen ist der eine Vorgang, der nicht sofort wirkt: er
greift mit dem nächsten Sync-Neubau, und eine Ausnahme zu entfernen muss nie sofort passieren.
rip--Set verweisen.
iptables-restore verwirft die ganze Datei, sobald es auf ein unbekanntes Set trifft,
eine übrig gebliebene Zeile in /etc/iptables/rules.v4 kann Ihnen also beim nächsten
Boot die komplette Firewall nehmen. Der Agent baut seine Kette bei jedem Boot selbst auf und
braucht nichts Gespeichertes. status warnt, wenn es rip- in
rules.v4, rules.v6, /etc/sysconfig/iptables,
ip6tables oder /etc/nftables.conf findet. In
/etc/nftables.d sieht es nicht nach.
Zuletzt aktualisiert: · Betreut vom ReportedIP-Team