Маршрутизация LXC и доступ к контейнерам по SSH

6 min read

В прошлой статье мы познакомились с настройкой окружения для LXC и создали первые контейнеры.

Продолжаем знакомиться с технологией. Из этой статьи вы узнате

Перенаправляем запросы с порта на порт

Внутри контейнера может быть запущен процесс, работающий с какими-то портами, которые должны быть доступны из интернета. Например, Telegram-бот или сайт на Node.js. В таком случае необходимо направить трафик с внешнего порта основного сервера на определенный порт контейнера. 

Для этого воспользуемся iptables.

iptables -t nat -A PREROUTING -i ens3 -p tcp --dport <external_port> -j DNAT --to <host>:<port>

В качестве external_port можно выбрать любой свободный порт на основном сервере. Адрес и порт контейнера, куда отправятся запросы, задаем в параметрах host и port. Выбор портов зависит только от ваших задач. 

Рассмотрим пару примеров, где можно воспользоваться этой командой. 

Настройка SSH-доступа

Для того, чтобы иметь возможность подключаться к контейнеру напрямую по SSH, необходимо перенаправлять запросы с какого-нибудь порта основного сервера на 22 порт этого контейнера.

Создадим правило, по которому все запросы к 1000 порту основного сервера будут направлены на 22 порт container-alice (10.0.1.2).

iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 1000 -j DNAT --to 10.0.1.2:22

Сохраняем параметры iptables

iptables-save > /etc/iptables/rules.v4

Если вы не знакомы с тем, как подключаться к серверу с использованием rsa-ключей, то рекомендуем ознакомиться со статьей «Беспарольный доступ по SSH».

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

lxc exec container-alice /bin/bash

Добавляем ключ в файл authorized_keys

nano ~/.ssh/authorized_keys

Сохраняем файл, выходим из nano и отключаемся от контейнера.

exit

Теперь можно подключиться напрямую к container-alice из терминала вашего компьютера. Вместо myserver.com подставьте доменное имя или адрес сервера.

ssh root@myserver.com -p 1000

Таким образом можно открывать доступ к конкретным контейнерам для администрирования.

Перенаправляем запросы к процессу

К примеру, нам нужно запустить в контейнере с адресом 10.0.1.2 какой-нибудь процесс, который будет слушать порт 1337. При этом мы хотим сделать так, чтобы к этому процессу шли все запросы, которые идут на порт 1400 основного сервера. Тогда нужно выполнить команду с такими параметрами.

iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 1400 -j DNAT --to 10.0.1.2:1337

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

Сохраним новые параметры iptables с помощью следующей команды

iptables-save > /etc/iptables/rules.v4

Подключимся по ssh к контейнеру, чтобы запустить процесс в фоне с помощью screen.

ssh root@myserver.com -p 1000

Создаем терминальную сессию, которую можно будет свернуть

screen

При первом запуске screen вы увидите подобное окно. Нажмите пробел или enter.

Откроется терминальная сессия, как если бы вы просто подключились к серверу

Запустим простой python-сервер, который будет показывать содержимое текущей директории.

python3 -m http.server 1337

Теперь можно свернуть эту терминальную сессию, нажав Ctrl+a, d. Процесс будет продолжать работать в фоне.

Открываем в браузере страницу по адресу вашего сервера и указываем порт, например, http://myserver.com:1400

Проксирование запросов также можно сделать с помощью nginx, если вам нужно задать адрес сайта с помощью поддомена без указания специфичного порта. Для этого на основном сервере нужно отредактировать nginx-конфиг этого контейнера.

nano /etc/nginx/sites-available/container-alice

Добавим в ещё одну секцию server в конец конфига

server { listen 80; server_name python-alice.myserver.com; include proxy_params; location / { proxy_pass http://10.0.1.2:1337/; } }

Перезагружаем nginx

service nginx restart

Теперь та же страница доступна по адресу http://python-alice.myserver.com

Содержимое директории, где был запущен python-скрипт

Запретим общение между контейнерами

Из соображений безопасности стоит сделать невозможным общение контейнеров из разных сетей между собой. Сейчас первый контейнер может пинговать второй и наоборот.

Прописываем ограничения для сети alice-br

iptables -A FORWARD -s 10.0.1.0/24 -i alice-br -o ens3 -j ACCEPT iptables -A FORWARD -i alice-br -j DROP

И для сети bob-br

iptables -A FORWARD -s 10.0.2.0/24 -i bob-br -o ens3 -j ACCEPT iptables -A FORWARD -i bob-br -j DROP

Сохраним параметры iptables

iptables-save > /etc/iptables/rules.v4

Теперь пакеты, которые будут пересылаться за пределы сетей 10.0.1.0/24 и 10.0.2.0/24 никуда не дойдут. Это значит, что если злоумышленник получит доступ к контейнеру в одной сети, то другие сети останутся в безопасности.

Подведем итоги

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

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