Как стать автором
Обновить
VK
Технологии, которые объединяют

Настройка GeoIP ACL в HAProxy в два шага

Блог компании VK Информационная безопасность *Серверное администрирование *DevOps *

Hello Planets by Augustinas Raginskis

Иногда возникает задача управления трафиком в зависимости от географического положения клиента. Возможные области применения — блокировка некоторых локаций либо перенаправление трафика на итоговый сервер в зависимости от локации клиента. Традиционно подобные вещи реализуются при помощи библиотек GeoIP компании MaxMind. В статье расскажу, как это сделать.

Настройка доступа к библиотекам MaxMind


Раньше не нужно было настраивать доступ, так как MaxMind предоставляли часть своих библиотек для прямого скачивания по ссылке. Однако сейчас функция прямого скачивания без регистрации недоступна. Поэтому сначала нужно зарегистрироваться здесь, заполнив форму:


После этого шага вам на почту придет письмо с дальнейшими инструкциями:


Перейдите по ссылке для создания пароля:


После завершения регистрации вы попадете в личный кабинет:


Чтобы скачивать файлы MaxMind напрямую, необходимо выписать лицензию на сайте. Для этого нужно перейти по ссылке My License Key:


Далее:


Далее:


На экране отобразится номер лицензии, который нужно сохранить — потом увидеть его будет нельзя, только выписывать новую лицензию:


Теперь, с номером лицензии, можно скачивать файлы баз данных GeoIP. Как это сделать написано тут.

Дальше переходим по ссылке: https://www.maxmind.com/en/accounts/current/geoip/downloads, и нажимаем линк Get permalinks напротив базы данных GeoLite2 Country: CSV Format:


В следующем окне указаны ссылки на скачивание:


Обратите внимание, что нужно заменить YOUR_LICENSE_KEY на вашу лицензию, которую вы выписали ранее. 

На этом настройка получения базы GeoIP закончена, переходим непосредственно к настройке.

Настройка HAProxy


HAProxy не умеет работать напрямую с базами MaxMind, однако умеет строить ACL на основе списков сетей. Вот как это описывается в конфиге HAProxy:

frontend frontend-https
    bind *:80

# GeoIP ACL
    acl acl_SNG src -f /etc/haproxy/geoip/SNG.txt

Содержимое файла /etc/haproxy/geoip/SNG.txt:

...
188.215.252.0/22
188.237.0.0/16
188.240.70.0/24
188.244.16.0/20
191.96.60.0/23
192.121.87.0/24
193.8.167.0/24
193.16.111.0/24
193.17.78.0/24
...

То есть файл SNG.txt содержит в себе список сетей, которые попадут в ACL.

Перед нами стоит задача автоматизировать создание файла со списком сетей из баз данных MaxMind.

Сформулируем задачу, которую мы хотим решить: необходимо, чтобы трафик из России, Беларуси и Украины шел на один бэкенд, а трафик из других локаций уходил на другой бэкенд. Для решения этой задачи напишем shell-скрипт. Скрипт будет состоять из нескольких этапов.

Сначала получим свежую копию базы данных MaxMind в формате csv:

# Download geoip2 lite csv database
wget 
"https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=${MAXMIND_LICENSE}&suffix=zip" -qO geoip2lite.zip 
&& unzip -j geoip2lite.zip

Здесь ${MAXMIND_LICENSE} — это номер лицензии, который мы выписали ранее на сайте MaxMind.

После выполнения команды содержимое архива будет выглядеть так:

root@ash:/tmp/geo2lite# ls -1
COPYRIGHT.txt
GeoLite2-Country-Blocks-IPv4.csv
GeoLite2-Country-Blocks-IPv6.csv
GeoLite2-Country-Locations-de.csv
GeoLite2-Country-Locations-en.csv
GeoLite2-Country-Locations-es.csv
GeoLite2-Country-Locations-fr.csv
GeoLite2-Country-Locations-ja.csv
GeoLite2-Country-Locations-pt-BR.csv
GeoLite2-Country-Locations-ru.csv
GeoLite2-Country-Locations-zh-CN.csv
LICENSE.txt
README.txt

Нас интересуют два файла — GeoLite2-Country-Blocks-IPv4.csv, содержащий информацию о принадлежности сетей ipv4 странам, и GeoLite2-Country-Locations-en.csv, содержащий соответствия названий стран цифровым кодам.

Соответственно, если нам нужно получить все сети, принадлежащие России, мы для начала получаем код России:

root@ash:/tmp/geo2lite# cat GeoLite2-Country-Locations-en.csv | grep 
Russia
2017370,en,EU,Europe,RU,Russia,0

Здесь 2017370 — это искомый код.

Теперь по нему можно определить сети. 

root@ash:/tmp/geo2lite# cat GeoLite2-Country-Blocks-IPv4.csv | grep 2017370
...
217.147.16.0/20,2017370,2017370,,0,0
217.148.48.0/20,2017370,2017370,,0,0
217.148.192.0/19,2017370,2017370,,0,0
217.149.16.0/20,2017370,2017370,,0,0
217.149.176.0/20,2017370,2017370,,0,0
217.150.0.0/18,2017370,2017370,,0,0
217.150.72.0/21,2017370,2017370,,0,0
217.150.192.0/20,2017370,2017370,,0,0

Обратите внимание, что число 2017370 встречается в каждой строке два раза. Обратимся к описанию формата файла:

root@ash:/tmp/geo2lite# cat GeoLite2-Country-Blocks-IPv4.csv | head -n 1
network,geoname_id,registered_country_geoname_id,represented_country_geo
name_id,is_anonymous_proxy,is_satellite_provider

Здесь registered_country_geoname_id — код страны, за которой зарегистрирована сеть, а represented_country_geoname_id — код страны, из которой происходит роутинг сети. 

Возможна ситуация, когда сеть зарегистрирована, например за Россией, а роутинг происходит из Голландии. Как поступать в такой ситуации, решайте сами, я выбирал только сети, зарегистрированные и маршрутизируемые из запрашиваемой страны.

Соответственно, выбирая нужные сети из файла GeoLite2-Country-Blocks-IPv4.csv, можно сформировать файл для HAProxy ACL.

Сама работа с ACL в HAProxy:

frontend frontend
# GeoIP ACL
    acl acl_SNG src -f /etc/haproxy/geoip/SNG.txt

    use_backend backend1 if acl_SNG
    default_backend backend2

Соответственно, если IP-адрес источника будет из сети, описанной в файле SNG.txt, то запрос уйдет на backend1, в противном случае — на backend2.

Для автоматизации операций был написан скрипт:

root@ash:~# cat haproxy_geoip_list.sh
#!/bin/bash
#-----------------------------------------------------------------------------------------------------------------------
# Variables
TMPDIR="/tmp/geo2lite"
MAXMIND_LICENSE="xxxxxxxxxxxxx"
LOCATIONS="Russia Ukraine Belarus"
HAPROXY_PATH="/etc/haproxy/geoip"
HAPROXY_FILE="SNG.txt"
#-----------------------------------------------------------------------------------------------------------------------
mkdir -p ${TMPDIR}
pushd ${TMPDIR}
# Download geoip2 lite csv database
wget 
"https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=${MAXMIND_LICENSE}&suffix=zip" -qO geoip2lite.zip 
&& unzip -j geoip2lite.zip
if [ $? -gt 0 ]; then
 logger -t "haproxy_geoip" "Download not success."
 exit 1
fi

exit
for COUNTRY in ${LOCATIONS}; do
 echo "# ${COUNTRY}"
 COUNTRY_CODE=`cat GeoLite2-Country-Locations-en.csv | grep -i 
"${COUNTRY}" | awk -F "," '{print $1}'`
 grep ",${COUNTRY_CODE}," GeoLite2-Country-Blocks-IPv4.csv | awk -F "," 
'{print $1}'
done > ${HAPROXY_FILE}

# Check file
if [ ! -s ${HAPROXY_FILE} ]; then
    logger -t "haproxy_geoip" "File is not exist"
    exit 1
fi

if [ -s ${HAPROXY_PATH}/${HAPROXY_FILE} ]; then
    MD5_FILE=`md5sum ${HAPROXY_PATH}/${HAPROXY_FILE} | awk '{print $1}'`
fi

MD5_TMPFILE=`md5sum ${HAPROXY_FILE} | awk '{print $1}'`

if [ "${MD5_TMPFILE}" != "${MD5_FILE}" ]; then
 logger -t "haproxy_geoip" "File ${HAPROXY_FILE} is changed"
 cp ${HAPROXY_PATH}/${HAPROXY_FILE} 
${HAPROXY_PATH}/${HAPROXY_FILE}.backup
 mv ${HAPROXY_FILE} ${HAPROXY_PATH}/${HAPROXY_FILE}
 # Test new haprpoxy cfg
 /usr/sbin/haproxy -c -f /etc/haproxy/haproxy.cfg
 if [ $? -gt 0 ]; then
  logger -t "haproxy_geoip" "New file is corrupted, replace by older one from backup."
  mv ${HAPROXY_PATH}/${HAPROXY_FILE}.backup 
${HAPROXY_PATH}/${HAPROXY_FILE}
 fi
fi

popd
rm -rf "${TMPDIR}"

Перед запуском не забудьте заполнить секцию Variables под ваши нужды.

Удачи!

Написано при поддержке Mail.ru Cloud Solutions

Что еще почитать

  1. Как ограничить частоту запросов в HAProxy: пошаговая инструкция.
  2. Лучшие практики и рекомендации для запуска контейнеров и Kubernetes в производственных средах.
  3. Наш телеграм-канал о цифровой трансформации и IT
Теги:
Хабы:
Всего голосов 35: ↑35 и ↓0 +35
Просмотры 2.7K
Комментарии Комментарии 4

Информация

Дата основания
Местоположение
Россия
Сайт
vk.com
Численность
5 001–10 000 человек
Дата регистрации
Представитель
Миша Буданов