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
Что еще почитать:
- Как ограничить частоту запросов в HAProxy: пошаговая инструкция.
- Лучшие практики и рекомендации для запуска контейнеров и Kubernetes в производственных средах.
- Наш телеграм-канал о цифровой трансформации и IT.