В данном разделе приведены рекомендации для повышения безопасности при использовании ECCM.

Смена паролей по умолчанию

Замена стандартных паролей на уникальные сложные пароли предотвращает несанкционированный доступ к веб-интерфейсу ECCM.

Перейдите в рабочую директорию ECCM:

cd eccm/2.13/

С помощью скрипта update_password.sh измените следующие пароли:

Основные пароли:

Пароли кластера (для отказоустойчивой установки):

При первом запуске скрипт compose-tools.sh сам предложит сгенерировать пароли — нажмите Enter для подтверждения или введите пароли вручную. Сгенерированные пароли сохраняются в файл .env.personal с правами доступа 600, путь к файлу выводится в выводе скрипта.

При необходимости пароли можно изменить вручную в файле .env.personal, который сохраняется при обновлении ECCM. При его отсутствии пароли берутся из файла eccm/.env, который может быть перезаписан при установке нового архива:

ROOT_POSTGRES_PASSWORD="eccm"
ECCM_POSTGRES_PASSWORD="eccm"
PEEPER_MONITOR_POSTGRES_PASSWORD="peeper_monitor"
ECCM_RABBITMQ_PASSWORD="eccm"

При использовании ECCM в отказоустойчивой системе скрипт также предложит изменить пароли кластера, если они являются паролями, заданными по умолчанию.

Запустите контейнеры ECCM с помощью compose-tools.sh и необходимых опций, например:

sudo ./compose-tools.sh --https --start <IP-адрес сервера или его доменное имя>

Для запуска ЕССМ с базой данных на отдельном сервере воспользуйтесь инструкцией в разделе "Инструкция по установке и запуску".

Для запуска ЕССМ в отказоустойчивой системе воспользуйтесь инструкцией в разделе "Запуск ЕССМ в отказоустойчивой системе".

При обновлении ECCM файл .env.personal сохраняется и не перезаписывается. Файл eccm/.env может быть заменен на новый из архива установки — тогда все измененные пароли вернутся к значениям по умолчанию. Чтобы не потерять пароли, используйте файл .env.personal или скопируйте их в новый файл .env после обновления.


Смена паролей при текущей эксплуатации

С помощью скрипта update_password.sh измените все старые пароли на новые или вручную замените в файле .env.personal следующие переменные:

ROOT_POSTGRES_PASSWORD="old_tester_password"
ECCM_POSTGRES_PASSWORD="old_eccm_password"
PEEPER_MONITOR_POSTGRES_PASSWORD="old_peeper_monitor_password"
ECCM_RABBITMQ_PASSWORD="old_rabbitmq_password"

Перезапустите контейнеры ECCM с помощью compose-tools.sh. Новые пароли применятся при запуске системы:

sudo ./compose-tools.sh --stop
sudo ./compose-tools.sh --https --start <IP-адрес сервера или его доменное имя>

С помощью скрипта update_password.sh измените все старые пароли на новые или вручную замените в файле .env.personal следующие переменные на каждом сервере:

ROOT_POSTGRES_PASSWORD="old_tester_password"
ECCM_POSTGRES_PASSWORD="old_eccm_password"
PEEPER_MONITOR_POSTGRES_PASSWORD="old_peeper_monitor_password"
ECCM_RABBITMQ_PASSWORD="old_rabbitmq_password"

 Произведите остановку сервера с сервисами ЕССМ:

sudo ./compose-tools.sh --stop

После полной остановки, повторите команду на сервере с базой данных. 

Запустите базу данных:

sudo ./compose-tools.sh --start <IP адрес сервера или его доменное имя> --database-only

 Запустите сервер с сервисами ЕССМ:

sudo ./compose-tools.sh --https --start <IP-адрес сервера или его доменное имя>

С помощью скрипта update_password.sh измените все старые пароли на новые или вручную замените в файле .env.personal следующие переменные на каждом сервере:

ROOT_POSTGRES_PASSWORD="old_tester_password"
ECCM_POSTGRES_PASSWORD="old_eccm_password"
PEEPER_MONITOR_POSTGRES_PASSWORD="old_peeper_monitor_password"
ECCM_RABBITMQ_PASSWORD="old_rabbitmq_password"
REPMGR_PASSWORD="old_repmgr_password"
RABBITMQ_CLUSTER_PASSWORD="old_rabbitmq_cluster_password"
REDIS_PASSWORD="old_redis_password"
SENTINEL_PASSWORD="old_sentinel_password"

Определите текущего Master и Standby в БД. Подробнее об определении текущего мастера и смене мастерства при необходимости описано в разделе "Обновление 2.12 -> 2.13".

Произведите остановку Slave узла:

sudo ./compose-tools.sh --stop

После полной остановки узла, произведите аналогичную операцию для Witness и Master. 

На каждом узле в конфигурационном файле .env.cluster установите переменной RECONFIGURE_CLUSTER значение true.

Произведите запуск узла мастера:

sudo ./compose-tools.sh --https --start <IP ADDRESS> --cluster master

 После того как мастер будет инициализирован и готов к работе, произведите запуск остальных узлов:

sudo ./compose-tools.sh --https --start <IP ADDRESS> --cluster slave
sudo ./compose-tools.sh --start <IP ADDRESS> --cluster witness

 После успешного запуска установите значение переменной RECONFIGURE_CLUSTER из конфигурационного файла .env.cluster на значение false.

 После изменения значения переменной произведите повторный запуск отказоустойчивой системы, при выполнении каждой из следующих команд дождитесь полного запуска узла:

sudo ./compose-tools.sh --https --start <IP ADDRESS> --cluster master
sudo ./compose-tools.sh --https --start <IP ADDRESS> --cluster slave
sudo ./compose-tools.sh --start <IP ADDRESS> --cluster witness

С помощью скрипта update_password.sh измените все старые пароли на новые или вручную замените в файле .env.personal следующие переменные на каждом сервере:

ROOT_POSTGRES_PASSWORD="old_tester_password"
ECCM_POSTGRES_PASSWORD="old_eccm_password"
PEEPER_MONITOR_POSTGRES_PASSWORD="old_peeper_monitor_password"
ECCM_RABBITMQ_PASSWORD="old_rabbitmq_password"
REPMGR_PASSWORD="old_repmgr_password"
RABBITMQ_CLUSTER_PASSWORD="old_rabbitmq_cluster_password"
REDIS_PASSWORD="old_redis_password"
SENTINEL_PASSWORD="old_sentinel_password"

 Произведите остановку узлов приложений на серверах Master-app и Slave-app:

sudo ./compose-tools.sh --stop

Определите текущего Master и Standby в БД. Подробнее об определении текущего мастера и смене мастерства при необходимости описано в разделе "Обновление 2.12 -> 2.13". 

Далее произведите команду остановки сначала для Slave-db:

sudo ./compose-tools.sh --stop

 После полной остановки узла, выполните аналогичную команду для оставшихся узлов Master-db и Witness.

 На каждом узле в конфигурационном файле .env.cluster установите переменной RECONFIGURE_CLUSTER значение true.

Произведите запуск узла Master-db:

sudo ./compose-tools.sh --start <IP ADDRESS> --cluster master --database-only

 После успешного запуска Master-db, произведите запуск узла Slave-db:

sudo ./compose-tools.sh --start <IP ADDRESS> --cluster master --database-only

 После полной инициализации кластера баз данных, произведите запуск ECCM на узле Master-app:

./compose-tools.sh --https --start <IP ADDRESS> --cluster master --database-host <POSTGRES_MASTER_HOST> --backup-database-host <POSTGRES_SLAVE_HOST>

 После успешного запуска Master-app, перейдите на узлы Slave-app и Witness и произведите их запуск:

./compose-tools.sh --https --start <IP ADDRESS> --cluster slave --database-host <POSTGRES_MASTER_HOST> --backup-database-host <POSTGRES_SLAVE_HOST>
./compose-tools.sh --start <IP ADDRESS> --cluster witness

 После успешного запуска установите значение переменной RECONFIGURE_CLUSTER из конфигурационного файла .env.cluster на значение false.

 После изменения значения переменной произведите повторный запуск отказоустойчивой системы согласно вышеописанной инструкции.


Настройка HTTPS

Запуск веб-интерфейса ECCM по протоколу HTTPS позволяет шифровать трафик между клиентом и приложением, защищая данные от перехвата. Инструкция по настройке доступна в разделе "Настройка доступа к ECCM по HTTPS".


Настройка PostgreSQL

Настройка PostgreSQL позволяет ограничить доступ нежелательных пользователей к базе данных при запуске ECCM в отказоустойчивой системе, или когда база данных находится на отдельном сервере.

Когда ECCM и база данных — на одном сервере, настройка подключений не требуется. По умолчанию контейнер с базой данных при выбранной инсталляции изолирован и недоступен из внешней сети.   

Настройте доступ к БД только с localhost, подсетей docker и адреса администратора при помощи любого текстового редактора в файле postgres/data/pg_hba.cluster.conf.tpl:

# TYPE      DATABASE            USER                              ADDRESS                 METHOD                                                                                                

# "local" is for Unix domain socket connections only                                                                                                                                            
local       all                 all                                                       trust                                                                                                 
# IPv4 local connections:                                                                                                                                                                       
host        all                 all                               127.0.0.1/32            trust                                                                                                 
# IPv6 local connections:                                                                                                                                                                       
host        all                 all                               ::1/128                 trust                                                                                                                                                                                                                                                                                                                                                                                                                                                                

# Docker network internal (172.21.0.0/20) и external (172.20.0.0/20)                                                                                                                            
hostssl     ${ECCM_DATABASE}    ${POSTGRES_USER}                  172.21.0.0/16           md5  # docker network internal                                                                        
hostssl     ${ECCM_DATABASE}    ${ECCM_POSTGRES_USER}             172.21.0.0/16           md5  # docker network internal                                                                        
hostssl     all                 ${PEEPER_MONITOR_POSTGRES_USER}   172.21.0.0/16           md5  # docker network internal                                                                        
hostssl     repmgr              ${REPMGR_USER}                    172.21.0.0/16           md5  # docker network internal                                                                        

hostssl     ${ECCM_DATABASE}    ${POSTGRES_USER}                  172.20.0.0/16           md5  # docker network external                                                                        
hostssl     ${ECCM_DATABASE}    ${ECCM_POSTGRES_USER}             172.20.0.0/16           md5  # docker network external                                                                        
hostssl     all                 ${PEEPER_MONITOR_POSTGRES_USER}   172.20.0.0/16           md5  # docker network external                                                                        
hostssl     repmgr              ${REPMGR_USER}                    172.20.0.0/16           md5  # docker network external

# Опционально: удаленный доступ администратора к БД                                                                                                                                             
hostssl     all                 all                               <admin_ip>/32           md5  # опционально: IP адрес для удаленного подключения администратора к БД

# Опционально: доступ приложений ECCM инсталляции отказоустойчивой системы с БД на отдельном сервере
hostssl     ${ECCM_DATABASE}    ${POSTGRES_USER}                  <master_app_ip>/32      md5  # IP адрес Master-ECCM                                                                       
hostssl     ${ECCM_DATABASE}    ${ECCM_POSTGRES_USER}             <master_app_ip>/32      md5  # IP адрес Master-ECCM                                                                       
hostssl     all                 ${PEEPER_MONITOR_POSTGRES_USER}   <master_app_ip>/32      md5  # IP адрес Master-ECCM
hostssl     repmgr              ${REPMGR_USER}                    <master_app_ip>/32      md5  # IP адрес Master-ECCM

hostssl     ${ECCM_DATABASE}    ${POSTGRES_USER}                  <slave_app_ip>/32       md5  # IP адрес Slave-ECCM                                                                       
hostssl     ${ECCM_DATABASE}    ${ECCM_POSTGRES_USER}             <slave_app_ip>/32       md5  # IP адрес Slave-ECCM                                                                       
hostssl     all                 ${PEEPER_MONITOR_POSTGRES_USER}   <slave_app_ip>/32       md5  # IP адрес Slave-ECCM                                                                       
hostssl     repmgr              ${REPMGR_USER}                    <slave_app_ip>/32       md5  # IP адрес Slave-ECCM                           

IP-адреса всех узлов отказоустойчивой системы будут добавлены автоматически при запуске ECCM.

Синхронизируйте конфигурационные файлы между узлами:

sudo rsync -av --delete --rsync-path="sudo rsync" eccm/2.13/postgres/data/pg_hba.cluster.conf.tpl <имя пользователя сервера>@<IP-адрес сервера назначения>:<полный путь до директории eccm>/postgres/data/

В файле .env.cluster измените значение параметра RECONFIGURE_CLUSTER на true и перезапустите систему в соответствии с инструкцией в разделе "Запуск ECCM в отказоустойчивой системе".

Во избежание ошибок верните значение параметра RECONFIGURE_CLUSTER на false после перезапуска. 

Настройка firewall

Для обеспечения большей безопасности необходимо ограничить внешние подключения к серверу ECCM.

Создайте файл iptables.sh с правилами:

#!/bin/bash

# ---------- адреса ----------
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
WEB_INTERFACE=443          # веб-интерфейс ЕССМ
HTTP_PORT=80               # HTTP-порт для обновления БШПД устройств по HTTP
DHCP_PORT=67               # DHCP-сервер: выдача адресов устройствам
TFTP_PORT=69               # TFTP: загрузка прошивок
SNMP_TRAP_PORT=162         # SNMP-trap: события устройств
SYSLOG_PORT=514            # ECCM_SYSLOG_PORT — прием журналов устройств (UDP и TCP)
SFTP_PORT=2222             # SFTP/SCP загрузчика upgrader (публикация 2222:22 — см. правило ниже)
UPGRADER_SSHD_PORT=22      # порт sshd внутри контейнера upgrader;
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)

ECCM_LOOP_PORTS="$WEB_INTERFACE,$SFTP_PORT,$SYSLOG_PORT,$DB_PORT"
ECCM_LOOP_PORTS_DNAT="$WEB_INTERFACE,$UPGRADER_SSHD_PORT,$SYSLOG_PORT,$DB_PORT"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

# Веб-интерфейс ЕССМ: порт $WEB_INTERFACE — по умолчанию 443
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$WEB_INTERFACE" -j ACCEPT
# Опционально: для ограничения только сетью администратора
# sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$WEB_INTERFACE" -j ACCEPT

# Прием трафика от управляемых устройств
# Опционально: при необходимости сузьте до сети устройств: -s <dev_net>/NN
sudo iptables -A ECCM-CLUSTER -p udp --dport "$DHCP_PORT"      -j ACCEPT   # DHCP: выдача адресов
sudo iptables -A ECCM-CLUSTER -p udp --dport "$TFTP_PORT"      -j ACCEPT   # TFTP: загрузка прошивок
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SNMP_TRAP_PORT" -j ACCEPT   # SNMP-trap: события устройств
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (UDP): журналы
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (TCP)
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$HTTP_PORT" -j ACCEPT        # HTTP: загрузка прошивок БШПД
sudo iptables -A ECCM-CLUSTER -p tcp -m conntrack --ctorigdstport "$SFTP_PORT" -j ACCEPT # Загрузка прошивок

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_LOOP_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_LOOP_PORTS" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_LOOP_PORTS_DNAT" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_LOOP_PORTS_DNAT" -j ACCEPT

Примените правила:

chmod +x iptables.sh
sudo ./iptables.sh

Для того чтобы правила сохранились после перезагрузки, можно использовать утилиту iptables-persistent (или любые другие доступные методы):

sudo apt-get install iptables-persistent
sudo netfilter-persistent save

Создайте файл iptables.sh на сервере с ECCM со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
WEB_INTERFACE=443          # веб-интерфейс ЕССМ
HTTP_PORT=80               # HTTP-порт для обновления БШПД устройств по HTTP
DHCP_PORT=67               # DHCP-сервер: выдача адресов устройствам
TFTP_PORT=69               # TFTP: загрузка прошивок
SNMP_TRAP_PORT=162         # SNMP-trap: события устройств
SYSLOG_PORT=514            # ECCM_SYSLOG_PORT — прием журналов устройств (UDP и TCP)
SFTP_PORT=2222             # SFTP/SCP загрузчика upgrader
UPGRADER_SSHD_PORT=22      # порт sshd внутри контейнера upgrader

ECCM_LOOP_PORTS="$WEB_INTERFACE,$SFTP_PORT,$SYSLOG_PORT"
ECCM_LOOP_PORTS_DNAT="$WEB_INTERFACE,$UPGRADER_SSHD_PORT,$SYSLOG_PORT"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

# Веб-интерфейс ЕССМ: порт $WEB_INTERFACE — по умолчанию 443
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$WEB_INTERFACE" -j ACCEPT
# Опционально: для ограничения только сетью администратора
# sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$WEB_INTERFACE" -j ACCEPT

# Прием трафика от управляемых устройств
# Опционально: при необходимости сузьте до сети устройств: -s <dev_net>/NN
sudo iptables -A ECCM-CLUSTER -p udp --dport "$DHCP_PORT"      -j ACCEPT   # DHCP: выдача адресов
sudo iptables -A ECCM-CLUSTER -p udp --dport "$TFTP_PORT"      -j ACCEPT   # TFTP: загрузка прошивок
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SNMP_TRAP_PORT" -j ACCEPT   # SNMP-trap: события устройств
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (UDP): журналы
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (TCP)
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$HTTP_PORT" -j ACCEPT        # HTTP: загрузка прошивок БШПД
sudo iptables -A ECCM-CLUSTER -p tcp -m conntrack --ctorigdstport "$SFTP_PORT" -j ACCEPT # Загрузка прошивок

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_LOOP_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_LOOP_PORTS" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_LOOP_PORTS_DNAT" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_LOOP_PORTS_DNAT" -j ACCEPT

На сервере с БД создайте файл iptables.sh со следующими правилами:


#!/bin/bash

# ---------- адреса ----------
ECCM_HOST=100.110.2.145    # узел ЕССМ
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов (psql, pgAdmin, бэкап)

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD ACCEPT      # фильтрация опубликованного 5432 — в DOCKER-USER
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

# PostgreSQL
for eccm_node in "$ECCM_HOST" ; do
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$DB_PORT" -j ACCEPT
done
# Опционально: доступ администратора к БД (psql, pgAdmin, выгрузка бэкапов).
sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$DB_PORT" -j ACCEPT

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp --dport "$DB_PORT" \
    -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp --dport "$DB_PORT" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  --dport "$DB_PORT" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  --dport "$DB_PORT" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for eccm_node in "$ECCM_HOST" ; do
  sudo iptables -C INPUT -s "$eccm_node" -p tcp --dport "$DB_PORT" \
    -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$eccm_node" -p tcp --dport "$DB_PORT" -j REJECT --reject-with tcp-reset
done

Примените правила на каждом сервере:

chmod +x iptables.sh
sudo ./iptables.sh

Для того чтобы правила сохранились после перезагрузки, можно использовать утилиту iptables-persistent (или любые другие доступные методы):

sudo apt-get install iptables-persistent
sudo netfilter-persistent save

Создайте файл iptables.sh на узлах Master и Slave со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
MASTER_IP=192.0.2.10       # узел ЕССМ в роли master
SLAVE_IP=192.0.2.11        # узел ЕССМ в роли slave
WITNESS_IP=192.0.2.12      # узел ЕССМ в роли witness
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
WEB_INTERFACE=443          # веб-интерфейс ЕССМ
HTTP_PORT=80               # HTTP-порт для обновления БШПД устройств по HTTP
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)
REDIS_PORT=6379            # Redis (данные)
REDIS_SENTINEL_PORT=26379  # Redis Sentinel
AMQPS_PORT=5671            # RabbitMQ AMQPS — клиентские TLS-соединения
EPMD_PORT=4369             # RabbitMQ epmd — регистрация имен нод
RABBITMQ_CLUSTER_PORT=25672 # RabbitMQ — межузловой канал кластера
DHCP_PORT=67               # DHCP-сервер: выдача адресов устройствам
TFTP_PORT=69               # TFTP: загрузка прошивок
SNMP_TRAP_PORT=162         # SNMP-trap: события устройств
SYSLOG_PORT=514            # ECCM_SYSLOG_PORT — приём журналов устройств (UDP и TCP)
SFTP_PORT=2222             # SFTP/SCP загрузчика upgrader

ECCM_SERVICE_PORTS="$DB_PORT,$REDIS_PORT,$REDIS_SENTINEL_PORT,$AMQPS_PORT,$EPMD_PORT,$RABBITMQ_CLUSTER_PORT,$WEB_INTERFACE"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя
sudo iptables -A INPUT -p vrrp -j ACCEPT                              # Keepalived

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

for eccm_node in "$MASTER_IP" "$SLAVE_IP" "$WITNESS_IP"; do
  # PostgreSQL
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$DB_PORT"             -j ACCEPT
  # Redis
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_PORT"          -j ACCEPT
  # Redis Sentinel
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_SENTINEL_PORT" -j ACCEPT
  # RabbitMQ
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$AMQPS_PORT"          -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$EPMD_PORT"           -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$RABBITMQ_CLUSTER_PORT" -j ACCEPT
done

# Опционально: доступ администратора к БД
# sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$DB_PORT" -j ACCEPT

# Веб-интерфейс ЕССМ: порт $WEB_INTERFACE — по умолчанию 443
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$WEB_INTERFACE" -j ACCEPT
# Опционально: для ограничения только сетью администратора
# sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$WEB_INTERFACE" -j ACCEPT

# Прием трафика от управляемых устройств
# Опционально: при необходимости сузьте до сети устройств: -s <dev_net>/NN
sudo iptables -A ECCM-CLUSTER -p udp --dport "$DHCP_PORT"      -j ACCEPT   # DHCP: выдача адресов
sudo iptables -A ECCM-CLUSTER -p udp --dport "$TFTP_PORT"      -j ACCEPT   # TFTP: загрузка прошивок
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SNMP_TRAP_PORT" -j ACCEPT   # SNMP-trap: события устройств
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (UDP): журналы
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (TCP)
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$HTTP_PORT" -j ACCEPT        # HTTP: загрузка прошивок БШПД
sudo iptables -A ECCM-CLUSTER -p tcp -m conntrack --ctorigdstport "$SFTP_PORT" -j ACCEPT # Загрузка прошивок

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for eccm_node in "$MASTER_IP" "$SLAVE_IP" "$WITNESS_IP"; do
  sudo iptables -C INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset
done

На узле Witness создайте файл iptables.sh со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
MASTER_IP=192.0.2.10       # узел ЕССМ в роли master
SLAVE_IP=192.0.2.11        # узел ЕССМ в роли slave
WITNESS_IP=192.0.2.12      # этот узел, witness

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)
REDIS_SENTINEL_PORT=26379  # Redis Sentinel
AMQPS_PORT=5671            # RabbitMQ AMQPS — клиентские TLS-соединения
EPMD_PORT=4369             # RabbitMQ epmd — регистрация имен нод
RABBITMQ_CLUSTER_PORT=25672 # RabbitMQ — межузловой канал кластера

ECCM_SERVICE_PORTS="$DB_PORT,$REDIS_SENTINEL_PORT,$AMQPS_PORT,$EPMD_PORT,$RABBITMQ_CLUSTER_PORT"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN


for eccm_node in "$MASTER_IP" "$SLAVE_IP"; do
  # PostgreSQL
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$DB_PORT"             -j ACCEPT
  # Redis Sentinel
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_SENTINEL_PORT" -j ACCEPT
  # RabbitMQ
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$AMQPS_PORT"          -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$EPMD_PORT"           -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$RABBITMQ_CLUSTER_PORT" -j ACCEPT
done

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT
done
# Случай 2 вставляется ТРЕТЬИМ в ECCM-CLUSTER: после ACCEPT ESTABLISHED и после
# `! --ctstate DNAT -j RETURN`, но обязательно до LOG и DROP в конце цепи.
sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for eccm_node in "$MASTER_IP" "$SLAVE_IP"; do
  sudo iptables -C INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset
done

Примените правила на каждом сервере:

chmod +x iptables.sh
sudo ./iptables.sh

Для того чтобы правила сохранились после перезагрузки, можно использовать утилиту iptables-persistent (или любые другие доступные методы):

sudo apt-get install iptables-persistent
sudo netfilter-persistent save

Создайте файл iptables.sh на узлах Master-app и Slave-app со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
MASTER_IP=100.110.3.139       # узел ЕССМ в роли master
SLAVE_IP=100.110.2.145        # узел ЕССМ в роли slave
WITNESS_IP=100.110.3.67      # узел ЕССМ в роли witness
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
WEB_INTERFACE=443          # веб-интерфейс ЕССМ
HTTP_PORT=80               # HTTP-порт для обновления БШПД устройств по HTTP
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)
REDIS_PORT=6379            # Redis (данные)
REDIS_SENTINEL_PORT=26379  # Redis Sentinel
AMQPS_PORT=5671            # RabbitMQ AMQPS — клиентские TLS-соединения
EPMD_PORT=4369             # RabbitMQ epmd — регистрация имен нод
RABBITMQ_CLUSTER_PORT=25672 # RabbitMQ — межузловой канал кластера
DHCP_PORT=67               # DHCP-сервер: выдача адресов устройствам
TFTP_PORT=69               # TFTP: загрузка прошивок
SNMP_TRAP_PORT=162         # SNMP-trap: события устройств
SYSLOG_PORT=514            # ECCM_SYSLOG_PORT — приём журналов устройств (UDP и TCP)
SFTP_PORT=2222             # SFTP/SCP загрузчика upgrader

ECCM_SERVICE_PORTS="$REDIS_PORT,$REDIS_SENTINEL_PORT,$AMQPS_PORT,$EPMD_PORT,$RABBITMQ_CLUSTER_PORT,$WEB_INTERFACE"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT
# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя
sudo iptables -A INPUT -p vrrp -j ACCEPT                              # Keepalived

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

for eccm_node in "$MASTER_IP" "$SLAVE_IP" "$WITNESS_IP"; do
  # Redis
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_PORT"          -j ACCEPT
  # Redis Sentinel
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_SENTINEL_PORT" -j ACCEPT
  # RabbitMQ
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$AMQPS_PORT"          -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$EPMD_PORT"           -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$RABBITMQ_CLUSTER_PORT" -j ACCEPT
done

# Веб-интерфейс ЕССМ: порт $WEB_INTERFACE — по умолчанию 443
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$WEB_INTERFACE" -j ACCEPT
# Опционально: для ограничения только сетью администратора
# sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$WEB_INTERFACE" -j ACCEPT

# Прием трафика от управляемых устройств
# Опционально: при необходимости сузьте до сети устройств: -s <dev_net>/NN
sudo iptables -A ECCM-CLUSTER -p udp --dport "$DHCP_PORT"      -j ACCEPT   # DHCP: выдача адресов
sudo iptables -A ECCM-CLUSTER -p udp --dport "$TFTP_PORT"      -j ACCEPT   # TFTP: загрузка прошивок
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SNMP_TRAP_PORT" -j ACCEPT   # SNMP-trap: события устройств
sudo iptables -A ECCM-CLUSTER -p udp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (UDP): журналы
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$SYSLOG_PORT" -j ACCEPT      # Syslog (TCP)
sudo iptables -A ECCM-CLUSTER -p tcp --dport "$HTTP_PORT" -j ACCEPT        # HTTP: загрузка прошивок БШПД
sudo iptables -A ECCM-CLUSTER -p tcp -m conntrack --ctorigdstport "$SFTP_PORT" -j ACCEPT # Загрузка прошивок

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for eccm_node in "$MASTER_IP" "$SLAVE_IP" "$WITNESS_IP"; do
  sudo iptables -C INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$eccm_node" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset
done

На узлах Master-db и Slave-db создайте файл iptables.sh со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
DB_MASTER_IP=100.110.3.203    # узел СУБД в роли master-db
DB_SLAVE_IP=100.110.3.204     # узел СУБД в роли slave-db
ECCM_MASTER_IP=100.110.3.139  # узел ЕССМ в роли master
ECCM_SLAVE_IP=100.110.2.145   # узел ЕССМ в роли slave
ECCM_WITNESS_IP=100.110.3.67 # узел ЕССМ в роли witness
ADMIN_NET=192.0.2.0/24     # сеть рабочих станций администраторов

# ---------- порты ----------
# Все используемые порты — переменные ниже: при нестандартных значениях меняйте только здесь.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD ACCEPT      # фильтрация опубликованного 5432 — в DOCKER-USER
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

# PostgreSQL
for db_client in "$DB_MASTER_IP" "$DB_SLAVE_IP" "$ECCM_MASTER_IP" "$ECCM_SLAVE_IP" "$ECCM_WITNESS_IP"; do
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$db_client" --dport "$DB_PORT" -j ACCEPT
done
# Опционально: доступ администратора к БД (psql, pgAdmin, выгрузка бэкапов).
sudo iptables -A ECCM-CLUSTER -p tcp -s "$ADMIN_NET" --dport "$DB_PORT" -j ACCEPT

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp --dport "$DB_PORT" \
    -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp --dport "$DB_PORT" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  --dport "$DB_PORT" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  --dport "$DB_PORT" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for db_client in "$DB_MASTER_IP" "$DB_SLAVE_IP" "$ECCM_MASTER_IP" "$ECCM_SLAVE_IP" "$ECCM_WITNESS_IP"; do
  sudo iptables -C INPUT -s "$db_client" -p tcp --dport "$DB_PORT" \
    -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$db_client" -p tcp --dport "$DB_PORT" -j REJECT --reject-with tcp-reset
done

На узле Witness создайте файл iptables.sh со следующими правилами:

#!/bin/bash

# ---------- адреса ----------
MASTER_IP=100.110.3.139      # узел ЕССМ в роли master
SLAVE_IP=100.110.2.145        # узел ЕССМ в роли slave
DB_MASTER_IP=100.110.3.203    # узел СУБД в роли master-db
DB_SLAVE_IP=100.110.3.204     # узел СУБД в роли slave-db

# ---------- порты ----------
# Все используемые порты — переменные ниже: изменяйте при нестандартных значениях.
SSH_PORT=22                # SSH узла — хостовый sshd, не контейнер
DB_PORT=5432               # PostgreSQL (POSTGRES_PORT)
REDIS_SENTINEL_PORT=26379  # Redis Sentinel (на witness узла данных Redis нет — 6379 не нужен)
AMQPS_PORT=5671            # RabbitMQ AMQPS — клиентские TLS-соединения
EPMD_PORT=4369             # RabbitMQ epmd — регистрация имен нод
RABBITMQ_CLUSTER_PORT=25672 # RabbitMQ — межузловой канал кластера

ECCM_SERVICE_PORTS="$DB_PORT,$REDIS_SENTINEL_PORT,$AMQPS_PORT,$EPMD_PORT,$RABBITMQ_CLUSTER_PORT"

# ---------- политика по умолчанию ----------
sudo iptables -P INPUT DROP                                           # запрет всех входящих соединений
sudo iptables -P FORWARD ACCEPT                                       # взаимодействие с docker
sudo iptables -P OUTPUT ACCEPT

# ---------- хостовые сервисы ----------
sudo iptables -A INPUT -i lo -j ACCEPT                                # разрешить обращения к localhost
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT   # ответы на исходящие соединения
sudo iptables -A INPUT -p tcp --dport "$SSH_PORT" -j ACCEPT           # SSH
sudo iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT                # опционально: разрешить пинговать себя

# ---------- цепочка сервисных портов ----------
sudo iptables -N ECCM-CLUSTER 2>/dev/null
sudo iptables -F ECCM-CLUSTER                          # файл можно запускать повторно
sudo iptables -C DOCKER-USER -j ECCM-CLUSTER 2>/dev/null \
  || sudo iptables -I DOCKER-USER 1 -j ECCM-CLUSTER   

# Ответы на уже разрешенные соединения и на соединения, открытые контейнером самостоятельно.
sudo iptables -A ECCM-CLUSTER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Фильтрация только новых соединений к опубликованным портам (состояние DNAT)
sudo iptables -A ECCM-CLUSTER -m conntrack ! --ctstate DNAT -j RETURN

for eccm_node in "$MASTER_IP" "$SLAVE_IP"; do
  # Redis Sentinel
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$REDIS_SENTINEL_PORT" -j ACCEPT
  # RabbitMQ
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$AMQPS_PORT"          -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$EPMD_PORT"           -j ACCEPT
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$eccm_node" --dport "$RABBITMQ_CLUSTER_PORT" -j ACCEPT
done

# PostgreSQL
for db_node in "$DB_MASTER_IP" "$DB_SLAVE_IP"; do
  sudo iptables -A ECCM-CLUSTER -p tcp -s "$db_node" --dport "$DB_PORT" -j ACCEPT
done

# Опционально: журнал отброшенных соединений
sudo iptables -A ECCM-CLUSTER -m limit --limit 6/min --limit-burst 20 \
  -j LOG --log-prefix "ECCM-FW: " --log-level 4

# Все остальное к опубликованным портам — отказать.
sudo iptables -A ECCM-CLUSTER -j DROP

# ---------- «петля»: контейнер обращается к своему же узлу ----------
# Нужно, если контейнер ходит в ЕССМ по адресу узла (ECCM_HOSTNAME), а не по имени сервиса.
# Docker не делает DNAT для «своего» моста, поэтому нужны оба правила ниже
for eccm_ifc in external internal docker0 br-+; do
  sudo iptables -C INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
  || sudo iptables -A INPUT -i "$eccm_ifc" -s 172.16.0.0/12 -p tcp \
    -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT
done

sudo iptables -C ECCM-CLUSTER -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT 2>/dev/null \
|| sudo iptables -I ECCM-CLUSTER 3 -s 172.16.0.0/12 -m conntrack --ctstate DNAT -p tcp \
  -m multiport --dports "$ECCM_SERVICE_PORTS" -j ACCEPT

# ---------- быстрое обнаружение отказа ----------
for eccm_peer in "$MASTER_IP" "$SLAVE_IP" "$DB_MASTER_IP" "$DB_SLAVE_IP"; do
  sudo iptables -C INPUT -s "$eccm_peer" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset 2>/dev/null \
  || sudo iptables -A INPUT -s "$eccm_peer" -p tcp -m multiport \
    --dports "$ECCM_SERVICE_PORTS" -j REJECT --reject-with tcp-reset
done

Примените правила на каждом сервере:

chmod +x iptables.sh
sudo ./iptables.sh

Для того чтобы правила сохранились после перезагрузки, можно использовать утилиту iptables-persistent (или любые другие доступные методы):

sudo apt-get install iptables-persistent
sudo netfilter-persistent save


Дополнительная защита сервера

Использование SSH-ключей вместо паролей

Замена доступа по паролям на доступ по генерируемым локальной машиной ключам обеспечивает повышенную безопасность данных.

Сгенерируйте SSH-ключи на локальной машине администратора ECCM:

ssh-keygen

Скопируйте публичный ключ администратора ~/.ssh/id_rsa.pub с локального хоста в файл, расположенный на хосте ECCM ~/.ssh/authorized_keys:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDubL15JQlEi2Nlrblwh+Iw+D8FakZnfs+B6H++YcQRrakoiUW6Zvd6DoSEPcKDMg6qnJ+ ... w/LhsLjD= admin@ECCM-admin

Отключите вход по паролю в /etc/ssh/sshd_config:

...
PasswordAuthentication no          # Запретить вход по паролю
PermitRootLogin no                 # Запретить вход root
PubkeyAuthentication yes           # Разрешить вход по ключам
...

Перезапустите службу sshd:

sudo systemctl restart sshd

Использование Fail2ban

Fail2ban — программа для защиты серверов от brute-force атак, которая автоматически блокирует IP-адреса при множественных неудачных попытках входа по SSH.

В зависимости от типа ОС, выполните одну из следующих команд:

apt-get install fail2ban
yum install fail2ban

Создайте конфигурационный файл и настройте параметры по общим рекомендациям:

sudo vim /etc/fail2ban/ssh.conf
[sshd]
# активируем правило
enabled   = true
# Если Вы сменили порт SSH по умолчанию, замените 1234 на ваш новый порт
port     = ssh,1234
## если в течение 1 часа:
findtime    = 1h
## произведено 6 неудачных попыток логина:
maxretry    = 6
## то банить IP на 2 часа:
bantime     = 2h
# какие ip адреса игнорируются правилом
ignoreip  = 127.0.0.1/8 23.34.45.56
sudo systemctl restart fail2ban

Данный набор условий означает, что IP-адрес, с которого было произведено 6 неудачных попыток SSH-подключения за последний час, будет заблокирован на 2 часа. Не будут блокироваться IP-адреса в диапазоне от 127.0.0.1 до 127.0.0.8 и адрес 23.34.45.56. Стоит обратить внимание, что в данном примере "/8" — не маска, а конечный адрес устройства.

Время для параметров findtime и bantime можно указывать не только в секундах, но и в минутах, часах, днях и даже неделях. Для этого необходимо сразу после численного значения параметра указать соответствующую букву (m, h, d, w).

Команда для вывода на экран сведений о работе jail, отвечающего за службу sshd:

sudo fail2ban-client status sshd

С помощью данной команды можно посмотреть список заблокированных IP-адресов.

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

Status for the jail: sshd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:	

IP-адреса, которые попали в бан:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list: 192.168.х.х

Чтобы разблокировать IP-адрес, который попал в бан (например, 192.168.х.х), используйте следующую команду:

sudo fail2ban-client unban 192.168.x.x

Чтобы разблокировать все адреса, которые попали в бан, используйте следующую команду:

sudo fail2ban-client unban --all

Чтобы разблокировать IP-адрес из jail sshd, используйте следующую команду:

sudo fail2ban-client set sshd unbanip 192.168.x.x