Table of Contents
Работа zabbix-прокси за NAT
Вводная
Есть головной офис HQ1 в котором стоит zabbix-сервер.
Всё сетевое оборудование HQ1 под нашим управлением, есть внешний ip адрес 80.x.x.201
Есть офис POP1 с мобильным интернетом или интернетом который даёт владелец здания.
Постоянного внешнего адреса нет, по Source NAT в интернет офис выходит с адресом их сети 178.x.x.0/24.
Внутрь POP1 сделать Destination NAT нельзя.
И есть машина подскока jb1 c постоянным внешним адресом 51.144.x.142.
ВM jb1 работает у одного из провайдера облаков или VCP .
L3-схема.
Необходимо в офисе POP1 разместить zabbix-прокси (mon1), который будет подключаться к zabbix-серверу в HQ1.
Так же надо обеспечить ssh доступ к mon1, что бы иметь возможность поправить какие-нибудь настройки.
Zabbix-прокси может работать на чём угодно - RaspberryPi, ВМ, железный сервер или машина.
В данном случае mon1 это ВМ с Centos8.
Схема решения:
- C mon1 до jb1 настраиваем обратный ssh-туннель (-R), обеспечиваем управление.
- Обращения с mon1 к zabbix-серверу, с помощью redsocks, заворачиваем на jb1 через динамический ssh-туннель (-D).
Тем самым, mon1 к zabbix-серверу будет обращаться с адреса 51.144.x.142, а не с внешнего адреса офиса POP1. - SSH-туннели запускаем через autossh.
- На mon1 настраиваем zabbix-proxy.
Обратный ssh-туннель
Что бы с jb1 получить доступ к машине mon1, необходимо с построить обратный ssh-туннель c до jb1.
В общем случаем, это делается следующей командой:
[root@mon1 ~]# ssh -f -N -R 22002:127.0.0.1:22 root@jumpbox.sitename.com
В результате, на jb1 будет слушаться tcp порт 22002.
[root@jb1 ~]# netstat -nap | grep 22002 tcp 0 0 127.0.0.1:22002 0.0.0.0:* LISTEN
Обращения на порт 22002 будут перенаправлены на машину mon1 на порт 22.
Что бы подключиться к mon1 на jb1 нужно будет дать команду:
[root@jb1 ~]# ssh -p 22002 root@127.0.0.1
Динамический ssh-туннель
Динамический ssh-туннель это фактически локальный SOCKS-сервер, запросы к которому будут через ssh доставлены к удалённой машине.
В общем случаем, это туннель поднимается следующей командой:
[root@mon1 ~]# ssh -f -N -D 127.0.0.1:31010 root@jumpbox.sitename.com
На mon1 начнет слушаться порт tcp/31010.
[root@mon1 ~]# netstat -nap | grep 3101 tcp 0 0 127.0.0.1:31010 0.0.0.0:* LISTEN 22216/ssh
SOCKS обращения на этот порт будут перенаправлены по ssh на удаленный сервер jumpbox.sitename.com и дальше трафик пойдет как будто от jumpbox.
Дальше рассмотрим как авторизовываться не под пользователем root и как автоматически поднимать и поддерживать ssh-туннель.
Настройка и использование autossh
Для автоматического старта и поддержания ssh-туннеля есть программа autossh.
Установка и тест autossh
[root@mon1 ~]# yum install autossh
Тестово запускаем autossh на mon1.
[root@mon1 ~]# autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -N -R 22002:127.0.0.1:22 root@jb1.sitename.com" Password:
Картина со стороны jb1.
[root@jb1 ~]# netstat -nap | less ... tcp 0 0 127.0.0.1:22002 0.0.0.0:* LISTEN 13988/sshd: root ...
Если со стороны jb1 сбросить ssh-сессию ([root@jb1 ~]# kill 13988), то со стороны mon1 autossh попробует ещё раз поднять ssh-туннель.
Настройки со стороны ssh-сервера
Заводим пользователя, под которым дальше будем логиниться на jb1 и строить туннели.
В данном случае это пользователь “autossh”.
[root@jb1 .ssh]$ useradd autossh [root@jb1 .ssh]$ cat /etc/passwd | grep autossh autossh:x:1013:1013::/home/autossh:/bin/bash
Правим /etc/ssh/sshd_config, запрещаем пользователю autossh логиниться по паролю и разрешаем форвардинг.
[root@jb1 .ssh]$ cat /etc/ssh/sshd_config ... Match User autossh AllowTcpForwarding yes PasswordAuthentication no AllowAgentForwarding no ForceCommand echo 'This account can only be used for one secret thing' ...
Дальше надо как-то обменяться ssh-ключами.
Способ обмена ключами зависит от конкретной ситуации.
Обычно mon1 настраивается заранее и доступ к нему есть.
Мне удобнее создать все ключи на jb1 и передать их на mon1.
На jb1 генерим новую пару ключей, делаем от пользователя autossh.
[root@jb1 .ssh]$ su - autossh [autossh@jb1 ~]$ cd .ssh/ [autossh@jb1 .ssh]$ ssh-keygen -t rsa -b 8192 -f ~/.ssh/autossh_to_jb1_from_mon1_id_rsa
Добавляем свежий публичный ключ в authorized_keys.
[autossh@jb1 .ssh]$ cp authorized_keys authorized_keys.bup \ && echo "#key_for_mon1" >> authorized_keys \ && cat autossh_to_jb1_from_mon1_id_rsa.pub >> authorized_keys \ && echo "#/key_for_mon1" >> authorized_keys
Отправляем приватную часть ключа на mon1.
На mon1 autossh будем запускать от root, копируем ключ в папку рута.
[autossh@jb1 .ssh]$ scp autossh_to_jb1_from_mon1_id_rsa root@z.z.z.z:/root/.ssh
Со стороны jb1 все сделали.
Настройка со стороны ssh-клиента
Системный пользователь autossh создался при установке autossh, с ним делать ничего не надо.
[root@mon1 ~]# cat /etc/passwd | grep auto autossh:x:990:986:autossh service account:/etc/autossh:/usr/sbin/nologin
Отключаем проверку ssh ключей при подключении к jb1.
Идем на это, что бы при смене ssh ключа на jb1, обратные ssh-туннели продолжали строиться.
[root@mon1 .ssh]# cat ~/.ssh/config Host jumpbox.sitename.com StrictHostKeyChecking no UserKnownHostsFile=/dev/null ServerAliveInterval=30 ServerAliveCountMax=3
Пишем юнит-файлы для запуска туннелей через systemd.
Обратный ssh-туннель.
[root@mon1 ~]# cat /etc/systemd/system/autossh-r-22-jb1.service [Unit] Description=AutoSSH reverse ssh tunnel to jb1 After=network.target [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \ -N -R 22002:127.0.0.1:22 -i /root/.ssh/autossh_to_jb1_from_mon1_id_rsa autossh@jumpbox.sitename.com [Install] WantedBy=multi-user.target
Динамический ssh-туннель.
[root@mon1 ~]# cat /etc/systemd/system/autossh-d-31010-jb1.service [Unit] Description=AutoSSH dynamic tunnel to jb1 After=network.target [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -M 0 -N -D 127.0.0.1:31010 -i /root/.ssh/autossh_to_jb1_from_mon1_id_rsa autossh@jb1.sitename.com [Install] WantedBy=multi-user.target
Применяем изменения, запускаем и включаем автозагрузку.
[root@mon1 ~]# systemctl daemon-reload [root@mon1 ~]# systemctl start autossh-d-31010-jb1 autossh-r-22-jb1 [root@mon1 ~]# systemctl enable autossh-d-31010-jb1 autossh-r-22-jb1
С autossh все, перегружаем mon1 и проверяем, что все туннели поднялись.
Работа с redsocks
Есть не активно поддерживающийся, но работающий проект redsocks, который позводяет через iptables завернуть трафик приложения в SOCKS-сервер.
Фактически redsocks это прослойка между SOCKS-сервером и приложением не поддерживающий работу через SOCKS.
Будем использовать redsocks, что бы на mon1 завернуть трафик от zabbix-прокси к zabbix-серверу в динамический ssh-туннель.
В результате до zabbix-сервера трафик zabbix-прокси будет доходить от внешнего ip адреса jb1.
Установка redsocks
Ставим нужные пакеты.
[root@mon1 ~]# yum install git gcc libevent libevent-devel make [root@mon1 ~]# yum group install "Development Tools"
Клонируем репозиторий.
[root@mon1 ~]# mkdir src [root@mon1 ~]# cd src/ [root@mon1 src]# git clone https://github.com/darkk/redsocks.git Cloning into 'redsocks'... remote: Enumerating objects: 1043, done. remote: Total 1043 (delta 0), reused 0 (delta 0), pack-reused 1043 Receiving objects: 100% (1043/1043), 776.60 KiB | 1.90 MiB/s, done. Resolving deltas: 100% (683/683), done.
Компилируется одной командой make.
[root@mon1 src]# cd redsocks/ [root@mon1 redsocks]# make cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o parser.o parser.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o main.o main.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o redsocks.o redsocks.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o log.o log.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o http-connect.o http-connect.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o socks4.o socks4.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o socks5.o socks5.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o http-relay.o http-relay.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o base.o base.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o base64.o base64.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o md5.o md5.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o http-auth.o http-auth.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o utils.o utils.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o redudp.o redudp.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o dnstc.o dnstc.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o dnsu2t.o dnsu2t.c dnsu2t.c:50:22: warning: ‘dnsq_soa_root’ defined but not used [-Wunused-const-variable=] static const uint8_t dnsq_soa_root[] = { ^~~~~~~~~~~~~ cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -c -o gen/version.o gen/version.c cc -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE -Wall -o redsocks parser.o main.o redsocks.o log.o http-connect.o socks4.o socks5.o http-relay.o base.o base64.o md5.o http-auth.o utils.o redudp.o dnstc.o dnsu2t.o gen/version.o -levent_core
В результате в директории появится бинарник redsocks, который надо будет скопировать, например, в “/bin”.
[root@mon1 redsocks]# ll ... -rwxr-xr-x 1 root root 514416 ноя 1 17:37 redsocks ... [root@mon1 redsocks]# mv redsocks /bin/
Настройка redsocks
Создаем конфигурационный файл в директории “/etc/redsocks”.
Правим порты и пока выключаем режим демона.
[root@mon1 redsocks]# cat /etc/redsocks/redsocks.conf base { // debug: connection progress log_debug = off; // info: start and end of client session log_info = on; /* possible `log' values are: * stderr * "file:/path/to/file" * syslog:FACILITY facility is any of "daemon", "local0"..."local7" */ log = stderr; // log = "file:/path/to/file"; // log = "syslog:local7"; // detach from console daemon = off; /* possible `redirector' values are: * iptables - for Linux * ipf - for FreeBSD * pf - for OpenBSD * generic - some generic redirector that MAY work */ redirector = iptables; } redsocks { /* `local_ip' defaults to 127.0.0.1 for security reasons, * use 0.0.0.0 if you want to listen on every interface. * `local_*' are used as port to redirect to. */ local_ip = 127.0.0.1; local_port = 31000; // `ip' and `port' are IP and tcp-port of proxy-server // You can also use hostname instead of IP, only one (random) // address of multihomed host will be used. ip = 127.0.0.1; port = 31010; // known types: socks4, socks5, http-connect, http-relay type = socks5; // login = "foobar"; // password = "baz"; }
Локальные обращения к 127.0.0.1:31000 будут перенаправляться на 127.0.0.1:31010 в виде socks5 “запросов”.
А на порту 31010 у нас висит динамический ssh-туннель до jb1.
Тестово запускаем redsocks
Для теста будем заворачивать трафик к ipinfo.io и смотреть какой внешний адрес показывает.
ВМ mon1 в интернет без redsocks выходит с адресом 178.x.x.7.
[root@mon1 system]# curl ipinfo.io { "ip": "178.x.x.7", "city": "Moscow", "region": "Moscow", "country": "RU", "loc": "55.7520,37.6150", "org": , "postal": "117246", "timezone": "Europe/Moscow", "readme": "https://ipinfo.io/missingauth" }
Имя ipinfo.io резолвится в 4 ip адреса.
[root@mon1 system]# host ipinfo.io ipinfo.io has address 216.239.38.21 ipinfo.io has address 216.239.34.21 ipinfo.io has address 216.239.36.21 ipinfo.io has address 216.239.32.21 ...
Ловим трафик и завоорачиваем на redsock порт 31000.
[root@mon1 system]# cat /etc/sysconfig/iptables ############################################################################### *nat :PREROUTING ACCEPT [39:1750] :INPUT ACCEPT [1:60] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A OUTPUT -p tcp -d 216.239.32.21/32 -j REDIRECT --to-ports 31000 -A OUTPUT -p tcp -d 216.239.34.21/32 -j REDIRECT --to-ports 31000 -A OUTPUT -p tcp -d 216.239.36.21/32 -j REDIRECT --to-ports 31000 -A OUTPUT -p tcp -d 216.239.38.21/32 -j REDIRECT --to-ports 31000 COMMIT ################################################################################ *filter :INPUT ACCEPT [0:0] ...
Руками запускаем redsocks.
[root@mon1 system]# /bin/redsocks -c /etc/redsocks/redsocks.conf 1604432720.612731 notice main.c:167 main(...) redsocks started, conn_max=128
Проверяем адрес, mon1 выходит через ВМ jb1.
[root@mon1 ~]# curl ipinfo.io { "ip": "51.144.x.142", "city": "Amsterdam", "region": "North Holland", "country": "NL", "loc": "52.3618,4.9280", "org": "AS8075 Microsoft Corporation", "postal": "1093", "timezone": "Europe/Amsterdam", "readme": "https://ipinfo.io/missingauth" }
Все работает.
Лог redsocks.
... 1604432723.304937 info redsocks.c:1243 redsocks_accept_client(...) [10.170.1.17:54474->216.239.34.21:80]: accepted 1604432723.551905 info redsocks.c:671 redsocks_drop_client(...) [10.170.1.17:54474->216.239.34.21:80]: connection closed ...
Автозапуск redsocks
В конфиге /etc/redsocks/redsocks.conf ставим “daemon = on”.
Пишем юнит-файл.
[root@mon1 system]# cat /etc/systemd/system/redsocks.service [Unit] Description=Transparent redirector of any TCP connection to proxy using your firewall StartLimitBurst=5 StartLimitIntervalSec=10 [Service] Type=forking PIDFile=/run/redsocks.pid EnvironmentFile=/etc/redsocks/redsocks.conf ExecStartPre=/bin/redsocks -t -c /etc/redsocks/redsocks.conf ExecStart=/bin/redsocks -c /etc/redsocks/redsocks.conf -p /run/redsocks.pid ExecStopPost=/bin/rm /run/redsocks.pid Restart=always RestartSec=1 [Install] WantedBy=multi-user.target
Применяем изменения, запускаем и включаем автозагрузку.
[root@mon1 ~]# systemctl daemon-reload [root@mon1 ~]# systemctl start redsocks [root@mon1 ~]# systemctl enable redsocks
Все, redsocks настроен.
Установка и настройка zabbix-proxy
Ставим репозиторий.
[root@mon1 ~]# rpm -i https://repo.zabbix.com/zabbix/4.0/rhel/8/x86_64/zabbix-release-4.0-2.el8.noarch.rpm warning: /var/tmp/rpm-tmp.zvV0js: Header V4 RSA/SHA512 Signature, key ID a14fe591: NOKEY
Ставим zabbix-прокси с поддержкой sqlite.
yum install zabbix-proxy-sqlite3
Создаем базу и меняем владельца.
[root@mon1 ~]# mkdir /var/lib/sqlite-zbx [root@mon1 ~]# gunzip /usr/share/doc/zabbix-proxy-sqlite3/schema.sql.gz [root@mon1 ~]# sqlite3 /var/lib/sqlite-zbx/zabbix_proxy.db < /usr/share/doc/zabbix-proxy-sqlite3/schema.sql [root@mon1 ~]# chown -R zabbix:zabbix /var/lib/sqlite-zbx/
Правим конфиг zabbix-прокси.
... Server=80.x.x.201 ... Hostname=proxy30-mon1 ... DBName=/var/lib/sqlite-zbx/zabbix_proxy.db ... TLSConnect=psk ... TLSAccept=psk ... TLSPSKIdentity=PSK_OighJuber0 ... TLSPSKFile=/etc/zabbix/zbxpsk ...
Создаем файл с psk и правим права.
[root@mon1 zabbix]# openssl rand -hex 36 > /etc/zabbix/zbxpsk [root@mon1 zabbix]# cat /etc/zabbix/zbxpsk f856c36f2bee726156e62604a15b49a9abc00d6b9f9ee8e5e02d30fec2a90d5b9bc19f98 [root@mon1 zabbix]# chown zabbix:zabbix zbxpsk [root@mon1 zabbix]# chmod 400 zbxpsk
Правим iptables, ловим трафик в zabbix-серверу.
[root@mon1 zabbix]# cat /etc/sysconfig/iptables ############################################################################### *nat :PREROUTING ACCEPT [39:1750] :INPUT ACCEPT [1:60] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] #CATCH_TRAFFIC_TO_ZABBIX_SERVER -A OUTPUT -p tcp -d 80.x.x.201/32 --dport 10051 -j REDIRECT --to-ports 31000 COMMIT ################################################################################ *filter :INPUT ACCEPT [0:0] ...
Запускаем zabbix-прокси.
[root@mon1 zabbix]# systemctl start zabbix-proxy [root@mon1 zabbix]# systemctl enable zabbix-proxy Created symlink /etc/systemd/system/multi-user.target.wants/zabbix-proxy.service → /usr/lib/systemd/system/zabbix-proxy.service.
Добавляем свеженастроенный проски на zabbix-сервер.
Всё, настройка закончена.
Еще раз перегружаем mon1 и проверяем, что все тунели и сервисы поднялись.