fix(haproxy): Autodiscover на :80 и точный fail2ban для Zabbix
Outlook при настройке ext.kalinamall.ru слал GET /autodiscover/autodiscover.xml на порт 80; старый fe_http_zabbix отвечал 403 всем не-zabbix Host, fail2ban банил клиента на сутки. fe_http проксирует Autodiscover на Exchange :80, 403 только для zabbix вне allowlist, ignoreregex для /autodiscover/.
This commit is contained in:
@@ -13,7 +13,7 @@ TLS: HAProxy на **443** в режиме **TCP + SNI**, **не терминир
|
|||||||
| Служба | Внешнее имя (клиенты) | Внутренний хост / IP | Порт | Allowlist |
|
| Служба | Внешнее имя (клиенты) | Внутренний хост / IP | Порт | Allowlist |
|
||||||
|--------|------------------------|----------------------|------|-----------|
|
|--------|------------------------|----------------------|------|-----------|
|
||||||
| Microsoft Exchange (OWA и т.д.) | `ext.kalinamall.ru` | fifth.kalinamall.ru — **192.168.160.42** | 443 | нет |
|
| Microsoft Exchange (OWA и т.д.) | `ext.kalinamall.ru` | fifth.kalinamall.ru — **192.168.160.42** | 443 | нет |
|
||||||
| Autodiscover | `autodiscover.kalinamall.ru` | тот же Exchange — **192.168.160.42** | 443 | нет |
|
| Autodiscover | `autodiscover.kalinamall.ru` | тот же Exchange — **192.168.160.42** | 443; **80** (HTTP Autodiscover → Exchange) | нет |
|
||||||
| RDS | `rds.kalinamall.ru` | k6a-dc3 — **192.168.160.40**, служба **4430** | 443 → 4430 | **`rds-allowed`** |
|
| RDS | `rds.kalinamall.ru` | k6a-dc3 — **192.168.160.40**, служба **4430** | 443 → 4430 | **`rds-allowed`** |
|
||||||
| 1С | `erp.kalinamall.ru` | hp-serv — **192.168.160.150** | 443 | **`1c-allowed`** |
|
| 1С | `erp.kalinamall.ru` | hp-serv — **192.168.160.150** | 443 | **`1c-allowed`** |
|
||||||
| Git (HTTPS) | `git.kalinamall.ru` | **192.168.160.129** | 443 | **`git-sac-allowed`** |
|
| Git (HTTPS) | `git.kalinamall.ru` | **192.168.160.129** | 443 | **`git-sac-allowed`** |
|
||||||
@@ -26,7 +26,31 @@ TLS: HAProxy на **443** в режиме **TCP + SNI**, **не терминир
|
|||||||
|
|
||||||
DNS: **A** для `ext`, `autodiscover`, `rds`, `erp`, `git`, `sac`, **`sac-api`**, **`zabbix`**, **`heap`**, **`exchange`** → публичный IP HAProxy. Inbound SMTP (**25**) с интернета на HAProxy **не** пробрасывается; `ksmg` / MX — отдельная схема (см. [security/architecture.md](docs/security/architecture.md)).
|
DNS: **A** для `ext`, `autodiscover`, `rds`, `erp`, `git`, `sac`, **`sac-api`**, **`zabbix`**, **`heap`**, **`exchange`** → публичный IP HAProxy. Inbound SMTP (**25**) с интернета на HAProxy **не** пробрасывается; `ksmg` / MX — отдельная схема (см. [security/architecture.md](docs/security/architecture.md)).
|
||||||
|
|
||||||
Снаружи Zabbix — **`http://zabbix.kalinamall.ru`**. Synology DSM — **`https://heap.kalinamall.ru`**, **`https://exchange.kalinamall.ru`** (TLS на NAS, wildcard `*.kalinamall.ru`). Имя **`exchange.kalinamall.ru`** — NAS, не OWA (**`ext.kalinamall.ru`**).
|
Снаружи Zabbix — **`http://zabbix.kalinamall.ru`**. Outlook при настройке почты на **`ext.kalinamall.ru`** шлёт **HTTP Autodiscover** на `:80` (`/autodiscover/autodiscover.xml`) — HAProxy проксирует на Exchange **192.168.160.42:80**, без allowlist (как HTTPS OWA). Synology DSM — **`https://heap.kalinamall.ru`**, **`https://exchange.kalinamall.ru`** (TLS на NAS, wildcard `*.kalinamall.ru`). Имя **`exchange.kalinamall.ru`** — NAS, не OWA (**`ext.kalinamall.ru`**).
|
||||||
|
|
||||||
|
### Порт 80: Zabbix и Outlook (Autodiscover)
|
||||||
|
|
||||||
|
До **0.7.8** весь `:80` обрабатывался как «только Zabbix»: любой другой `Host` (в т.ч. Autodiscover при настройке Outlook) получал **403**, fail2ban jail **`haproxy-zabbix-403`** банил IP на сутки через UFW — пользователь мог не знать про Zabbix.
|
||||||
|
|
||||||
|
С **0.7.8** frontend **`fe_http`**:
|
||||||
|
|
||||||
|
| Host / путь | Куда | Allowlist |
|
||||||
|
|-------------|------|-----------|
|
||||||
|
| `autodiscover.kalinamall.ru` | Exchange `.42:80` | нет |
|
||||||
|
| `ext.kalinamall.ru` + `/autodiscover/*` | Exchange `.42:80` | нет |
|
||||||
|
| `zabbix.kalinamall.ru` | Zabbix `.53:80` | **`zabbix-allowed`** |
|
||||||
|
| прочее | **404** (не 403) | — |
|
||||||
|
|
||||||
|
fail2ban **`haproxy-zabbix-403`**: только **403** на Zabbix с IP вне allowlist; в filter добавлен **`ignoreregex`** для `/autodiscover/`.
|
||||||
|
|
||||||
|
После деплоя на **192.168.160.117**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo haproxy -c -f /etc/haproxy/haproxy.cfg && sudo systemctl reload haproxy
|
||||||
|
sudo cp ~/reverse-proxy/scripts/security/fail2ban/haproxy-zabbix-403.conf /etc/fail2ban/filter.d/
|
||||||
|
sudo fail2ban-client reload
|
||||||
|
sudo fail2ban-client set haproxy-zabbix-403 unbanip 5.143.32.177 # если ещё забанен
|
||||||
|
```
|
||||||
|
|
||||||
Если после **Git** в том же браузере **SAC** показывает Gitea — см. [SAC, Seaca и coalescing](docs/sac-access.md).
|
Если после **Git** в том же браузере **SAC** показывает Gitea — см. [SAC, Seaca и coalescing](docs/sac-access.md).
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ sudo haproxy -c -f /etc/haproxy/haproxy.cfg
|
|||||||
|
|
||||||
**Полный план:** [docs/security/README.md](security/README.md) — UFW, бэкенды, чеклист, скрипты `scripts/security/`.
|
**Полный план:** [docs/security/README.md](security/README.md) — UFW, бэкенды, чеклист, скрипты `scripts/security/`.
|
||||||
|
|
||||||
Порт **80** используется для **`http://zabbix.kalinamall.ru`** (allowlist `zabbix-allowed`). Для ACME на других именах см. [letsencrypt-acme.md](letsencrypt-acme.md) — потребуется расширить `fe_http_zabbix` маршрутизацией по Host/пути.
|
Порт **80**: **`fe_http`** — Exchange Autodiscover (`autodiscover`, `ext` + `/autodiscover/*`) и **`http://zabbix.kalinamall.ru`** (allowlist `zabbix-allowed`). Для ACME на других именах см. [letsencrypt-acme.md](letsencrypt-acme.md).
|
||||||
|
|
||||||
## SAC и Seaca (sac-api)
|
## SAC и Seaca (sac-api)
|
||||||
|
|
||||||
@@ -90,6 +90,13 @@ sudo haproxy -c -f /etc/haproxy/haproxy.cfg
|
|||||||
curl -sI --resolve zabbix.kalinamall.ru:80:ПУБЛИЧНЫЙ_IP http://zabbix.kalinamall.ru/
|
curl -sI --resolve zabbix.kalinamall.ru:80:ПУБЛИЧНЫЙ_IP http://zabbix.kalinamall.ru/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Проверка Autodiscover (без allowlist, как Outlook):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sI --resolve autodiscover.kalinamall.ru:80:ПУБЛИЧНЫЙ_IP http://autodiscover.kalinamall.ru/autodiscover/autodiscover.xml
|
||||||
|
# ожидается не 403 (обычно 301/302 на HTTPS или 401 от Exchange)
|
||||||
|
```
|
||||||
|
|
||||||
## Synology DSM (heap, exchange)
|
## Synology DSM (heap, exchange)
|
||||||
|
|
||||||
| Имя | NAS | Порт DSM |
|
| Имя | NAS | Порт DSM |
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
### Через HAProxy (80/443)
|
### Через HAProxy (80/443)
|
||||||
|
|
||||||
- **443**: reject неизвестного SNI; allowlist — git, sac-web, rds, erp, syno; без allowlist — Exchange, sac-api.
|
- **443**: reject неизвестного SNI; allowlist — git, sac-web, rds, erp, syno; без allowlist — Exchange, sac-api.
|
||||||
- **80**: только `Host: zabbix.kalinamall.ru` + `zabbix-allowed`.
|
- **80**: `autodiscover.kalinamall.ru` и `ext.kalinamall.ru/autodiscover/*` → Exchange (без allowlist); `zabbix.kalinamall.ru` + `zabbix-allowed`; прочие Host → 404.
|
||||||
|
|
||||||
Прокси и health-check идут **с IP `.117`**. Бэкенды должны разрешать этот источник (UFW на бэкендах — **позже**, см. [backend-hosts.md](backend-hosts.md)).
|
Прокси и health-check идут **с IP `.117`**. Бэкенды должны разрешать этот источник (UFW на бэкендах — **позже**, см. [backend-hosts.md](backend-hosts.md)).
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
| Git (Gitea) | 192.168.160.129 | 443 | be_git |
|
| Git (Gitea) | 192.168.160.129 | 443 | be_git |
|
||||||
| SAC | 192.168.160.145 | 443 | be_sac |
|
| SAC | 192.168.160.145 | 443 | be_sac |
|
||||||
| Zabbix | 192.168.160.53 | 80 | be_zabbix |
|
| Zabbix | 192.168.160.53 | 80 | be_zabbix |
|
||||||
|
| Exchange (HTTP Autodiscover) | 192.168.160.42 | 80 | be_exchange_http |
|
||||||
| Synology heap | 192.168.160.185 | 5001 | be_syno_heap |
|
| Synology heap | 192.168.160.185 | 5001 | be_syno_heap |
|
||||||
| Synology exchange | 192.168.160.35 | 5001 | be_syno_exchange |
|
| Synology exchange | 192.168.160.35 | 5001 | be_syno_exchange |
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|------|--------|------------------------|---------------------|
|
|------|--------|------------------------|---------------------|
|
||||||
| 22 | sshd | нет DNAT | только `SSH_ALLOWED` |
|
| 22 | sshd | нет DNAT | только `SSH_ALLOWED` |
|
||||||
| 25 | fe_smtp → KSMG | **нет** (25 → `.57`) | **закрыт** |
|
| 25 | fe_smtp → KSMG | **нет** (25 → `.57`) | **закрыт** |
|
||||||
| 80 | fe_http_zabbix | да | все |
|
| 80 | fe_http (Autodiscover + Zabbix) | да | все |
|
||||||
| 443 | fe_https_sni | да | все |
|
| 443 | fe_https_sni | да | все |
|
||||||
| 8404 | stats (закомментирован) | нет | только `SSH_ALLOWED` |
|
| 8404 | stats (закомментирован) | нет | только `SSH_ALLOWED` |
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ Inbound-почта с интернета идёт на **KSMG `.57`**, не на
|
|||||||
| Jail | Что ловит |
|
| Jail | Что ловит |
|
||||||
|------|-----------|
|
|------|-----------|
|
||||||
| `haproxy-reject` | JSON: `"be":"fe_https_sni","srv":"<NOSRV>"` — сканеры, чужой SNI, allowlist reject |
|
| `haproxy-reject` | JSON: `"be":"fe_https_sni","srv":"<NOSRV>"` — сканеры, чужой SNI, allowlist reject |
|
||||||
| `haproxy-zabbix-403` | httplog: `fe_http_zabbix` + `403` |
|
| `haproxy-zabbix-403` | httplog: `fe_http` + **403** только при доступе к Zabbix с IP вне `zabbix-allowed` (не Autodiscover) |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install -y fail2ban
|
sudo apt install -y fail2ban
|
||||||
|
|||||||
+23
-8
@@ -1,7 +1,7 @@
|
|||||||
# HAProxy — периметровый reverse-proxy для kalinamall.ru
|
# HAProxy — периметровый reverse-proxy для kalinamall.ru
|
||||||
# Config version: 0.7.7
|
# Config version: 0.7.8
|
||||||
# Режим: TCP + SNI на 443 (TLS end-to-end, сертификаты на бэкендах)
|
# Режим: TCP + SNI на 443 (TLS end-to-end, сертификаты на бэкендах)
|
||||||
# HTTP на 80: zabbix.kalinamall.ru → 192.168.160.53 (allowlist zabbix-allowed)
|
# HTTP на 80: Exchange Autodiscover (ext/autodiscover) + zabbix.kalinamall.ru (allowlist)
|
||||||
#
|
#
|
||||||
# Проверка синтаксиса: haproxy -c -f haproxy.cfg
|
# Проверка синтаксиса: haproxy -c -f haproxy.cfg
|
||||||
# Установка: скопируйте в /etc/haproxy/haproxy.cfg
|
# Установка: скопируйте в /etc/haproxy/haproxy.cfg
|
||||||
@@ -115,23 +115,38 @@ backend be_syno_exchange
|
|||||||
server syno_exch 192.168.160.35:5001 check check-ssl check-sni exchange.kalinamall.ru verify none
|
server syno_exch 192.168.160.35:5001 check check-ssl check-sni exchange.kalinamall.ru verify none
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# HTTP (80): Zabbix — только HTTP на бэкенде, снаружи http://zabbix.kalinamall.ru
|
# HTTP (80): Exchange Autodiscover (Outlook) + Zabbix UI
|
||||||
# Allowlist: /etc/haproxy/zabbix-allowed
|
# Autodiscover: autodiscover.kalinamall.ru, ext.kalinamall.ru/autodiscover/* → Exchange :80
|
||||||
|
# Zabbix: только Host zabbix.kalinamall.ru + allowlist /etc/haproxy/zabbix-allowed
|
||||||
|
# Прочие Host на :80 → 404 (не 403), чтобы fail2ban не путал с атакой на Zabbix
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
frontend fe_http_zabbix
|
frontend fe_http
|
||||||
bind *:80
|
bind *:80
|
||||||
mode http
|
mode http
|
||||||
option httplog
|
option httplog
|
||||||
option forwardfor except 127.0.0.0/8
|
option forwardfor except 127.0.0.0/8
|
||||||
|
|
||||||
acl host_zabbix hdr(host) -i zabbix.kalinamall.ru
|
acl host_zabbix hdr(host) -i zabbix.kalinamall.ru
|
||||||
|
acl host_autodiscover hdr(host) -i autodiscover.kalinamall.ru
|
||||||
|
acl host_ext hdr(host) -i ext.kalinamall.ru
|
||||||
|
acl path_autodiscover path_beg /autodiscover
|
||||||
acl src_zabbix_allowed src -f /etc/haproxy/zabbix-allowed
|
acl src_zabbix_allowed src -f /etc/haproxy/zabbix-allowed
|
||||||
|
|
||||||
http-request deny deny_status 403 unless host_zabbix
|
# Zabbix: 403 только при неверном IP (fail2ban haproxy-zabbix-403)
|
||||||
http-request deny deny_status 403 if !src_zabbix_allowed
|
http-request deny deny_status 403 if host_zabbix !src_zabbix_allowed
|
||||||
|
|
||||||
default_backend be_zabbix
|
use_backend be_exchange_http if host_autodiscover
|
||||||
|
use_backend be_exchange_http if host_ext path_autodiscover
|
||||||
|
use_backend be_zabbix if host_zabbix
|
||||||
|
|
||||||
|
http-request deny deny_status 404 if !host_zabbix !host_autodiscover !(host_ext path_autodiscover)
|
||||||
|
|
||||||
|
backend be_exchange_http
|
||||||
|
mode http
|
||||||
|
option forwardfor
|
||||||
|
# fifth.kalinamall.ru (192.168.160.42) — IIS Autodiscover / редирект на HTTPS OWA
|
||||||
|
server exch 192.168.160.42:80 check
|
||||||
|
|
||||||
backend be_zabbix
|
backend be_zabbix
|
||||||
mode http
|
mode http
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
failregex = ^.*haproxy\[(?:\d+|master)\]: <HOST>:\d+ \[[^\]]+\] fe_http_zabbix .* 403
|
# 403 на fe_http только при доступе к Zabbix с IP вне zabbix-allowed.
|
||||||
|
# Autodiscover (Outlook) и прочие Host на :80 больше не получают 403 — см. haproxy.cfg fe_http.
|
||||||
|
failregex = ^.*haproxy\[(?:\d+|master)\]: <HOST>:\d+ \[[^\]]+\] fe_http .* 403
|
||||||
|
|
||||||
ignoreregex =
|
# Подстраховка: не банить HTTP Autodiscover, если в логе всё ещё 403
|
||||||
|
ignoreregex = /autodiscover/
|
||||||
|
|||||||
Reference in New Issue
Block a user