Принцип одного из отделов компании ответственного за взаимодействие с подрядчиками по сайту, так и самостоятельного написания какого-либо функционала для ответственного Web-сервиса строится по принципу: «не предполагали столкнуться с такой ситуацией». Какова предыстория: есть портал по подбору жалюзей, штор, т.е. какой-то калькулятор, не важно. Ну так вот 13.03.2023 наши добросанные "Коллеги" включили API и предоставили его дилерам и началось утро:

Андрей Сивков (09:58:23 13/03/2024)

привет

 Андрей Сивков (09:58:31 13/03/2024)

глянь, что там на серваке

 Андрей Сивков (09:58:35 13/03/2024)

чего-то не открывается

На вопрос, что Вы сделали раз до этого все, работало?

Андрей Сивков (10:29:41 13/03/2024)

да хз, ничего нового за последние дни не выкатывали

Приступил к анализу произошедшего.

По процессам nginx, mysql, логам вышел что идут массовые запросы на подключение к этому самому API и происходит исчерпание ресурсов.

Задал вопрос, а почему перед тем как что-то включить не проверили: может увеличить количество соединение, ресурсов или поэтапно включать клиентов, а не все скопом.

Ответ: см в начале заметки принцип «не предполагали столкнуться с такой ситуацией», т.е. разбираться с проблемой будем по мере возникновения проблемы.

Я же в свою очередь вышел уже после всего проанализированного на лог сайта в nginx где фигурируют WAN-IP тех кто задействует обращение к API и просто опираясь на свою заметку: "GEO блокировка через firewalld на Ubuntu 22.04" создал source:wanblock и занес туда всех кто есть в параметре client: WAN-IP.

Ниже пример строки в логе:

2024/03/13 11:05:30 [error] 2163#2163: *2346 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 81.200.248.106, server: <VPS_SYSTEM>.site.ru, request: "GET /api/dealers/companies HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.3-fpm.sock:", host: "<VPS_SYSTEM>.site.ru", referrer: "https://<VPS_SYSTEM>.site.ru/account/"

т.е.

  • f1 -> это 2024/03/13 11:05:30 [error] 2163#2163: *2346 recv() failed (104: Connection reset by peer) while reading response header from upstream
  • f2 -> Это client: 81.200.248.106
  • f3 -> это server: <VPS_SYSTEM>.site.ru
  • f4 -> это request: «GET /api/dealers/companies HTTP/1.1»
  • f5 -> это upstream: «fastcgi://unix:/run/php/php7.3-fpm.sock:»
  • f6 -> это host: «<VPS_SYSTEM>.site.ru»

Шаг №1: Чтобы выделить IP адреса из лога, я сперва экспортировал весь лог в файл для последующего с оставления регулярного выражения по его преображению к вижу с которым я смогу работать задействую заметку выше:

ekzorchik@<VPS_SYSTEM>:~$ sudo bash -c "cat /var/log/nginx/site.error.log > error.log"

Шаг №2: Чтобы из error.log файла получить WAN-IP адреса:

ekzorchik@<VPS_SYSTEM>:~$ cat error.log | cut -d ','  -f2 |  grep -v excess | tr -d ' client: ' | uniq | head -n 10
87.103.134.145
27.115.124.34
101.68.211.2
195.151.251.89
79.171.173.178
109.195.114.131
87.237.41.144
185.41.41.190
95.26.24.117
109.195.114.131
ekzorchik@<VPS_SYSTEM>:~$

где

  • grep -v excess — исключить строки содержащие excess
  • tr -d ‘ client ‘ — удалить из строки «<пробел>client<пробел»
  • uniq — отсортировать
  • head -n 10 — > отобразить первые 10 строк

Шаг №3: С учетом проработки выше, просто без какого-либо сохранения отдельно приступил к обработке лога вот прям здесь и сейчас:

ekzorchik@<VPS_SYSTEM>:~$ sudo bash -c "cat /var/log/nginx/site.error.log | cut -d ','  -f2 |  grep -v excess | tr -d ' client: ' | uniq | head -n 10"
87.103.134.145
27.115.124.34
101.68.211.2
195.151.251.89
79.171.173.178
109.195.114.131
87.237.41.144
185.41.41.190
95.26.24.117
109.195.114.131
ekzorchik@<VPS_SYSTEM>:~$

и вывод копируем в wanblock.zone

sudo bash -c "cat /var/log/nginx/site.error.log | cut -d ','  -f2 |  grep -v excess | tr -d ' client: ' | uniq | head -n 10" > wanblock.zone
sudo firewall-cmd --zone=drop --ipset=wanblock.zone --add-entries-from-file=/home/ekzorchik/wanblock.zone --permanent
sudo firewall-cmd --permanent --zone=drop --add-source="ipset:wanblock.zone"
sudo firewall-cmd --reload

Шаг №4: Если нужно удалить IP адрес из списка wanblock.zone:

sudo bash -c "cat /etc/firewalld/ipsets/wanblock.zone.xml" | grep 101.68.211.2
  <entry>101.68.211.2</entry>
ekzorchik@<VPS_SYSTEM>:~$ sudo nano /etc/firewalld/ipsets/wanblock.zone.xml

находим через поиск строку <entry>101.68.211.2</entry>, удаляем, сохраняем внесенные изменения

и перезапускаем:

sudo firewall-cmd --reload

Итого: после, когда помогли дилерам с правильной настройкой к API уже по отдельности удаляли WAN-IP дилеров из blocklist(а) с наказом, если такое повторится, то не обессуте снова заблокируем. В очередной раз разобранное для себя с применением firewalld + ipset выручило. В дополнении к этому я прикрутил fail2ban и уже все делается в автоматическом режиме.

На этом пока все, с уважением автор блога Олло Александр aka ekzorchik.