Как использовать хост в качестве рассчитанной цели бэкенда для HAProxy?

Вопрос или проблема

Я хочу перехватить TCP-трафик, а затем перенаправить всё остальное на соответствующие серверы в бэкенде. У меня есть внутренний DNS с совпадающим доменом для внешнего wildcard ingress.

Я думаю о чём-то подобном, но подозреваю, что это не поддерживается, так как HAProxy проверяет бэкенд при старте, и это не разрешится ни на что.

server all { req.hdr(host) }:443 check ssl verify none

Моя полная конфигурация приведена ниже:

# Этот файл управляется Puppet
global
  chroot  /var/lib/haproxy
  daemon
  group  haproxy
  log  172.22.91.180 local0
  maxconn  4000
  pidfile  /var/run/haproxy.pid
  user  haproxy

defaults
  log  global
  maxconn  8000
  option  redispatch
  retries  3
  timeout  http-request 10s
  timeout  queue 1m
  timeout  connect 10s
  timeout  client 1m
  timeout  server 1m
  timeout  check 10s

frontend waf-server
  bind 172.22.91.180:443
  mode tcp
  option tcplog
  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 }
  use_backend load-balancer if { req_ssl_sni -i rdg.example.com }
  default_backend reverse-proxy

backend load-balancer
  balance roundrobin
  server blue rd1.example.com:443 check
  server green rd2.example.com:443 check

backend reverse-proxy
  mode tcp
  server loopback-terminated abns@haproxy-terminate send-proxy-v2

frontend https-terminated
  mode http
  stats enable
  bind abns@haproxy-terminate accept-proxy ssl crt /etc/ssl/private/fullchain.cer
  use_backend jenkins if { req.hdr(host) -i jenkins.example.com }
  use_backend puppet if { req.hdr(host) -i puppet.example.com }

backend jenkins
  mode http
  option forwardfor
  option http-server-close
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https
  http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains"
  server jenkins jenkins.example.com:443 check ssl verify none

backend puppet
  mode http
  option forwardfor
  option http-server-close
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https
  http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains"
  server puppet puppet.example.com:443 check ssl verify none

Кратко говоря, каждый бэкенд должен быть явно определён. Мне удалось уменьшить количество ошибок вручную, используя Puppet для генерации всех необходимых бэкендов, ниже приведён фрагмент

# В модулях/haproxy/manifests/backend.pp
define waf_server::dynamic_backend (
  String $backend_name,
  String $host,
) {
  haproxy::backend { $backend_name:
    mode    => 'http',
    options => [
      { 'option'        => 'forwardfor' },
      { 'option'        => 'http-server-close' },
      { 'http-request'  => 'set-header X-Forwarded-Port %[dst_port]' },
      { 'http-request'  => 'add-header X-Forwarded-Proto https' },
      { 'http-response' => 'set-header Strict-Transport-Security "max-age=15552000; includeSubDomains"' },
      { 'server'        => "${backend_name} ${host}:443 check ssl verify none" },
    ],
  }
}

и в init.pp

  $backends = {
    'jenkins' => 'jenkins.example.com',
    'puppet'  => 'puppet.example.com',
  }

  $options = $backends.map |$backend, $host| {
    { 'use_backend' => "${backend} if { req.hdr(host) -i ${host} }" }
  }

  haproxy::frontend { 'https-terminated':
    mode    => 'http',
    bind    => { 'abns@haproxy-terminate' => ['accept-proxy', 'ssl', 'crt', '/etc/ssl/private/fullchain.pem'] },
    options => [
      { 'option' => 'httplog' }  # включить HTTP Access логирование
    ] + $backends.map |$backend, $host| {
      { 'use_backend' => "${backend} if { req.hdr(host) -i ${host} }" }
    },
      require => Haproxy::Backend[$backends.keys], # Убедитесь, что все бэкенды созданы первыми
  }

Ответ или решение

Для использования HAProxy в качестве динамического маршрутизатора для обратных прокси, где бэкенды определяются на основе заголовка Host, важно понимать некоторые ограничения и возможности настройки конфигурации. В вашем случае вы хотите использовать заголовок Host для динамического определения бэкенда, к которому отправляются запросы. Однако нужно учитывать, что HAProxy не поддерживает динамическое разрешение DNS на этапе запуска и требуются явные определения бэкенда.

Конфигурация HAProxy:

Ваш текущий конфиг выглядит довольно хорошо, но чтобы добиться желаемого поведения, вы можете попробовать использовать http-request для динамической маршрутизации HTTPS-соединений. Поскольку вы уже используете шаблоны с Puppet, это позволит вам уменьшить количество ошибок при ручном редактировании конфигурации.

Вот упрощённая и адаптированная версия вашего конфигурационного файла с учётом ваших требований к динамическому маршруту:

global
  chroot  /var/lib/haproxy
  daemon
  group  haproxy
  log 172.22.91.180 local0
  maxconn 4000
  pidfile /var/run/haproxy.pid
  user haproxy

defaults
  log global
  maxconn 8000
  option redispatch
  retries 3
  timeout http-request 10s
  timeout queue 1m
  timeout connect 10s
  timeout client 1m
  timeout server 1m
  timeout check 10s

frontend https-terminated
  mode http
  bind abns@haproxy-terminate accept-proxy ssl crt /etc/ssl/private/fullchain.cer
  acl is_jenkins hdr(host) -i jenkins.example.com
  acl is_puppet hdr(host) -i puppet.example.com

  use backend jenkins if is_jenkins
  use backend puppet if is_puppet

backend jenkins
  mode http
  option forwardfor
  option http-server-close
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https
  http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains"
  server jenkins jenkins.example.com:443 check ssl verify none

backend puppet
  mode http
  option forwardfor
  option http-server-close
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https
  http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains"
  server puppet puppet.example.com:443 check ssl verify none

Объяснения:

  1. Frontend https-terminated: Здесь мы определяем ACL (Access Control List) для проверки заголовка Host. Если заголовок совпадает с нужными значениями, мы используем соответствующий бэкенд.

  2. Бэкенды: Каждый бэкенд (например, jenkins и puppet) жестко прописан. Это удобно, потому что HAProxy проверяет доступность серверов на старте и может успешно перезапустить их в случае сбоя.

  3. Puppet: Использование Puppet для управления конфигурацией упрощает процесс создания и редактирования бэкендов. Вы можете поддерживать изменения в коде вместо ручного редактирования конфигурационного файла HAProxy каждый раз.

Динамическое разрешение:

Хотя вы пытались динамически использовать заголовок Host для определения бэкендов, имейте в виду, что такие настройки могут потребовать дополнительных средств настройки. Если вы планируете вводить много различных серверов с динамически определяемыми адресами, рассмотрите возможность использования более продвинутых решений, таких как Consul или подобные сервисы для управления сервисами.

Заключение:

HAProxy является мощным инструментом для балансировки нагрузки и может быть настроен для работы в соответствии с вашими требованиями. Однако для динамического разрешения бэкендов вам придется использовать либо статические определения, как показано выше, либо интегрировать другие решения для управления сервисами. Если вам нужно больше информации или помощь с конкретной настройкой, не стесняйтесь задавать вопросы.

Оцените материал
Добавить комментарий

Капча загружается...