Для доступа в Интернет из приватной сети AWS предоставляет две возможности — NAT Gateway и NAT инстансы.
Сравнение между ними можно почитать тут>>>. Насколько я в курсе — NAT инстансы от AWS появились раньше, а NAT Gateway для VPC — году в 2015. До этого — требовалась ручная настройка NAT на своём инстансе в публичной сети.
Собственно — это и будет задачей на сегодня. Основная цель — уменьшить расходы на инфраструктуру, ибо NAT GW тоже стоит денег.
Дальше выполним:
- создадим вручную VPC с двумя подсетями и инстансами в них
- настроим NAT трансляцию на инстансе в публичной сети
- настроим таблицу маршрутизации для приватной сети на инстанс в публичной сети
Ещё надо будет написать Ansible роль для Bastion хоста для настройки NAT на нём и обновить CloudFormation шаблон для стека RTFM — убрать NAT Gateway и обновить таблицу маршрутизации.
Создание VPC, подсетей, инстансов
VPC
Быстренько делаем всё через веб-консоль.
Создаём VPC:

Subnets
Создаём две подсети в этой VPC — публичную и приватную:


Internet Gateway
Создаём Internet Gateway для доступа VPC к интернету:

Подключаем этот IGW к VPC:


Route Tables
Создаём две таблицы маршрутизации — для публичной и приватной подсетей.
Public Route Table
Таблица для публичной подсети:

Подключаем её к публичной подсети:

Во вкладке Routes добавляем маршрут 0.0.0.0/0 через созданный ранее IGW:


Private Route Table
Аналогично — создаём таблицу для приватной посети, но пока не меняем в ней маршруты — обновим после создания EC2 инстанса, который будет работать в роли NAT-шлюза:

Подключаем её к private subnet:

EC2 инстансы
Запускем два EC2. Один — в публичной сети, он и будет нашим NAT-шлюзом, второй — в приватной подсети.
Первый инстанс:

VPC — nat-test, подсеть — public, присвоить публичный IP — enable:


Второй интстанс — та же VPC, но приватная подсеть, Public IP disable:

В настройках Security Group — разрешаем доступ только из SG публичного инстанса:

Для сетевого интерфейса nat-gw инстанса — отключаем проверку Source/Destination, что бы он мог играть роль NAT-gateway:


Возвращаемся к таблице маршрутизации приватной посети, и задаём маршрут 0.0.0.0/0 через nat-gw инстанс:


Переходим к Security Group nat-gw инстанса, и задаём два правила — 22 отовсюду, и весь трафик для security group инстанса в приватной сети:
Т.е, у нас есть две группы безопасности:
- nat-test-sg — SG для NAT-инстанса, которая разрешает:
- SSH из сети 0.0.0.0/0
- весь трафик из SG nat-test-sg-priv
- nat-test-sg-priv — SSH из сети nat-test-sg
Понятно, что если будут сервисы типа NGINX на сервере в публичной сети — то добавляем порты 80 и 443 в группу nat-test-sg, и если какая-то MySQL на инстансе в приватной сети — то добавляем 3306 для доступа из nat-test-sg.
Тут всё готово.
Настройка NAT на EC2
Логинимся на EC2 в публичной сети:
ssh ubuntu@34.250.81.116 -i .ssh/rtfm-dev.pem
...
ubuntu@ip-10-0-0-245:~$ sudo -s
sudo: unable to resolve host ip-10-0-0-245
root@ip-10-0-0-245:~#
Проверяем интернет на нём:
root@ip-10-0-0-245:~# ping -c 1 ya.ru
PING ya.ru (87.250.250.242) 56(84) bytes of data.
64 bytes from ya.ru (87.250.250.242): icmp_seq=1 ttl=45 time=47.6 ms
--- ya.ru ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 47.687/47.687/47.687/0.000 ms
Копируем на него ключ и логинимся на инстанс в приватной подсети:
root@ip-10-0-0-245:~# ssh ubuntu@10.0.1.7 -i .ssh/rtfm.dev.pem
...
ubuntu@ip-10-0-1-7:~$
Проверяем доступ в интернет — должен сфейлится, т.к. NAT ещё не настроен:
ubuntu@ip-10-0-1-7:~$ ping -c 1 ya.ru
PING ya.ru (87.250.250.242) 56(84) bytes of data.
--- ya.ru ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
ОК, всё хорошо — доступа нет. Возвращаемся на nat-gw, проверяем таблицу nat
в IPTABLES:
root@ip-10-0-0-245:~# iptables -vL -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Настраиваем NAT:
root@ip-10-0-0-245:~# echo 1 > /proc/sys/net/ipv4/ip_forward
root@ip-10-0-0-245:~# iptables --table nat --append POSTROUTING --source 10.0.0.0/16 --destination 0.0.0.0/0 --jump MASQUERADE
Проверяем правила таблицы ещё раз:
root@ip-10-0-0-245:~# iptables -vL -t nat
Chain PREROUTING (policy ACCEPT 33 packets, 2676 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 3 packets, 188 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 307 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
4 307 MASQUERADE all -- any any 10.0.0.0/16 anywhere
Снова переходим на приватный инстанс — проверяем ещё раз:
ubuntu@ip-10-0-1-7:~$ ping -c 1 ya.ru
PING ya.ru (87.250.250.242) 56(84) bytes of data.
64 bytes from ya.ru (87.250.250.242): icmp_seq=1 ttl=41 time=45.9 ms
--- ya.ru ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 45.996/45.996/45.996/0.000 ms
Всё работает.
NAT on startup
Последний штрих — добавить включение NAT при рестарте NAT-инстанса.
Создаём каталог для правил IPTABLES:
Сохраняем правила:
iptables-save > /etc/iptables/iptables.rules
Находим исполняемый файл iptables-restore
:
which iptables-restore
/sbin/iptables-restore
Создаём systemd-сервис iptables
:
mkdir /usr/lib/systemd/system
vim /usr/lib/systemd/system/iptables.service
Указываем:
[Unit]
Description=Packet Filtering Framework
Before=network-pre.target
Wants=network-pre.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/iptables.rules
ExecReload=/sbin/iptables-restore /etc/iptables/iptables.rules
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Проверяем:
systemd-analyze verify /usr/lib/systemd/system/iptables.service
Добавляем в автозапуск:
systemctl enable iptables.service
Created symlink from /etc/systemd/system/multi-user.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service.
Обновляем /etc/sysctl.conf
, добавляем forwading постоянно:
...
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
...
Сохраняем, перезагружаем машину:
root@ip-10-0-0-245:~# reboot
Connection to 34.250.81.116 closed by remote host.
Connection to 34.250.81.116 closed.
После перезагрузки проверяем статус IPTABLES:
ubuntu@ip-10-0-0-245:~$ systemctl status iptables.service
● iptables.service - Packet Filtering Framework
Loaded: loaded (/usr/lib/systemd/system/iptables.service; enabled; vendor preset: enabled)
Active: active (exited) since Mon 2017-10-16 11:56:35 UTC; 59s ago
Process: 828 ExecStart=/sbin/iptables-restore /etc/iptables/iptables.rules (code=exited, status=0/SUCCESS)
Main PID: 828 (code=exited, status=0/SUCCESS)
Tasks: 0
Memory: 0B
CPU: 0
CGroup: /system.slice/iptables.service
Oct 16 11:56:35 ip-10-0-0-245 systemd[1]: Starting Packet Filtering Framework...
Oct 16 11:56:35 ip-10-0-0-245 systemd[1]: Started Packet Filtering Framework.
Правила:
ubuntu@ip-10-0-0-245:~$ sudo iptables -vL -t nat
sudo: unable to resolve host ip-10-0-0-245
Chain PREROUTING (policy ACCEPT 8 packets, 1098 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 2 packets, 148 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 7 packets, 502 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
7 502 MASQUERADE all -- any any 10.0.0.0/16 anywhere
И доступ в интернет с инстанса в приватной сети:
ubuntu@ip-10-0-0-245:~$ ssh -t ubuntu@10.0.1.7 -i .ssh/rtfm.dev.pem "ping -c 1 ya.ru"
PING ya.ru (87.250.250.242) 56(84) bytes of data.
64 bytes from ya.ru (87.250.250.242): icmp_seq=1 ttl=41 time=48.2 ms
--- ya.ru ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 48.291/48.291/48.291/0.000 ms
Connection to 10.0.1.7 closed.
Всё работает.
P.S. не забываем удалить все тестовые ресурсы 🙂