ipset-access: Модуль доступа к ipset для NGINX
Установка на Debian/Ubuntu
Эти документы относятся к APT-пакету nginx-module-ipset-access, предоставляемому репозиторием GetPageSpeed Extras.
- Настройте APT-репозиторий, как описано в настройке APT-репозитория.
- Установите модуль:
sudo apt-get update
sudo apt-get install nginx-module-ipset-access
Warning
Этот модуль еще не опубликован как nginx-module-ipset-access в APT-репозиториях. Оставайтесь на связи или напишите на support@getpagespeed.com, чтобы запросить его.
Высокопроизводительный модуль NGINX, который позволяет вам включать или исключать IP-адреса клиентов с использованием средства ядра Linux ipset.
Все запросы обрабатываются в пользовательском пространстве через libipset и кэшируются на поток-для минимизации накладных расходов.
Особенности
- Нулевые накладные расходы во время выполнения – сеансы IPSet инициализируются один раз и кэшируются с помощью хранилища, привязанного к потоку.
- Режимы черного и белого списков – блокируйте все, кроме перечисленных наборов, или разрешайте все, кроме перечисленных наборов.
- Динамические обновления – изменение
ipsetне требует перезагрузки NGINX. - Нативные RPM-пакеты для RHEL / Alma / Rocky и производных через репозиторий GetPageSpeed.
Как это работает
┌ Client ──► NGINX worker
│ │
│ ├─► Thread‑local ipset session (libipset)
│ │ ├─ Test client IP against one or more sets
│ │ └─ Cache session handle for reuse
│ │
└─────────────┴── Allow / Deny based on match & mode
Модуль:
- Инициализирует
libipsetодин раз на каждый рабочий процесс. - Кэширует дескриптор сеанса в данных, специфичных для потока POSIX (
pthread_setspecific). - Оценивает адрес клиента по каждому настроенному набору.
- Возвращает настраиваемый статус (по умолчанию 403 Forbidden), когда запрос заблокирован.
Быстрая установка (для дистрибутивов на основе RPM)
sudo dnf --assumeyes install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf --assumeyes install nginx-module-ipset-access
Совет: Пакет подписан; убедитесь, что у вас включен
gpgcheck=1.
Включите модуль в /etc/nginx/nginx.conf перед любыми блоками http {}:
load_module modules/ngx_http_ipset_access.so;
Перезагрузите NGINX для применения:
sudo systemctl reload nginx
Клонирование NGINX и модуля
git clone https://github.com/nginx/nginx.git
git clone https://example.com/ngx_ipset_access.git
cd nginx
./auto/configure --with-compat --add-dynamic-module=../ngx_ipset_access
make -j$(nproc)
sudo make install
Сборка создает objs/ngx_http_ipset_access.so; скопируйте его в каталог модулей вашего NGINX и добавьте load_module, как показано выше.
Директивы конфигурации
ipset_blacklist set1 [set2 … setN]
Контекст: server
Блокирует запросы если IP клиента присутствует в любом из указанных ipset.
ipset_whitelist set1 [set2 … setN]
Контекст: server
Разрешает запросы только если IP клиента присутствует в указанном наборе. Все другие IP отклоняются.
ipset_status code
Контекст: server
Устанавливает код состояния HTTP, возвращаемый, когда запрос блокируется whitelist или blacklist. По умолчанию 403, если не установлено.
Общие варианты: 403 (Запрещено) или 444 (заблокировать без ответа).
ipset_autoadd setname
Контекст: location
Функциональность ловушки: Автоматически добавляет IP клиента в указанный ipset, когда доступ к локации осуществляется. Идеально подходит для создания конечных точек-ловушек, которые автоматически заносят в черный список вредоносные боты и сканеры.
Когда IP автоматически добавляется, модуль принудительно закрывает текущее соединение (отключает keep-alive), чтобы злоумышленники не могли повторно использовать соединение.
off
Любая директива принимает буквальное слово off для отключения обработки в текущем контексте:
server {
listen 80;
blacklist off; # нет фильтрации ipset в этом виртуальном хосте
}
Пример использования
## Создание ipset для заблокированных адресов
sudo ipset create bad_guys hash:ip
sudo ipset add bad_guys 203.0.113.4
sudo ipset add bad_guys 198.51.100.23
load_module modules/ngx_http_ipset_access.so;
http {
server {
listen 80 default_server;
root /usr/share/nginx/html;
# Блокировка любого IP, найденного в "bad_guys"
ipset_blacklist bad_guys;
# Возврат 444 для заблокированных запросов (по желанию)
ipset_status 444;
}
}
Поскольку запросы обрабатываются в реальном времени, добавление или удаление IP из bad_guys вступает в силу мгновенно без перезагрузки NGINX.
Пример ловушки
Создание автоматических ловушек, которые добавляют вредоносные IP в черные списки:
## Создание ipset для функциональности ловушки
sudo ipset create honeypot hash:ip
sudo ipset create malicious_scanners hash:ip
load_module modules/ngx_http_ipset_access.so;
http {
server {
listen 80 default_server;
root /usr/share/nginx/html;
# Используйте наборы ловушки в качестве черного списка - попавшие IP блокируются
ipset_blacklist honeypot malicious_scanners;
# По желанию: настройка статуса блокировки
ipset_status 403;
# Обычное содержимое
location / {
try_files $uri $uri/ =404;
}
# Конечные точки ловушки - боты, которые попадают на эти, автоматически добавляются в черный список
location /config.php {
ipset_autoadd honeypot;
return 200 "Доступ к конфигурации зарегистрирован";
}
location /wp-admin.php {
ipset_autoadd honeypot;
return 200 "Доступ к администратору зарегистрирован";
}
# Поймать общие попытки эксплуатации
location ~ ^/(phpMyAdmin|admin|eval\.php|shell\.php)$ {
ipset_autoadd malicious_scanners;
return 200 "Сканер обнаружен";
}
}
}
Когда бот посещает /config.php, его IP автоматически добавляется в набор honeypot и немедленно блокируется от всех последующих запросов. Соединение закрывается после добавления, чтобы предотвратить повторное использование keep-alive. Без внешних скриптов или fcgiwrap!
Логирование и отладка
Соберите NGINX с --with-debug и установите error_log /var/log/nginx/error.log debug;, чтобы увидеть подробный вывод, например:
test bad_guys 203.0.113.4 -> IPS_TEST_IS_IN_SET
Blocking 203.0.113.4 due to IPSET
Коды возврата
| Условие | HTTP статус |
|---|---|
whitelist и не в любом наборе |
По умолчанию 403 (или ipset_status) |
blacklist и присутствует в наборе |
По умолчанию 403 (или ipset_status) |
| Временная ошибка ipset (безопасный отказ) | По умолчанию 403 (или ipset_status) |
Ограничения и план развития
- Только IPv4 –
AF_INET6еще не поддерживается. - Использует синхронные вызовы libipset; при очень высоких скоростях запросов ядро может работать быстрее только с правилами
nft set. - Индивидуальный возвращаемый статус 444 подготовлен, но закомментирован; включите, если вам нужна семантика отказа без ответа.
Рабочий процесс разработки и тестирования (быстрая итерация)
Чтобы избежать повторного скачивания и сборки NGINX при каждом запуске теста, мы используем предустановленный образ Docker с NGINX и Test::Nginx. Тесты затем компилируют только этот модуль как динамический .so и загружают его через обертку.
Предварительные требования: Docker (и, по желанию, act, если вы хотите запустить рабочий процесс CI локально).
Быстрый старт:
## 1) Сборка повторно используемого базового образа один раз для каждой версии NGINX
make base-image NGINX_VERSION=release-1.27.2
## 2) Запуск всего набора тестов (компилирует только модуль .so при каждом запуске)
make tests NGINX_VERSION=release-1.27.2
## 3) Повторите для отдельного файла теста
make tests NGINX_VERSION=release-1.27.2 T=t/10-ipset.t
Подробности:
- Базовый образ определяется в Dockerfile.tests-base и помечается как nginx-ipset-access-tests-base:<NGINX_VERSION>.
- В момент тестирования скрипт-исполнитель (docker-run-tests.sh) настраивает NGINX с помощью --add-dynamic-module, указывая на репозиторий (/work), запускает make modules, затем устанавливает:
- TEST_NGINX_BINARY на предустановленный бинарный файл nginx
- TEST_NGINX_LOAD_MODULES на скомпилированный .so
Советы:
- Для логов и скорости в процессе итерации Makefile устанавливает:
- TEST_NGINX_FAST_SHUTDOWN=1
- TEST_NGINX_NO_CLEAN=1 (сохраняет t/servroot/)
- TEST_NGINX_LOG_LEVEL=debug
- TEST_NGINX_ERROR_LOG=/work/test-error.log
- Используйте T=<path> для запуска отдельного файла теста. Проверьте t/servroot/conf/nginx.conf и test-error.log при отладке.
Запустите рабочий процесс CI локально с помощью act:
## Требуется: npm i -g act (или brew install act), работающий демон Docker
act -W .github/workflows/build.yml -j build --container-daemon-socket 'unix:///var/run/docker.sock'
Это локально воспроизводит задание GitHub Actions, которое собирает базовый образ и выполняет набор тестов внутри контейнера с правами возможности NET_ADMIN.