В данном руководстве мы рассмотрим как реализовать концепцию большого динамического черного или белого списка с помощью веб-сервера Nginx, сервера Redis и скрипта расширения Nginx, реализованного на Lua.
В данном руководстве все программное обеспечение будет устанавливаться в CentOS 7. Практически без изменений данные решения можно применить и в других дистрибутивах, основанных на RPM и Yum.
Nginx содержит встроенный механизм обработки черных или белых списков, который подходит в случае использования небольших списков. Однако, этот механизм неудобен, когда требуется работать с большими списками адресов, когда списки формируются динамически.
К счастью, Nginx поддерживает модули расширения на языке Lua, которые совместно с кэшу в памяти Redis позволяют реализовать требуемую функциональность черных и белых списков.
Установка Nginx, Lua и Redis в CentOS 7
Установка всех компонентов будет производиться с помощью Yum.
Вероятно, вам придется подобрать подходящую для пакета nginx-module-lua версию Nginx, поскольку они устанавливаются из разных репозиториев. На момент написания руководства nginx-module-lua «хотел» версию Nginx 1.15.7.
$ sudo yum install epel-release $ sudo yum update $ sudo yum install redis # запускаем redis $ sudo systemctl start redis $ sudo systemctl enable redis # устанавливаем nginx и модуль lua для него $ sudo yum install -y http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm $ sudo sed -i -e 's@/packages/@/packages/mainline/@' /etc/yum.repos.d/nginx.repo $ sudo curl -L https://copr.fedorainfracloud.org/coprs/khara/nginx-module-ndk-lua/repo/epel-7/khara-nginx-module-ndk-lua-epel-7.repo -o /etc/yum.repos.d/nginx-module-ndk-lua.repo $ sudo yum install -y nginx-1.15.7 nginx-module-lua # запускаем nginx $ sudo systemctl start nginx $ sudo systemctl enable nginx
Проверяем доступность Nginx, открыв страницу по ip-сервера в браузере:
Проверим доступность Redis:
$ redis-cli ping PONG $
Если вы настраиваете сервер для боевого использования, обязательно настройте безопасность Redis по нашему руководству.
Перейдем к настройке белого или черного списков.
Установка модуля Lua для доступа к Redis
Модуль будем устанавливать из Git-репозитория OpenResty, поскольку в пакетах CentOS данный модуль отсутствует:
$ sudo mkdir -p /opt/openresty && cd /opt/openresty $ sudo yum install git $ sudo git clone https://github.com/openresty/lua-resty-redis.git
Добавим путь к модулю в Nginx и протестируем конфигурацию. Для этого отредактируем файл /etc/nginx/nginx.conf, добавив строки, отмеченные в следующем листинге цветом:
# в первые строки файла load_module modules/ndk_http_module.so; load_module "modules/ngx_http_lua_module.so"; ... ... http { lua_package_path "/opt/openresty/lua-resty-redis/lib/?.lua;;"; ... }
Теперь убедимся в том, что конфигурация nginx корректна и перезапустим его:
sudo nginx -t && sudo systemctl restart nginx
Настройка белого списка
Мы будем использовать рецепт скрипта белого списка, который приведет в GitHub. Для его использования внесем несколько директив в Nginx:
В файл /etc/nginx/nginx.conf добавим строку, приведенную ниже:
http { ## # Basic Settings ## lua_shared_dict ip_whitelist 1m;
и в секцию server или location сам обработчик по белому списку. В нашем примере добавим в файл /etc/nginx/sites-enabled/default:
# Default server configuration # server { listen 80 default_server; listen [::]:80 default_server; access_by_lua_file /etc/nginx/lua/ip_whitelist.lua; ....
Скачаем сам Lua-скрипт:
$ sudo mkdir /etc/nginx/lua $ cd /etc/nginx/lua $ sudo wget https://gist.githubusercontent.com/itbdw/bc6c03f754cc30f66b824f379f3da30f/raw/a655713ecbe676558244d44dc78c875d7a84f8d1/ip_whitelist.lua $ sudo sed -i 's| \= require "nginx.redis"| \= require "resty.redis"|' ip_whitelist.lua
Проверим, конфигурацию Nginx и перезапустим его:
$ sudo nginx -t && sudo systemctl restart nginx
Если теперь вы попытаетесь открыть сайт, то получите страницу с ошибкой вида:
Теперь добавьте в Redis свой IP с помощью консоли Redis:
$ redis-cli SADD ip_whitelist A.B.C.D
и снова проверьте доступ к сайту, должна открываться страница Nginx, которую мы уже видели раньше:
Опять удалите запись для вашего IP с помощью консоли Redis:
$ redis-cli SREM ip_whitelist 148.77.35.49
Результатом доступа к сайту снова будет ошибка.
Таким образом, мы успешно настроили белый список, используя Nginx, Redis и скрипт Lua, который подходит для динамического управления записями и работы с большими списками. Список реализован с помощью высокопроизводительных множеств Redis, скорость доступа к которым подчиняется закону трудоемкости O(1), то есть работает быстро, если по-русски.
Настройка черного списка
Черный список настраивается аналогично с точностью до замены white на black:
- lua_shared_dict ip_blacklist 1m;
- access_by_lua_file /etc/nginx/lua/ip_blacklist.lua;
- скрипт.
Модифицируйте скрипт для использования правильного сервера Redis и правильного модуля Lua для него:
$ sudo sed -i 's|your.redis.server.here|127.0.0.1|' ip_blacklist.lua $ sudo sed -i 's| \= require "nginx.redis"| \= require "resty.redis"|' ip_blacklist.lua
Добавление и удаление записей в черный список осуществляется следующими командами:
$ redis-cli SADD ip_blacklist A.B.C.D $ redis-cli SREM ip_blacklist A.B.C.D
Заключение
Динамические черные и белые списки являются более универсальным решением в случае необходимости использования больших списков с необходимостью изменения записей на лету, что может быть востребовано при наличии средств диагностики злоумышленников.
Хранение списков в Redis позволяет обеспечить высочайшую производительность решения, которая не деградирует с ростом списка адресов в списке. Доступность Redis через API подходит для интеграции со сторонними поставщиками записей для списков.
В том случае, если необходимо сохранение списков между перезагрузками Redis, то в файл конфигурации /etc/redis/redis.conf необходимо изменить строку:
appendonly no на appendonly yes
Установка данной конфигурации для CentOS 7 является весьма трудоемкой и требует установки пакетов из внешних репозиториев.
Скрипт на Lua достаточно прост и легко может быть адаптирован для более специфических задач.