Как ограничить доступ по IP
Что проверяют
Понимаете ли вы, на каком уровне стека ставить ограничение и какой IP там на самом деле виден. Следом почти всегда спрашивают: сервис стоит за балансировщиком или CDN, как отличить реальный адрес клиента от адреса прокси.
Как отвечать
Перечислите уровни от внешнего к внутреннему и скажите, что их комбинируют:
- облако: группы безопасности и сетевые ACL. Самый ранний и дешёвый фильтр, трафик не доходит до машины;
- хост:
nftablesилиiptables(на современных дистрибутивах он обычно работает поверх nftables), обёрткиufwиfirewalld. Правила проверяются по порядку, решает первое совпадение; - веб-сервер: в nginx директивы
allowиdenyвнутриlocationсdeny allв конце, в Caddy матчерremote_ip. Удобно, когда закрыть надо один путь, например/admin; - Kubernetes:
NetworkPolicyсipBlock, полеloadBalancerSourceRangesу сервиса типаLoadBalancer, аннотации контроллера ингресса.
Главная тонкость это реальный адрес клиента. За прокси приложение видит IP балансировщика, а настоящий лежит в X-Forwarded-For. Доверять заголовку можно только от своих прокси: в nginx это set_real_ip_from с их подсетями и real_ip_header. В Kubernetes адрес клиента сохраняют через externalTrafficPolicy: Local.
Закончите тем, что белый список IP это дополнительный слой, а не замена аутентификации. Для админок и SSH надёжнее VPN (WireGuard) или бастион, а сам список держат в коде инфраструктуры (Terraform, Ansible), чтобы изменения проходили ревью.
Где спотыкаются
Закрывают порт в ufw и не знают, что Docker публикует порты через собственные цепочки iptables в обход этих правил. Контейнер остаётся доступен всему интернету: фильтровать надо в цепочке DOCKER-USER или не публиковать порт наружу.
Доверяют X-Forwarded-For от кого угодно. Заголовок подделывается одной опцией curl, и ограничение перестаёт работать.
Добавляют запрещающее правило на удалённой машине без запасного доступа и отрезают себе SSH. Второй частый промах: фильтр настроен для IPv4, а через IPv6 сервис доступен без ограничений.