Вопрос или проблема
Я хочу перехватить 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
Объяснения:
-
Frontend
https-terminated
: Здесь мы определяем ACL (Access Control List) для проверки заголовкаHost
. Если заголовок совпадает с нужными значениями, мы используем соответствующий бэкенд. -
Бэкенды: Каждый бэкенд (например,
jenkins
иpuppet
) жестко прописан. Это удобно, потому что HAProxy проверяет доступность серверов на старте и может успешно перезапустить их в случае сбоя. -
Puppet: Использование Puppet для управления конфигурацией упрощает процесс создания и редактирования бэкендов. Вы можете поддерживать изменения в коде вместо ручного редактирования конфигурационного файла HAProxy каждый раз.
Динамическое разрешение:
Хотя вы пытались динамически использовать заголовок Host
для определения бэкендов, имейте в виду, что такие настройки могут потребовать дополнительных средств настройки. Если вы планируете вводить много различных серверов с динамически определяемыми адресами, рассмотрите возможность использования более продвинутых решений, таких как Consul или подобные сервисы для управления сервисами.
Заключение:
HAProxy является мощным инструментом для балансировки нагрузки и может быть настроен для работы в соответствии с вашими требованиями. Однако для динамического разрешения бэкендов вам придется использовать либо статические определения, как показано выше, либо интегрировать другие решения для управления сервисами. Если вам нужно больше информации или помощь с конкретной настройкой, не стесняйтесь задавать вопросы.