Введение
Развертывание отдельных компонентов в настройках вашего приложения на разных узлах – это общий способ снижения нагрузки и начала масштабирования горизонтально. Типичным примером является настройка базы данных на отдельном сервере от вашего приложения. Хотя существует ряд преимуществ такой настройки, подключение через сеть включает в себя новый набор проблем безопасности.
В этом руководстве мы продемонстрируем, как настроить брандмауэр на каждом из ваших серверов в распределенной среде. Мы настроим нашу политику так, чтобы разрешить предполагаемый трафик между нашими компонентами, отклоняя другой трафик.
Вы также можете настроить Облачные брандмауэры DigitalOcean, которые работают как дополнительный внешний слой к вашим серверам на инфраструктуре DigitalOcean. Таким образом, вам не нужно настраивать брандмауэр на самих серверах.
Для демонстрации в этом руководстве мы будем использовать два сервера Ubuntu 22.04. Один будет обслуживать веб-приложение с помощью Nginx, а другой будет хостить базу данных MySQL для приложения. Хотя мы будем использовать эту настройку в качестве примера, вы сможете экстраполировать используемые методы для вашего собственного требования к серверу.
Предварительные условия
Для начала вам понадобятся два новых сервера Ubuntu 22.04. Добавьте обычную учетную запись пользователя с привилегиями sudo
на каждом из них. Для этого следуйте нашему руководству по настройке исходного сервера Ubuntu 22.04.
Настройка приложения, которое мы будем обеспечивать безопасностью, основана на этом руководстве. Если вы хотите следовать этому примеру, настройте ваши серверы приложений и базы данных, как указано в этом учебнике. В противном случае, вы можете использовать эту статью в качестве общей справки.
Шаг 1 — Настройка брандмауэра
Вы начнете с реализации базовой конфигурации брандмауэра для каждого из ваших серверов. Политика, которую мы будем реализовывать, основана на безопасности в первую очередь. Мы будем блокировать практически все, кроме SSH-трафика, а затем пробивать отверстия в брандмауэре для нашего конкретного приложения.
В этом руководстве используется синтаксис iptables
. iptables
автоматически устанавливается в Ubuntu 22.04 с использованием бэкенда nftables
, поэтому вам не нужно устанавливать дополнительные пакеты.
Используя nano
или ваш редактор текста, откройте файл /etc/iptables/rules.v4
:
- sudo nano /etc/iptables/rules.v4
Вставьте конфигурацию из руководства по шаблону брандмауэра:
*filter
# Разрешить все исходящие, но по умолчанию отбрасывать входящие и пересылаемые пакеты
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# Пользовательские цепи для каждого протокола
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]
# Допустимый трафик UDP
# Допустимый трафик TCP
-A TCP -p tcp --dport 22 -j ACCEPT
# Допустимый трафик ICMP
# Основная политика принятия
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
# Отбрасывать недопустимые пакеты
-A INPUT -m conntrack --ctstate INVALID -j DROP
# Перенаправление трафика в протоколо-специфические цепи
## Разрешить только новые соединения (установленные и связанные уже должны быть обработаны)
## Для TCP дополнительно разрешить только новые SYN-пакеты, так как это единственный допустимый
## метод установки нового TCP-соединения
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
# Отклонять все, что не прошло до этой точки
## Попытаться быть протоколо-специфичным с сообщением об отклонении
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
# Применить изменения
COMMIT
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
Сохраните и закройте файл. Если вы используете nano
, нажмите Ctrl+X
для выхода, затем по запросу введите Y
, а затем Enter.
Если вы выполняете это в живой среде, пока не перезагружайте правила брандмауэра. Загрузка набора правил, описанных здесь, немедленно прервет соединение между вашим приложением и сервером базы данных. Вам нужно будет настроить правила в соответствии с нашими операционными потребностями перед перезагрузкой.
Шаг 2 — Определите используемые порты ваших служб
Для обеспечения взаимодействия между компонентами вам необходимо знать используемые сетевые порты. Вы можете найти правильные сетевые порты, изучив ваши конфигурационные файлы, но метод, не зависящий от приложения, для нахождения правильных портов заключается в проверке, на какие службы происходит прослушивание соединений на каждой из наших машин.
Для этого вы можете использовать инструмент netstat
. Поскольку ваше приложение общается только по протоколу IPv4, мы добавим аргумент -4
, но вы можете удалить его, если также используете IPv6. Другие аргументы, необходимые для поиска работающих служб, – это -p
, -l
, -u
, -n
и -t
, которые вы можете указать как -plunt
.
Эти аргументы можно разделить следующим образом:
p
: Show the PID and name of the program to which each socket belongs.l
: Show only listening sockets.u
: Show UDP traffic.n
: Show numeric output instead of service names.t
: Show TCP traffic.
- sudo netstat -4plunt
На вашем веб-сервере вывод может выглядеть так:
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1058/sshd
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 4187/nginx
Первый выделенный столбец показывает IP-адрес и порт, на котором прослушивается служба, выделенная в конце строки. Специальный адрес 0.0.0.0
означает, что соответствующая служба прослушивает все доступные адреса.
На вашем сервере базы данных вывод может выглядеть так:
- sudo netstat -4plunt
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1097/sshd
tcp 0 0 192.0.2.30:3306 0.0.0.0:* LISTEN 3112/mysqld
Вы можете прочитать эти столбцы точно так же. В этом примере адрес 192.0.2.30
представляет собой частный IP-адрес сервера базы данных. В предыдущем учебнике вы ограничили доступ MySQL только к частному интерфейсу из соображений безопасности.
Обратите внимание на значения, найденные на этом шаге. Это сетевые данные, которые вам потребуется настроить в конфигурации вашего брандмауэра.
На вашем веб-сервере вам необходимо убедиться, что доступны следующие порты:
- Порт 80 на всех адресах
- Порт 22 на всех адресах (уже учтен в правилах брандмауэра)
Ваш сервер баз данных должен обеспечить доступность следующих портов:
- Порт 3306 на адресе
192.0.2.30
(или на связанном с ним интерфейсе) - Порт 22 на всех адресах (уже учтен в правилах брандмауэра)
Шаг 3 — Настройка правил брандмауэра веб-сервера
Теперь, когда у вас есть необходимая информация о портах, вы настроите набор правил брандмауэра вашего веб-сервера. Откройте файл правил в вашем редакторе с привилегиями sudo
:
- sudo nano /etc/iptables/rules.v4
На веб-сервере вам нужно добавить порт 80 в список допустимого трафика. Поскольку сервер слушает все доступные адреса — веб-серверы обычно ожидают доступа откуда угодно — вы не ограничите правило по интерфейсу или адресу назначения.
Ваши веб-посетители будут использовать протокол TCP для подключения. Ваш фреймворк уже имеет пользовательскую цепь с именем TCP
для исключений приложений TCP. Вы можете добавить порт 80 в эту цепь, прямо под исключением для вашего порта SSH:
*filter
. . .
# Допустимый TCP-трафик
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 80 -j ACCEPT
. . .
Ваш веб-сервер инициирует соединение с сервером базы данных. Исходящий трафик не ограничен в вашем брандмауэре, и входящий трафик, связанный с установленными соединениями, разрешен, поэтому нам не нужно открывать дополнительные порты на этом сервере для разрешения этого соединения.
Сохраните и закройте файл, когда закончите. Теперь у вашего веб-сервера есть политика брандмауэра, которая позволит всем легитимным трафикам, блокируя все остальное.
Протестируйте файл правил на наличие синтаксических ошибок:
- sudo iptables-restore -t < /etc/iptables/rules.v4
Если синтаксические ошибки не отображаются, перезагрузите брандмауэр, чтобы применить новый набор правил:
- sudo service iptables-persistent reload
Шаг 4 — Настройка правил брандмауэра сервера базы данных
На сервере базы данных вам нужно разрешить доступ к порту 3306
по частному IP-адресу вашего сервера. В этом случае это был адрес 192.0.2.30
. Вы можете ограничить доступ именно к этому адресу, или вы можете ограничить доступ, сравнивая с интерфейсом, которому назначен этот адрес.
Чтобы найти сетевой интерфейс, связанный с этим адресом, выполните команду ip -4 addr show scope global
:
- ip -4 addr show scope global
Output2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 203.0.113.5/24 brd 104.236.113.255 scope global eth0
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.0.2.30/24 brd 192.0.2.255 scope global eth1
valid_lft forever preferred_lft forever
Выделенные области показывают, что интерфейс eth1
связан с этим адресом.
Затем вы настроите правила брандмауэра на сервере базы данных. Откройте файл правил с привилегиями sudo
на вашем сервере базы данных:
- sudo nano /etc/iptables/rules.v4
Снова вы будете добавлять правило в нашу цепочку TCP
, чтобы создать исключение для соединения между вашим веб- и базами данных серверами.
Чтобы ограничить доступ на основе фактического адреса, вы можете добавить правило следующим образом:
*filter
. . .
# Приемлемый TCP-трафик
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -d 192.0.2.30 -j ACCEPT
. . .
Если вы предпочитаете разрешить исключение на основе интерфейса, содержащего этот адрес, вы можете добавить правило, подобное следующему:
*filter
. . .
# Приемлемый TCP-трафик
-A TCP -p tcp --dport 22 -j ACCEPT
-A TCP -p tcp --dport 3306 -i eth1 -j ACCEPT
. . .
Сохраните и закройте файл, когда закончите.
Проверьте наличие синтаксических ошибок с помощью этой команды:
- sudo iptables-restore -t < /etc/iptables/rules.v4
Когда будете готовы, перезагрузите правила брандмауэра:
- sudo service iptables-persistent reload
Теперь оба ваших сервера должны быть защищены без ограничения необходимого потока данных между ними.
Заключение
Внедрение правильного брандмауэра всегда должно быть частью вашего плана развертывания при установке приложения. Хотя мы продемонстрировали эту конфигурацию с использованием двух серверов, работающих на Nginx и MySQL, представленные выше техники применимы независимо от ваших конкретных технологических выборов.
Чтобы узнать больше о брандмауэрах и iptables
в частности, ознакомьтесь с следующими руководствами: