ActiveDirectory/LDAP-HA

Материал из ALT Linux Wiki

Постановка задачи

Представим ситуацию, что вам надо реализовать отказоустойчивый балансировщик для ldap/ldaps запросов, чтобы была единая точка входа для запросов, а выход из строя ldap-бэкенда или одного из узлов балансировщика не влиял на получение результата.

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

LDAP HA

Несколько узлов балансировщика (balancer1..N) и несколько ldap-бэкендов (LDAP1..N).

HA-реализация

Рассмотрим реализацию, в которой будет:

  • два сервера LDAP (в реализации Альт Домен) — dc1, dc2, rodc1;
  • два узла балансировки — balancer1, balancer2.

Подготовка

Конфигурацию серверов LDAP пропустим — будем считать, что они есть и работают.

Сетевая конфигурация узлов балансировщика будет такой:

  • balancer1 — 1.2.3.10
  • balancer2 — 1.2.3.11
  • «Плавающий» общий адрес — 1.2.3.5

На узлах балансировки нужно установить пакеты ha-proxy и keepalived:

# apt-get update && apt-get install -y haproxy keepalived

Также нужно разрешить поддержку двух ip-адресов, т.к. логика работы keepalived основана на том, что один адрес (основная точка входа для запросов) будет «плавающим», передаваясь от узла к узлу.

Для этого изменим параметр net.ipv4.ip_nonlocal_bind:

# sysctl net.ipv4.ip_nonlocal_bind=1
# echo net.ipv4.ip_nonlocal_bind = 1 >>/etc/net/sysctl.conf

Настройка

Файл конфигурации для всех узлов будет выглядеть примерно так:

/etc/haproxy/haproxy.cfg  
global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    pidfile     /run/haproxy.pid
    stats socket /var/lib/haproxy/stats
    stats timeout 30s
    user _haproxy
    group _haproxy
    daemon
    maxconn 10000
defaults
    log global
    mode tcp
    option tcplog
    option dontlognull
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    retries 3
frontend ldap_frontend
    bind *:389
    default_backend ldap_servers
frontend ldaps_frontend
    bind *:636
    default_backend ldaps_backend
backend ldaps_backend
    mode tcp
#   balance roundrobin
    option ssl-hello-chk
    option tcp-check
    balance leastconn
    server  dc1 dc1.test.alt:636 check port 636 inter 2000 rise 2 fall 3 
    server  dc2 dc2.test.alt:636 check port 636 inter 2000 rise 2 fall 3 
    server  rodc rodc.test.alt:636 check port 636 inter 2000 rise 2 fall 3 
backend ldap_servers
    mode tcp
    option ldap-check 
#   balance roundrobin
    balance leastconn
#   tcp-check connect port 389
#   tcp-check   send-binary 300c020101600702010304008000
#   tcp-check expect binary 300c02010161070a010004000400
    server  dc1 dc1.test.alt:389 check port 389 inter 2000 rise 2 fall 3 
    server  dc2 dc2.test.alt:389 check port 389 inter 2000 rise 2 fall 3 
    server  rodc rodc.test.alt:389 check port 389 inter 2000 rise 2 fall 3

Поясню некоторые моменты относительно конфигурации haproxy.

Как видно, настроено два бэкенда — для LDAP и LDAPS; параметры схожи.

balance roundrobin — алгоритм балансировки. Просто круговой перебор: первый запрос ⇾ сервер 1, второй ⇾ сервер 2, третий ⇾ сервер 3, четвертый ⇾ снова сервер 1. Вполне понятный и предсказуемый, но есть минусы:

  • игнорирует текущую нагрузку серверов;
  • не учитывает время выполнения запросов;
  • проблемы с «длинными» соединениями — если один запрос выполняется 10 сек., а другой 0.1 сек,, серверы будут загружены неравномерно.

balance leastconn — в этом случае подсчитываются активные соединения на каждом сервере и новый запрос всегда отправляется на сервер с наименьшим количеством текущих соединений. Очень удобно при использовании долгих соединений (LDAP !)

Кроме этих двух режимов есть и другие:

  • source — привязка к ip т.е. один клиент (по IP) всегда попадает на один сервер;
  • uri — запросы к одному URI идут на один сервер;
  • random — вероятно, лучший выбор для большого кластера.

Для остальных просто приложу краткую таблицу:

Алгоритмы балансировки HAProxy  
Алгоритм Сфера применения
roundrobin Сглаженное и справедливое распределение при равномерном времени обработки серверов. Динамический алгоритм с ограничением 4095 серверов на бэкенд.
static-rr Аналогичен roundrobin, но статический — изменение весов серверов на лету не действует. Нет ограничения на количество серверов. Не используется в режиме LOG.
leastconn Рекомендуется для очень длинных сессий: LDAP, SQL, TSE и т.д. Не очень хорошо подходит для протоколов с короткими сессиями (например, HTTP). Учитывает как установленные, так и ожидающие соединения.
first Первый сервер с доступными слотами соединений получает запрос. Цель — использовать минимальное количество серверов. Игнорирует вес серверов. Полезен для длинных сессий (RDP, IMAP).
hash Универсальный алгоритм хеширования по заданному выражению. Может заменить source, uri, hdr() и т.д. Позволяет использовать конвертеры или извлекать данные из локальных переменных.
source Хеширует исходный IP-адрес. Гарантирует, что один клиент (по IP) будет попадать на один сервер, пока состав серверов не изменится. Часто используется в TCP-режиме.
uri Хеширует часть URI или весь URI. Используется с прокси-кешами и антивирусными прокси для максимизации hit rate. Только для HTTP-бэкендов.
url_param Ищет указанный параметр в строке запроса HTTP GET (или в теле POST с модификатором check_post). Используется для отслеживания идентификаторов пользователей. Только для HTTP-бэкендов.
hdr(<имя>) Балансировка на основе значения указанного HTTP-заголовка. Если заголовок отсутствует или пуст, используется roundrobin. Только для HTTP-бэкендов.
random Использует случайное число в качестве ключа для консистентного хеширования. Полезен при больших фермах или частом добавлении/удалении серверов (избегает "эффекта молота").
rdp-cookie Ищет и хеширует указанную RDP-куку (по умолчанию "mstshash"). Используется как упрощённый механизм сохранения сессии для протокола RDP.
log-hash Применяет конвертеры к лог-сообщению, хеширует результат для выбора сервера. Только для бэкендов в режиме LOG.
sticky Старается отправлять все сообщения на первый доступный сервер в списке. При его отказе переходит к следующему. Используется для логирования.

Параметры опции server, кроме и без того понятных — inter 2000 rise 2 fall 3:

  • проверка выполняется каждые 2 секунды (inter 2000);
  • чтобы сервер был признан нерабочим, нужно 3 неудачные проверки подряд (fall 3).

Только после этого HAProxy исключит его из балансировки.

Файл /etc/keepalived/keepalived.conf будет отличатся для хостов с разными ролями, например:

для роли MASTER  
global_defs {
    router_id haproxy_ldap_100
}
# Script used to check if HAProxy is running
vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3 
    weight 2
    fall 2     
    rise 1   
}
# Виртуальный интерфейс
vrrp_instance VI_01 {
    state MASTER
    interface ens19
    virtual_router_id 51
    priority 100
    # Виртуальный IP-адрес
    virtual_ipaddress {
        1.2.3.5/24
    }
    track_script {
        check_haproxy
    }
}
для роли BACKUP  
global_defs {
    router_id haproxy_ldap_100_passive
}
# Script used to check if HAProxy is running
vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3 
    weight 2
    fall 2     
    rise 1   
}
# Виртуальный интерфейс
vrrp_instance VI_01 {
    state BACKUP
    interface ens19
    virtual_router_id 51
    priority 90
    # Виртуальный IP-адрес
    virtual_ipaddress {
        1.2.3.5/24
    }
    track_script {
        check_haproxy
    }
}
Примечание: Обратите внимание на...
- параметр state, принимающий значение либо MASTER, либо BACKUP;
- уникальные параметры router_id и priority, а также
- одинаковые для всех узлов балансировщика:
  • параметр virtual_router_id,
  • имя сетевого интерфейса,
  • ip-адрес.


Запуск

После сделанных изменений запускаем необходимые сервисы на всех узлах балансировщика:

# systemctl enable --now haproxy keepalived

После чего на узле MASTER в выводе команды ip a появится еще один ip-адрес.

Проверка

Точка входа для запросов у нас 1.2.3.5. Если один из узлов балансировщика становится недоступен, адрес 1.2.3.5 автоматически поднимается на другом узле.

Проверяется обычным ldapsearch:

LDAP
ldapsearch -b 'dc=test,dc=alt' -D 'user@TEST.ALT' -w 'Qwerty1' -H  ldap://1.2.3.5 'Objectclass=*'
LDAPS
ldapsearch -b 'dc=test,dc=alt' -D 'user@TEST.ALT' -w 'Qwerty1' -H ldaps://1.2.3.5 'Objectclass=*' -o TLS_REQCERT=Never

Теперь можно выключать то один, то другой узел балансировщика и проверять, что ldapsearch всё равно работает как задумывалось. То же самое и с контроллерами домена.