745 lines
48 KiB
Markdown
745 lines
48 KiB
Markdown
# Защита хоста с помощью CrowdSec
|
||
|
||
Вы наверняка использовали (или как минимум слышали) о Fail2Ban. Он очень широко распространён для защиты SSH на хостах,
|
||
противодействия сканированию сайтов, легких DDoS-атак и "фонового bot-трафика". Fail2Ban существует с 2004 года
|
||
и давно стал стандартом для защиты серверов. Но он слабо подходит для защиты кластеров Kubernetes, так поды
|
||
обслуживающие внешний трафик (Ingress-контроллеры Traefik в случае k3s) могут находиться на разных узлах кластера.
|
||
Если Fail2Ban заблокирует IP-адрес на одной ноде, то он не сможет защитить другие узлы кластера, так как они ничего
|
||
не узнают о блокировках.
|
||
|
||
Для защиты распределённых систем (в том числе кластеров Kubernetes) набирает популярность CrowdSec. Это проект
|
||
с открытым исходным кодом, который, кроме обмена информацией об атаках между узлами (за периметром), использует
|
||
и внешний краудсорсинг (Community Blocklist) для защиты от атак. Он собирает данные о блокировках и позволяет
|
||
обмениваться этой информацией между всеми участниками сети (это отключаемая опция, и по умолчанию она отключена).
|
||
Таким образом, CrowdSec может не только защитить все узлы кластера (благодаря обмену информацией за периметром),
|
||
о блокировать IP-адреса, еще до их атаки на ваш сервер (если данные IP уже заблокированы другими участниками CrowdSec).
|
||
А еще CrowdSec модульный, поддерживает сценарии (http-cms-scanning, sshd-bf и тому-подобное),в 60 раз быстрее
|
||
Fail2Ban (он написан на Golang), работает с IPv6 и имеет интеграции с Traefik, Cloudflare, Nginx, k3s, Docker и другими
|
||
инструментами. CrowdSec активно растёт в нише DevOps, облаков, контейнеров и кластеров Kubernetes. А еще он не
|
||
требовательный по ресурсам (~100 МБ RAM) и подходит для Orange Pi.
|
||
|
||
----
|
||
## Утановка CrowdSec
|
||
|
||
В принципе, СrowdSec можно установить в кластер через Helm. Тогда он сам развернется на всех узлах кластера и это
|
||
отличный вариант для защиты Traefik (HTTP-запросы, сценарии http-cms-scanning, http-probing) и контейнеризированных
|
||
приложений (в моем случае [Gitea](../kubernetes/k3s-migrating-container-from-docker-to-kubernetes.md), [3x-ui](../kubernetes/k3s-3xui-pod.md)
|
||
и тому подобного). Но мне нужно защитить еще и SSH самих узлов (узла) кластера. Поэтому план такой:
|
||
|
||
* Хостовый CrowdSec (на одном или всех узлах кластера) использует тот же Local API (LAPI) через виртуальный IP (VIP)
|
||
Keepalived для получения бан-листа и применяет его к SSH (через Firewall Bouncer) и через тот же LAPI сообщает
|
||
о банах ssh-bt в CrowdSec Agent внутри k3s.
|
||
* Кластерный CrowdSec Agent, внутри k3s, анализирует логи Traefik и создаёт решения (decisions) о бане IP.
|
||
* Traefik Bouncer в k3s, также подключается к LAPI для защиты HTTP (для git.cube2.ru и других web-приложений).
|
||
|
||
----
|
||
### CrowdSec на первом узле и защита SSH на хосте
|
||
|
||
----
|
||
#### Подготовка к установке CrowdSec
|
||
|
||
Делаем обновляем список пактов и систему:
|
||
```shell
|
||
sudo apt update
|
||
sudo apt upgrade
|
||
```
|
||
|
||
Добавляем репозиторий CrowdSec и ключи репозитория:
|
||
```shell
|
||
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
|
||
```
|
||
|
||
----
|
||
#### Установка CrowdSec и проверка
|
||
|
||
Устанавливаем CrowdSec:
|
||
```shell
|
||
sudo apt install crowdsec
|
||
```
|
||
|
||
Увидим, в число прочего:
|
||
```text
|
||
...
|
||
...
|
||
reating /etc/crowdsec/acquis.yaml
|
||
INFO[2025-xx-xx xx:xx:xx] crowdsec_wizard: service 'ssh': /var/log/auth.log
|
||
INFO[2025-xx-xx xx:xx:xx] crowdsec_wizard: using journald for 'smb'
|
||
INFO[2025-xx-xx xx:xx:xx] crowdsec_wizard: service 'linux': /var/log/syslog /var/log/kern.log
|
||
Machine 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' successfully added to the local API.
|
||
API credentials written to '/etc/crowdsec/local_api_credentials.yaml'.
|
||
Updating hub
|
||
Downloading /etc/crowdsec/hub/.index.json
|
||
Action plan:
|
||
🔄 check & update data files
|
||
|
||
|
||
INFO[2025-05-17 17:56:45] crowdsec_wizard: Installing collection 'crowdsecurity/linux'
|
||
downloading parsers:crowdsecurity/syslog-logs
|
||
downloading parsers:crowdsecurity/geoip-enrich
|
||
downloading https://hub-data.crowdsec.net/mmdb_update/GeoLite2-City.mmdb
|
||
downloading https://hub-data.crowdsec.net/mmdb_update/GeoLite2-ASN.mmdb
|
||
downloading parsers:crowdsecurity/dateparse-enrich
|
||
downloading parsers:crowdsecurity/sshd-logs
|
||
downloading scenarios:crowdsecurity/ssh-bf
|
||
downloading scenarios:crowdsecurity/ssh-slow-bf
|
||
downloading scenarios:crowdsecurity/ssh-cve-2024-6387
|
||
downloading scenarios:crowdsecurity/ssh-refused-conn
|
||
downloading contexts:crowdsecurity/bf_base
|
||
downloading collections:crowdsecurity/sshd
|
||
downloading collections:crowdsecurity/linux
|
||
enabling parsers:crowdsecurity/syslog-logs
|
||
enabling parsers:crowdsecurity/geoip-enrich
|
||
enabling parsers:crowdsecurity/dateparse-enrich
|
||
enabling parsers:crowdsecurity/sshd-logs
|
||
enabling scenarios:crowdsecurity/ssh-bf
|
||
enabling scenarios:crowdsecurity/ssh-slow-bf
|
||
enabling scenarios:crowdsecurity/ssh-cve-2024-6387
|
||
enabling scenarios:crowdsecurity/ssh-refused-conn
|
||
enabling contexts:crowdsecurity/bf_base
|
||
enabling collections:crowdsecurity/sshd
|
||
enabling collections:crowdsecurity/linux
|
||
...
|
||
...
|
||
```
|
||
|
||
Как видим, CrowdSec сам определил, что у нас есть SSH и Linux (syslog и kern.log). Создан локальный API (LAPI)
|
||
м логин/пароль для него записан в `/etc/crowdsec/local_api_credentials.yaml`.
|
||
|
||
Далее CrowdSec загрузил парсеры, сценарии и коллекции для настройки защиты SSH и Linux.
|
||
|
||
Проверим, что CrowdSec работает:
|
||
```shell
|
||
sudo systemctl status crowdsec
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
● crowdsec.service - Crowdsec agent
|
||
Loaded: loaded (/lib/systemd/system/crowdsec.service; enabled; vendor preset: enabled)
|
||
Active: active (running) since Sat xxxx-xx-xx xx:xx:xx XXX; 51min ago
|
||
Main PID: 3357651 (crowdsec)
|
||
Tasks: 14 (limit: 18978)
|
||
Memory: 30.7M
|
||
CPU: 18.233s
|
||
CGroup: /system.slice/crowdsec.service
|
||
├─3357651 /usr/bin/crowdsec -c /etc/crowdsec/config.yaml
|
||
└─3357715 journalctl --follow -n 0 _SYSTEMD_UNIT=smb.service
|
||
|
||
Xxx xx xx:xx:xx xxxx systemd[1]: Starting Crowdsec agent...
|
||
Xxx xx xx:xx:xx xxxx systemd[1]: Started Crowdsec agent.
|
||
```
|
||
|
||
Проверим версию CrowdSec:
|
||
```shell
|
||
sudo cscli version
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
version: v1.6.8-debian-pragmatic-arm64-f209766e
|
||
Codename: alphaga
|
||
BuildDate: 2025-03-25_14:50:57
|
||
GoVersion: 1.24.1
|
||
Platform: linux
|
||
libre2: C++
|
||
User-Agent: crowdsec/v1.6.8-debian-pragmatic-arm64-f209766e-linux
|
||
...
|
||
...
|
||
```
|
||
|
||
Проверим список установленных парсеров:
|
||
```shell
|
||
sudo cscli parsers list
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
PARSERS
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
Name 📦 Status Version Local Path
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
crowdsecurity/dateparse-enrich ✔️ enabled 0.2 /etc/crowdsec/parsers/s02-enrich/dateparse-enrich.yaml
|
||
crowdsecurity/geoip-enrich ✔️ enabled 0.5 /etc/crowdsec/parsers/s02-enrich/geoip-enrich.yaml
|
||
crowdsecurity/smb-logs ✔️ enabled 0.2 /etc/crowdsec/parsers/s01-parse/smb-logs.yaml
|
||
crowdsecurity/sshd-logs ✔️ enabled 3.0 /etc/crowdsec/parsers/s01-parse/sshd-logs.yaml
|
||
crowdsecurity/syslog-logs ✔️ enabled 0.8 /etc/crowdsec/parsers/s00-raw/syslog-logs.yaml
|
||
crowdsecurity/whitelists ✔️ enabled 0.3 /etc/crowdsec/parsers/s02-enrich/whitelists.yaml
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
Как видим `crowdsecurity/sshd-logs` доступны, а значит CrowdSec может парсить логи SSH. Проверим список
|
||
установленных коллекций:
|
||
```shell
|
||
sudo cscli collections list
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
─────────────────────────────────────────────────────────────────────────────────
|
||
COLLECTIONS
|
||
─────────────────────────────────────────────────────────────────────────────────
|
||
Name 📦 Status Version Local Path
|
||
─────────────────────────────────────────────────────────────────────────────────
|
||
crowdsecurity/linux ✔️ enabled 0.2 /etc/crowdsec/collections/linux.yaml
|
||
crowdsecurity/smb ✔️ enabled 0.1 /etc/crowdsec/collections/smb.yaml
|
||
crowdsecurity/sshd ✔️ enabled 0.6 /etc/crowdsec/collections/sshd.yaml
|
||
─────────────────────────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
Видим, что `crowdsecurity/sshd` доступны. Проверим список установленных сценариев:
|
||
```shell
|
||
sudo cscli scenarios list
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
SCENARIOS
|
||
───────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
Name 📦 Status Version Local Path
|
||
───────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
crowdsecurity/smb-bf ✔️ enabled 0.2 /etc/crowdsec/scenarios/smb-bf.yaml
|
||
crowdsecurity/ssh-bf ✔️ enabled 0.3 /etc/crowdsec/scenarios/ssh-bf.yaml
|
||
crowdsecurity/ssh-cve-2024-6387 ✔️ enabled 0.2 /etc/crowdsec/scenarios/ssh-cve-2024-6387.yaml
|
||
crowdsecurity/ssh-refused-conn ✔️ enabled 0.1 /etc/crowdsec/scenarios/ssh-refused-conn.yaml
|
||
crowdsecurity/ssh-slow-bf ✔️ enabled 0.4 /etc/crowdsec/scenarios/ssh-slow-bf.yaml
|
||
───────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
Сценарии `ssh-bf`, `crowdsecurity/ssh-slow-bf` (брутфорсинг и медленный брутфорсинг SSH),
|
||
`crowdsecurity/ssh-cve-2024-6387` (защита от regreSSHion-атак на старые SSH-сервера) и
|
||
crowdsecurity/ssh-refused-conn` (отказ соединения SSH) доступны.
|
||
|
||
Кстати, обновлять все это богачество (парсеры, сценарии, коллекции и т.п.) можно командой:
|
||
```shell
|
||
sudo cscli hub update
|
||
```
|
||
|
||
Проверим конфиги CrowdSec, и убедимся, что он анализирует логи SSH:
|
||
```shell
|
||
sudo cat /etc/crowdsec/acquis.yaml
|
||
```
|
||
|
||
Должны увидеть вот такой блок:
|
||
```yaml
|
||
filenames:
|
||
- /var/log/auth.log
|
||
labels:
|
||
type: syslog
|
||
---
|
||
```
|
||
|
||
Если, вдруг, такого блока нет, добавьте его (лучше в начало) и перезапустим CrowdSec. Но обычно все уже настроено.
|
||
|
||
Проверим, что CrowdSec анализирует логи SSH:
|
||
```shell
|
||
sudo cscli metrics
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ Acquisition Metrics │
|
||
├────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────┤
|
||
│ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │
|
||
├────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤
|
||
│ file:/var/log/auth.log │ 628 │ - │ 628 │ - │ - │
|
||
│ file:/var/log/kern.log │ 2.78k │ - │ 2.78k │ - │ - │
|
||
│ file:/var/log/syslog │ 3.46k │ - │ 3.46k │ - │ - │
|
||
╰────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯
|
||
...
|
||
...
|
||
```
|
||
|
||
Как видим, CrowdSec читает `/var/log/auth.log` (логи SSH).
|
||
|
||
----
|
||
#### Установка CrowdSec Firewall Bouncer -- блокировщик IP-адресов
|
||
|
||
По мне, блокировки CrowdSec довольно беззубые. К счастью через "вышибалу" Firewall Bouncer можно блокировать
|
||
IP-адреса по iptables (или nftables) и сделать CrowdSec злее fail2ban. Для этого нужно установить
|
||
`crowdsec-firewall-bouncer-iptables`:
|
||
```shell
|
||
sudo apt-get install crowdsec-firewall-bouncer-iptables
|
||
```
|
||
Проверим, что "вышибала" запустилась:
|
||
```shell
|
||
sudo systemctl status crowdsec-firewall-bouncer
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
● crowdsec-firewall-bouncer.service - The firewall bouncer for CrowdSec
|
||
Loaded: loaded (/etc/systemd/system/crowdsec-firewall-bouncer.service; enabled; vendor preset: enabled)
|
||
Active: active (running) since Sun 2025-05-18 14:47:10 MSK; 723ms ago
|
||
Process: 621537 ExecStartPre=/usr/bin/crowdsec-firewall-bouncer -c /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml -t (code=exited, status=0/SUCCESS)
|
||
Process: 621674 ExecStartPost=/bin/sleep 0.1 (code=exited, status=0/SUCCESS)
|
||
Main PID: 621622 (crowdsec-firewa)
|
||
Tasks: 10 (limit: 18978)
|
||
Memory: 7.4M
|
||
CPU: 401ms
|
||
CGroup: /system.slice/crowdsec-firewall-bouncer.service
|
||
└─621622 /usr/bin/crowdsec-firewall-bouncer -c /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
|
||
|
||
May 18 14:47:04 opi5 systemd[1]: Starting The firewall bouncer for CrowdSec...
|
||
May 18 14:47:10 opi5 systemd[1]: Started The firewall bouncer for CrowdSec.
|
||
```
|
||
|
||
Подключить его в CrowdSec:
|
||
```shell
|
||
sudo cscli bouncers add firewall-bounce
|
||
```
|
||
|
||
Проверим, что "вышибала" добавлен:
|
||
```shell
|
||
sudo cscli bouncers list
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
Name IP Address Valid Last API pull Type Version Auth Type
|
||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
cs-firewall-bouncer-xxxx 127.0.0.1 ✔️ xxxx-xx-xxTxx:xx:xxZ crowdsec-firewall-bouncer v0.0.31-debian-pragmatic-xxxxxx... api-key
|
||
firewall-bouncer ✔️ api-key
|
||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
----
|
||
#### Подключаем наш CrowdSec к обмену данными об атаках
|
||
|
||
CrowdSec может обмениваться данными об атаках с другими участниками сети. Чтобы это сделать, нужно пойти [на сайт
|
||
CrowdSec](https://crowdsec.net/) и зарегистрироваться. После подтверждения регистрации по email, в личном кабинете
|
||
в самом низу, увидим строчку команды, типа:
|
||
```shell
|
||
sudo cscli console enroll -e context хеш-идентификатор-вашего-аккаунта
|
||
```
|
||
|
||
Скопируем эту команду и выполняем в терминале. Увидим что-то вроде:
|
||
```text
|
||
INFO manual set to true
|
||
INFO context set to true
|
||
INFO Enabled manual : Forward manual decisions to the console
|
||
INFO Enabled tainted : Forward alerts from tainted scenarios to the console
|
||
INFO Enabled context : Forward context with alerts to the console
|
||
INFO Watcher successfully enrolled. Visit https://app.crowdsec.net to accept it.
|
||
INFO Please restart crowdsec after accepting the enrollment.
|
||
```
|
||
|
||
Как видим, нужно перезапустить CrowdSec:
|
||
```shell
|
||
sudo systemctl restart crowdsec
|
||
```
|
||
|
||
Теперь нужно снова зайти в личный кабинет CrowdSec и подтвердить подключение Security Engine.
|
||
|
||
Все! Подключение локального CrowdSec к Community Blocklist завершено. В личном кабинете можно посмотреть статистику
|
||
(по каждому Security Engine, ведь на один аккаунт можно подключить несколько хостов с CrowdSec) и даже управлять
|
||
фильтрами и сценариями (это не точно).
|
||
|
||

|
||
|
||
Проверим, что CrowdSec получает блокировки через Community Blocklist API (CAPI):
|
||
```shell
|
||
sudo cscli metrics
|
||
```
|
||
|
||
Увидим что-то типа:
|
||
```text
|
||
...
|
||
...
|
||
╭──────────────────────────────────────────╮
|
||
│ Local API Decisions │
|
||
├────────────────┬────────┬────────┬───────┤
|
||
│ Reason │ Origin │ Action │ Count │
|
||
├────────────────┼────────┼────────┼───────┤
|
||
│ generic:scan │ CAPI │ ban │ 3222 │
|
||
│ smb:bruteforce │ CAPI │ ban │ 427 │
|
||
│ ssh:bruteforce │ CAPI │ ban │ 10033 │
|
||
│ ssh:exploit │ CAPI │ ban │ 1315 │
|
||
╰────────────────┴────────┴────────┴───────╯
|
||
...
|
||
```
|
||
|
||
Как видим, CrowdSec получает блокировки. Если очень интересно, можно посмотреть, что именно и почему блокируется
|
||
(например, `ssh:bruteforce`):
|
||
```shell
|
||
sudo cscli decisions list --origin CAPI
|
||
```
|
||
|
||
Увидим длиннющий список, примерно такого содержания:
|
||
```text
|
||
╭───────┬────────┬────────────────────────────────────┬────────────────┬────────┬─────────┬────┬────────┬────────────┬──────────╮
|
||
│ ID │ Source │ Scope:Value │ Reason │ Action │ Country │ AS │ Events │ expiration │ Alert ID │
|
||
├───────┼────────┼────────────────────────────────────┼────────────────┼────────┼─────────┼────┼────────┼────────────┼──────────┤
|
||
..... .... ...................... .............. ... . ......... .
|
||
│ ..... │ CAPI │ Ip:129.211.204.27 │ ssh:bruteforce │ ban │ │ │ 0 │ 79h15m46s │ 1 │
|
||
│ ..... │ CAPI │ Ip:128.199.124.27 │ ssh:bruteforce │ ban │ │ │ 0 │ -1h44m14s │ 1 │
|
||
│ ..... │ CAPI │ Ip:Ip:2602:80d:1006::76 │ ssh:bruteforce │ ban │ │ │ 0 │ 48h15m46s │ 1 │
|
||
│ ..... │ CAPI │ Ip:123.58.213.127 │ ssh:bruteforce │ ban │ │ │ 0 │ 160h15m46s │ 1 │
|
||
╰───────┴────────┴────────────────────────────────────┴────────────────┴────────┴─────────┴────┴────────┴────────────┴──────────╯
|
||
```
|
||
|
||
----
|
||
#### Настройка Whitelist (белого списка)
|
||
|
||
Чтобы не заблокировать себя (случайно) нужно создать в Whitelist (белый список). Например, сделаем `home_whitelist`
|
||
(имя списка, таких списков может быть несколько, и
|
||
```shell
|
||
sudo cscli allowlist create home_whitelist -d 'Мой домашний whitelist'
|
||
```
|
||
|
||
Теперь добавим в него свои домашнюю подсеть или IP-адрес (через пробел можно указать несколько адресов или подсетей):
|
||
```shell
|
||
sudo cscli allowlist add home_whitelist 192.168.1.0/24 XXX.XXX.XXX.XXX
|
||
````
|
||
|
||
Проверим, что все добавилось:
|
||
```shell
|
||
sudo cscli allowlist inspect home_whitelist
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
──────────────────────────────────────────────
|
||
Allowlist: home_whitelist
|
||
──────────────────────────────────────────────
|
||
Name home_whitelist
|
||
Description Мой домашний whitelist
|
||
Created at 2025-05-17T21:00:13.042Z
|
||
Updated at 2025-05-17T21:01:29.090Z
|
||
Managed by Console no
|
||
──────────────────────────────────────────────
|
||
|
||
───────────────────────────────────────────────────────────────
|
||
Value Comment Expiration Created at
|
||
───────────────────────────────────────────────────────────────
|
||
192.168.1.0/24 never 2025-05-17T21:00:13.042Z
|
||
XXX.XXX.XXX.XXX never 2025-05-17T21:00:13.042Z
|
||
XXX.XXX.XXX.XXX never 2025-05-17T21:00:13.042Z
|
||
...
|
||
...
|
||
───────────────────────────────────────────────────────────────
|
||
```
|
||
|
||
Еще один способ отредактировать (создать) Whitelist-конфиг парсера, который мы получили командой
|
||
`sudo cscli parsers list`. Конфиг `/etc/crowdsec/parsers/s02-enrich/whitelists.yaml` довольно простой, если его
|
||
отредактировать (добавить нужные IP-адреса, подсети или даже доменные имена), а затем перезапустить CrowdSec -- получим
|
||
тот же результат. Только управлять через списки (allowlist) удобнее.
|
||
[См. документацию](https://doc.crowdsec.net/u/getting_started/post_installation/whitelists/).
|
||
|
||
----
|
||
#### Настройка Firewall Bouncer (блокировщик IP-адресов)
|
||
|
||
----
|
||
##### Сценарии блокировок
|
||
|
||
Когда мы проверяли установку CrowdSec, и проверим список сценариев `shell sudo cscli scenarios list`, то нам был
|
||
показан список yaml-манифестов c конфигурациями сценариев блокировок. Эти **сценарии занимаются распознаванием атак**,
|
||
в частности касающихся SSH:
|
||
* `/etc/crowdsec/scenarios/ssh-bf.yaml` -- брутфорс SSH
|
||
* `/etc/crowdsec/scenarios/ssh-slow-bf.yaml` -- медленный брутфорс SSH
|
||
* `/etc/crowdsec/scenarios/ssh-cve-2024-6387.yaml` -- regreSSHion-атака (атаки уязвимости SSH-серверов старых версий)
|
||
* `/etc/crowdsec/scenarios/ssh-refused-conn.yaml` -- отказ соединения SSH, защищает от сканеров, которые ищут
|
||
открытые SSH-порты (на очень актуально, если у вас SSH открыт по стандартном 22-порту).
|
||
|
||
В некоторых манифестах может быть несколько блоков конфигурации блокировок для разных сценариев атак "зловредов".
|
||
Например, в `ssh-bf.yaml` есть блоки `crowdsecurity/ssh-bf` (для тупого брутфорса) и `crowdsecurity/ssh-bf_user-enum`
|
||
(для перебора пользователей).
|
||
|
||
Меняем "беззубые" параметры, на что-то более серьезное. Открываем на редактирование, например, `ssh-bf.yaml`:
|
||
```shell
|
||
sudo nano /etc/crowdsec/scenarios/ssh-bf.yaml
|
||
```
|
||
|
||
Увидим что-то типа:
|
||
```yaml
|
||
# ssh bruteforce
|
||
type: leaky
|
||
name: crowdsecurity/ssh-bf
|
||
description: "Detect ssh bruteforce"
|
||
filter: "evt.Meta.log_type == 'ssh_failed-auth'"
|
||
leakspeed: "10s"
|
||
references:
|
||
- http://wikipedia.com/ssh-bf-is-bad
|
||
capacity: 5
|
||
groupby: evt.Meta.source_ip
|
||
blackhole: 1m
|
||
reprocess: true
|
||
labels:
|
||
service: ssh
|
||
confidence: 3
|
||
spoofable: 0
|
||
classification:
|
||
- attack.T1110
|
||
label: "SSH Bruteforce"
|
||
behavior: "ssh:bruteforce"
|
||
remediation: true
|
||
---
|
||
# ssh user-enum
|
||
type: leaky
|
||
name: crowdsecurity/ssh-bf_user-enum
|
||
description: "Detect ssh user enum bruteforce"
|
||
filter: evt.Meta.log_type == 'ssh_failed-auth'
|
||
groupby: evt.Meta.source_ip
|
||
distinct: evt.Meta.target_user
|
||
leakspeed: 10s
|
||
capacity: 5
|
||
blackhole: 1m
|
||
labels:
|
||
service: ssh
|
||
remediation: true
|
||
confidence: 3
|
||
spoofable: 0
|
||
classification:
|
||
- attack.T1589
|
||
behavior: "ssh:bruteforce"
|
||
label: "SSH User Enumeration"
|
||
```
|
||
|
||
Что тут происходит:
|
||
|
||
* Сценарий `crowdsecurity/ssh-bf`:
|
||
* Тип: `leaky` -- leaky bucket — алгоритм "дырявое ведро", считающий события в окне времени. Метафора "дырявого
|
||
ведра" в том, что из дырок на дне идет утечка со скоростью одна попытка за `leakspeed`. Емкость ведра равна
|
||
`capacity`. Когда "ведро" было пустм, в него можно было поместить `capacity` событий, и после по одому событию
|
||
в `leakspeed`. Если ведро переполнено событиями, то включается `blackhole` (черная дыра) и события игнорируются
|
||
в течении `blackhole` времени.
|
||
* Фильтр: `evt.Meta.log_type == 'ssh_failed-auth'` -- ловит неудачные попытки входа по SSH из `/var/log/auth.log`.
|
||
* Логика:
|
||
* `groupby: evt.Meta.source_ip` -- группирует события по IP атакующего.
|
||
* `leakspeed: 10s` -- "окно времени" — 10 секунд (каждые 10 сек разрешена одна попытка).
|
||
* `capacity: 5` -- Бан после 5 неудачных попыток.
|
||
* `blackhole: 1m` -- Бан на 1 минуту.
|
||
* Сценарий `crowdsecurity/ssh-bf_user-enum`:
|
||
* Тип тот же.
|
||
* Фильтр тот же.
|
||
* Логика:
|
||
* `distinct: evt.Meta.target_user` -- считает попытки с разными пользователями (root, admin, pi, orangepi и т.д.).
|
||
* `leakspeed: 10s` -- "окно времени" — 10 секунд.
|
||
* `capacity: 5` -- Бан после 5 разных пользователей за 10 секунд.
|
||
* `blackhole: 1m` -- Бан на 1 минуту.
|
||
|
||
Как видим в обоих случаях бан срабатывает после пяти попыток за десять секунд, и блокировка всего на минуту. Конечно,
|
||
брутфорсеры -- это быстрые атаки, но "быстрота" понятие относительное. Я выставляю:
|
||
* `leakspeed: 10m`
|
||
* `capacity: 2`
|
||
* `blackhole: 1h`
|
||
|
||
И считаю, что это довольно мягко. Но чтоб случайно не заблокировать себя, когда буду подключаться с внешнего IP
|
||
не из белого списка (например, по мобильному интернету) -- это разумный компромисс.
|
||
|
||
После редактирования файла, нужно перезапустить CrowdSec, чтоб он применил изменения:
|
||
```shell
|
||
sudo systemctl restart crowdsec
|
||
sudo systemctl restart crowdsec-firewall-bouncer
|
||
```
|
||
|
||
Другие сценарии можно настроить по аналогии. "Злость" управляется параметрами `leakspeed`, `capacity` и `blackhole`.
|
||
Но имейте в виду: не стоит менять много параметров одновременно. Настройки разных сценариев могут конфликтовать
|
||
друг другом, и тогда CrowdSec не запустится.
|
||
|
||
После перезапуска CrowdSec:
|
||
```shell
|
||
sudo systemctl restart crowdsec
|
||
```
|
||
|
||
И еще, экспериментально я обнаружил, что настройки дней, например `2d` недопустимы. Надо указывать `48h` (48 часов),
|
||
и в целом не нужно сразу месть настройки сразу во всех сценариях. Они могут конфликтовать друг с другом, и CrowdSec
|
||
не перезапуститься.
|
||
|
||
Проверим, что CrowdSec начал банить на основании настроенных правил (особо ждать не придется, зловреды попадутся уже через
|
||
пару минут):
|
||
```shell
|
||
sudo cscli decisions list
|
||
```
|
||
|
||
Увидим что-то типа:
|
||
```text
|
||
╭───────┬──────────┬───────────────────┬────────────────────────────────┬─────┬────┬────────────────────────┬────────┬────────────┬──────────╮
|
||
│ ID │ Source │ Scope:Value │ Reason │ Act │ Co │ AS │ Events │ expiration │ Alert ID │
|
||
├───────┼──────────┼───────────────────┼────────────────────────────────┼─────┼────┼────────────────────────┼────────┼────────────┼──────────┤
|
||
│ 30004 │ crowdsec │ Ip:39.98.38.186 │ crowdsecurity/ssh-slow-bf │ ban │ CN │ 37963 Hangzhou Alibaba │ 11 │ 3h54m49s │ 6 │
|
||
│ 30002 │ crowdsec │ Ip:165.246.104.64 │ crowdsecurity/ssh-bf │ ban │ KR │ 9317 INHA UNIVERSITY │ 3 │ 3h50m0s │ 4 │
|
||
│ 90210 │ crowdsec │ Ip:180.10.143.248 │ crowdsecurity/ssh-bf_user-enum │ ban │ CN │ 4134 Chinanet │ 3 │ 3h6m38s │ 216 │
|
||
╰───────┴──────────┴───────────────────┴────────────────────────────────┴─────┴────┴────────────────────────┴────────┴────────────┴──────────╯
|
||
```
|
||
|
||
----
|
||
##### Время блокировок
|
||
|
||
Сценарии занимаются распознаванием угроз, но самими блокировками они не занимаются. Блокировки настроены по умолчанию
|
||
на четыре часа, и это указано в профилях `/etc/crowdsec/profiles.yaml`. Чтобы изменить время, на которое "зловред"
|
||
отправляется в бан, нужно отредактировать этот файл. По умолчанию он вот такой:
|
||
```yaml
|
||
name: default_ip_remediation
|
||
#debug: true
|
||
filters:
|
||
- Alert.Remediation == true && Alert.GetScope() == "Ip"
|
||
decisions:
|
||
- type: ban
|
||
duration: 4h
|
||
#duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)
|
||
# notifications:
|
||
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
|
||
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
|
||
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
|
||
# - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
|
||
on_success: break
|
||
---
|
||
name: default_range_remediation
|
||
#debug: true
|
||
filters:
|
||
- Alert.Remediation == true && Alert.GetScope() == "Range"
|
||
decisions:
|
||
- type: ban
|
||
duration: 4h
|
||
#duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)
|
||
# notifications:
|
||
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
|
||
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
|
||
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
|
||
# - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
|
||
on_success: break
|
||
```
|
||
|
||
Как видим, по умолчанию блокировка на 4 часа. Чтобы изменить время блокировок, нужно отредактировать `duration: 4h` на
|
||
нужное. Но в конфигурации есть "заготовка" для динамического времени блокировок:
|
||
`duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)` -- каждый раз, когда зловред
|
||
попадает в бан, время блокировки увеличивается на 4 часа. То есть, если зловред попался в бан 5 раз, то его блокировка
|
||
будет 20 часов. И так далее (формулу, при желании, можно изменить). Это то, что нам нужно. Имейте в виду, что
|
||
подключение `duration_expr` исключает возможность указать `duration` (время блокировки) в секции `decisions`. Таким
|
||
образом получаем вот такой конфиг:
|
||
```yaml
|
||
name: default_ip_remediation
|
||
#debug: true
|
||
filters:
|
||
- Alert.Remediation == true && Alert.GetScope() == "Ip"
|
||
decisions:
|
||
- type: ban
|
||
# duration: 4h
|
||
duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)
|
||
on_success: break
|
||
---
|
||
name: default_range_remediation
|
||
#debug: true
|
||
filters:
|
||
- Alert.Remediation == true && Alert.GetScope() == "Range"
|
||
decisions:
|
||
- type: ban
|
||
duration: 5h
|
||
on_success: break
|
||
```
|
||
|
||
Можно добавлять и свои правила. Например, для более длительных блокировок медленных брутфорсов, добавим в конце:
|
||
```yaml
|
||
---
|
||
name: ssh_slow_bf_remediation
|
||
filters:
|
||
- Alert.Remediation == true && Alert.Scenario == "crowdsecurity/ssh-slow-bf"
|
||
decisions:
|
||
- type: ban
|
||
duration: 10h
|
||
on_success: break
|
||
```
|
||
|
||
После сохранения конфига, перезапустим CrowdSec:
|
||
```shell
|
||
sudo systemctl restart crowdsec
|
||
```
|
||
|
||
И убедимся, что время блокировки увеличилось:
|
||
```shell
|
||
sudo cscli decisions list
|
||
```
|
||
```text
|
||
╭────────┬──────────┬───────────────────┬──────────────────────┬────────┬─────────┬──────────────────────┬────────┬────────────┬──────────╮
|
||
│ ID │ Source │ Scope:Value │ Reason │ Action │ Country │ AS │ Events │ expiration │ Alert ID │
|
||
├────────┼──────────┼───────────────────┼──────────────────────┼────────┼─────────┼──────────────────────┼────────┼────────────┼──────────┤
|
||
│ 165247 │ crowdsec │ Ip:165.246.104.64 │ crowdsecurity/ssh-bf │ ban │ KR │ 9317 INHA UNIVERSITY │ 3 │ 91h25m24s │ 258 │
|
||
╰────────┴──────────┴───────────────────┴──────────────────────┴────────┴─────────┴──────────────────────┴────────┴────────────┴──────────╯
|
||
```
|
||
|
||
----
|
||
#### Web-панель
|
||
|
||
Плюсом CrowdSec является то, что благодаря обмену информацией о блокировках, в личном кабинете на сайте CrowdSec можно
|
||
посмотреть ваши локальные блокировки через веб-интерфейсе:
|
||
|
||

|
||
|
||
----
|
||
#### Управление блокировками
|
||
|
||
Можно добавить бан вручную (по умолчанию: `duration:4h` и `type:ban`):
|
||
```shell
|
||
sudo cscli decisions add -i xxx.xxx.xxx.xxx
|
||
sudo cscli decisions add --ip xxx.xxx.xxx.xxx --duration 24h --reason "любопытный безопасник"
|
||
sudo cscli decisions add --ip xxx.xxx.xxx.xxx --reason "web bruteforce" --type captcha
|
||
```
|
||
|
||
Снять блокировку отдельного IP, подсети (диапазона) или вообще все:
|
||
```shell
|
||
sudo cscli decisions delete --ip xxx.xxx.xxx.xxx
|
||
sudo cscli decisions delete --range yyy.yyy.yyyy.yyy/24
|
||
sudo cscli decisions delete --all
|
||
```
|
||
|
||
#### Блокировки по GeoIP
|
||
|
||
Проверим, что у нас есть парсер на основе GeoIP:
|
||
```shell
|
||
sudo cscli parsers lis
|
||
```
|
||
|
||
Увидим в числе прочих:
|
||
```text
|
||
PARSERS
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
Name 📦 Status Version Local Path
|
||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||
crowdsecurity/geoip-enrich ✔️ enabled 0.5 /etc/crowdsec/parsers/s02-enrich/geoip-enrich.yaml
|
||
```
|
||
|
||
Он обогащает события (events) GeoIP-информацией: страна, город, ASN, континент и так далее, но сам ничего не блокирует —
|
||
он просто добавляет поля к событиям. Но это делает возможным создание собственных фильтров и сценариев,
|
||
завязанных на GeoIP. Используется двухбуквенный код страны (стандарт ISO-3166-1 alpha-2).
|
||
|
||
У меня на хосте половина зловредов из Китая и Кореи. За ними, с большим отрывом, Индия и Индонезия. Вот честно,
|
||
ничего против этих стран не имею, от из этих регионов 80% всех атак на мой SSH. Создаем свой сценарий:
|
||
```shell
|
||
sudo nano /etc/crowdsec/scenarios/ban-cn--geoip.yaml
|
||
```
|
||
|
||
И вставим туда:
|
||
```yaml
|
||
# /etc/crowdsec/scenarios/ban-cn--geoip.yaml
|
||
# Бан по GeoIP для Китая и Кореи
|
||
type: trigger
|
||
name: local/ban-russian-ips
|
||
description: "Ban any IP from China & Korea"
|
||
filter: evt.Meta.geoip_country in ['CN', 'KR'] and evt.Meta.service == 'ssh'
|
||
groupby: evt.Meta.source_ip
|
||
labels:
|
||
country_ban: CN
|
||
remediation: true
|
||
classification:
|
||
- abuse
|
||
behavior: "geoip:ban"
|
||
confidence: 5
|
||
label: "GeoIP Country Ban"
|
||
manual: true
|
||
```
|
||
|
||
Как видно, это `trigger`-сценарий, он срабатывает при одиночном совпадении, без необходимости "накопить
|
||
события", как в `leaky`. И бан срабатывает если "зловред" лезет в сервис `ssh`.
|
||
|
||
Перезапустим CrowdSec:
|
||
```shell
|
||
sudo systemctl restart crowdsec
|
||
```
|
||
|
||
Теперь CrowdSec будет автоматически блокировать все новые IP из указанных стран при появлении их в логах.
|
||
И если честно, можно вообще все страны забанить, кроме тех, где бываю в отпуске. Нечего им делать на моем сервере. :)
|
||
|