diff --git a/haproxy/group_map.cfg b/haproxy/group_map.cfg new file mode 100644 index 0000000..2235918 --- /dev/null +++ b/haproxy/group_map.cfg @@ -0,0 +1,12 @@ +# Формат: <префикс пути> +# Путь сопоставляется как path_beg (начало пути), поэтому важно указывать +# завершающий "/". adminusergroup — реальное имя AD-группы (cn из LDAP). +# +# Файл читается HAProxy из /etc/haproxy/group_map.cfg — после правки +# перечитывать конфиг: systemctl reload haproxy + +/admins-network/resource1/ be_admin_resource1 +/admins-network/resource2/ be_admin_resource2 + +# Пример добавления новой группы/ресурса: +# /admins-storage/ceph-dashboard/ be_admin_storage_ceph diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg new file mode 100644 index 0000000..327c3d4 --- /dev/null +++ b/haproxy/haproxy.cfg @@ -0,0 +1,110 @@ +#--------------------------------------------------------------------- +# HAProxy: единая точка входа для портала администрирования +# Устанавливается штатно из пакета дистрибутива, этот файл заменяет +# /etc/haproxy/haproxy.cfg (см. README.md, шаг 6). +#--------------------------------------------------------------------- +global + log /dev/log local0 info + maxconn 20000 + user haproxy + group haproxy + tune.ssl.default-dh-param 2048 + ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 + ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM + +defaults + log global + mode http + option httplog + option dontlognull + option forwardfor + timeout connect 5s + timeout client 30s + timeout server 30s + timeout http-request 10s + errorfile 400 /etc/haproxy/errors/400.http + errorfile 403 /etc/haproxy/errors/403.http + errorfile 500 /etc/haproxy/errors/500.http + errorfile 502 /etc/haproxy/errors/502.http + errorfile 503 /etc/haproxy/errors/503.http + errorfile 504 /etc/haproxy/errors/504.http + +#--------------------------------------------------------------------- +# Статистика (в проде — ограничить отдельным ACL по внутренней сети) +#--------------------------------------------------------------------- +listen stats + bind 127.0.0.1:8404 + stats enable + stats uri /haproxy?stats + stats refresh 15s + +#--------------------------------------------------------------------- +# HTTP -> HTTPS редирект +#--------------------------------------------------------------------- +frontend fe_http + bind *:80 + http-request redirect scheme https unless { ssl_fc } + +#--------------------------------------------------------------------- +# Основной вход +#--------------------------------------------------------------------- +frontend fe_https + bind *:443 ssl crt /etc/haproxy/certs/fqdn.pem alpn h2,http/1.1 + + http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains" + + # Простейшая защита от брутфорса логина + stick-table type ip size 100k expire 10m store http_req_rate(1m) + http-request track-sc0 src + http-request deny deny_status 429 if { path_beg /login/ } { sc_http_req_rate(0) gt 20 } + + # Путь вида ///... считаем "ресурсным" + acl is_resource_path path_reg ^/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+(/.*)?$ + # Служебные префиксы портала — всегда на Django, даже если совпали с regex выше + acl is_portal_path path_beg /login/ /logout/ /static/ /django-admin/ /healthz + + # Признак для роутинга на реальный backend — короткоживущий resource_token, + # который Django выпускает ПОСЛЕ проверки прав на конкретный ресурс + # (см. docs/architecture.md, раздел 5). Сессия портала (sessionid) в + # backend'ы никогда не передаётся. + acl has_resource_token cook(resource_token) -m found + + use_backend be_django if !is_resource_path + use_backend be_django if is_portal_path + use_backend be_django if is_resource_path !has_resource_token !is_portal_path + + use_backend %[path,map_beg(/etc/haproxy/group_map.cfg,be_django)] \ + if is_resource_path has_resource_token !is_portal_path + +#--------------------------------------------------------------------- +# Backend: Django frontend (портал), работает через Gunicorn на localhost +#--------------------------------------------------------------------- +backend be_django + balance roundrobin + option httpchk GET /healthz + http-check expect status 200 + http-request set-header X-Forwarded-Proto https + server django1 127.0.0.1:8000 check + # server django2 10.0.0.11:8000 check # вторая ВМ с Django — для горизонтального масштабирования + +#--------------------------------------------------------------------- +# Backends реальных admin panel — по одной секции на систему. +# Ниже — 2 демонстрационных backend'а (см. backend_demo/, работают на +# localhost через Nginx на отдельных портах). По этому шаблону добавляются +# последующие продуктовые системы (обычно они на других хостах в сети). +#--------------------------------------------------------------------- +backend be_admin_resource1 + balance roundrobin + option httpchk GET / + http-request set-header X-Forwarded-Proto https + http-request set-header X-Resource-Token %[cook(resource_token)] + http-request del-header Cookie + server resource1 127.0.0.1:8081 check + +backend be_admin_resource2 + balance roundrobin + option httpchk GET / + http-request set-header X-Forwarded-Proto https + http-request set-header X-Resource-Token %[cook(resource_token)] + http-request del-header Cookie + server resource2 127.0.0.1:8082 check