Как не запереть себя файрволом на удалённом сервере
Классика жанра: применяешь правила iptables по SSH, нажимаешь Enter — и терминал замирает. Политика DROP сработала раньше, чем правило, разрешающее твоё собственное подключение. Дальше только консоль хостера.
Страховка через systemd-run
Перед применением правил я ставлю отложенный откат. Если после применения я не смогу зайти и отменить его, сервер сам откроется:
# через 3 минуты вернуть всё как было
systemd-run --unit=fw-rollback --on-active=180 \
/bin/bash -c 'iptables -P INPUT ACCEPT; iptables -F INPUT'
/usr/local/sbin/firewall.sh # применить новые правила
# проверить: НОВОЕ ssh-подключение, сайты, сервисы...
# всё работает — отменить откат:
systemctl stop fw-rollback.timer
Сами правила
iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -P INPUT DROP
То же самое — для ip6tables, только вместо icmp нужен ipv6-icmp: без него перестаёт работать обнаружение соседей и IPv6 молча ломается.
Чтобы правила пережили перезагрузку
Я держу правила в скрипте и запускаю его маленьким oneshot-сервисом с After=docker.service. Так правила для входящих не конфликтуют с цепочками, которые создаёт Docker, а сохранять весь iptables-save вместе с ними не приходится.
Проверять нужно именно новое подключение. Старая SSH-сессия держится на правиле
ESTABLISHED и будет работать, даже если новые подключения уже режутся.