AWS Client VPN подключён, но EC2 всё равно не отвечает
Подключён означает только то, что сертификат или вход через SAML сработал. Правила авторизации, маршруты endpoint и группы безопасности охраняют каждый свой участок пути к приватному хосту.
Мой ноутбук показывал подключено. Клиент AWS Client VPN показывал зелёное состояние, endpoint записал сессию, и всё равно я не мог открыть порт MongoDB на инстансе EC2 в приватной подсети. Ничего явно не было сломано: сертификат действителен, профиль пришёл из консоли, туннель передавал трафик. Ошибка была моя, потому что я читал подключено как авторизовано.
Вход отвечает ровно на один вопрос: может ли эта учётная запись установить сессию? Всё дальнейшее решают отдельные правила, которые никогда не видят ваш сертификат. Сессия, прошедшая аутентификацию, и пакет, который дошёл, — два разных успеха, и зазор между ними и есть то место, где живёт большинство жалоб вида VPN поднят, но хост недоступен.
Проверки ниже — это порядок, которым я пользуюсь сейчас.
Что на самом деле доказывает подключённая сессия
Во время handshake endpoint проверяет клиентский сертификат по своему trust store или перенаправляет браузер к вашему провайдеру идентичности, если настроен SAML. Если это проходит, клиент получает адрес из клиентского CIDR endpoint, и консоль показывает активное подключение. Ни в один момент этой процедуры никто не спрашивает, можно ли достучаться до 10.0.4.17 по порту 27017.
Разрешение на назначение — отдельный объект на endpoint. Каждый поток сверяется с правилами авторизации, и каждое из них связывает CIDR назначения с группой, которой выдано правило. Когда ни одно правило не покрывает назначение, endpoint принимает сессию и отбрасывает трафик. Нет ни баннера, ни цикла переподключения, ни чего-либо в интерфейсе клиента, что сказало бы отказано.
Сравнивайте правило авторизации с ресурсом, а не с VPC
Перечислите правила и положите их рядом с адресом, который на самом деле есть у инстанса:
aws ec2 describe-client-vpn-authorization-rules \
--client-vpn-endpoint-id cvpn-endpoint-0a1b2c3d4e5f6a7b8Вывод показывает CIDR назначения и идентификатор группы для каждого правила. В нём спрятаны две неисправности. Правило может разрешать 10.0.0.0/16, тогда как инстанс находится в объединённой через peering VPC на 10.1.0.0/16; маршрут peering существует, но никто не написал правило авторизации для второго диапазона. Либо правило указывает на группу каталога, в которой пользователь состоит в каталоге, но не в той группе, которую оценивает endpoint.
Напишите самое узкое правило, которое покрывает назначение, и добавляйте второе только тогда, когда второй CIDR действительно нужен. Широкое правило 0.0.0.0/0 из быстрого старта работает, и именно поэтому оно доживает до продакшена и скрывает модель.
Движение пакета решают две таблицы маршрутов
Маршрут endpoint сопоставляет CIDR назначения с одной из подсетей, с которыми связан endpoint. Это половина пути. Собственная таблица маршрутов подсети всё ещё должна знать, как передать пакет дальше, и это важно в тот момент, когда назначение находится за peering-соединением, transit gateway или локальным диапазоном, доступным через туннель site-to-site.
aws ec2 describe-client-vpn-routes \
--client-vpn-endpoint-id cvpn-endpoint-0a1b2c3d4e5f6a7b8Ищите маршрут, у которого назначение совпадает с CIDR ресурса, а целью является связанная подсеть. Если маршрута нет, добавьте его. Если он есть, а хост молчит, зазор на стороне VPC, поэтому сравните с таблицей маршрутов подсети ассоциации.
Одна настройка на стороне клиента ломает маршрутизацию, не ломая туннель: профиль, содержащий route-nopull. Директива велит клиенту на основе OpenVPN игнорировать маршруты, которые продвигает сервер, поэтому интерфейс поднимается только с собственным адресом endpoint, и у назначения просто нет маршрута. Проверьте с помощью ip route show в Linux или netstat -rn в macOS, есть ли маршрут через интерфейс tun. Если нет, удалите route-nopull из экспортированного профиля и переподключитесь, чтобы продвинутые маршруты применились.
Группы безопасности не видят адрес вашего клиента
Это та часть, которую я целый день понимал неправильно. Для IPv4 endpoint, связанного с подсетью, сервис транслирует адрес источника клиента в адрес сетевого интерфейса endpoint в этой подсети. Пакет, который приходит на инстанс, не несёт адрес, который показывал ваш клиент, поэтому правило группы безопасности, разрешающее пул клиентов, скажем 172.16.0.0/22, не совпадает ни с чем.
Разрешите порт из группы безопасности endpoint, которая прикреплена к интерфейсу ассоциации, а не из клиентского CIDR. Ссылка на группу долговечнее жёстко прописанного адреса, потому что адрес интерфейса не вам контролировать. Сетевые ACL не хранят состояние, поэтому там, где есть собственные записи, и входящее, и исходящее направление должны разрешать поток.
Подключайтесь и к приватному адресу инстанса. Публичный IP выводит пакет из VPC и возвращает его другим путём с другими правилами, поэтому проверка по публичному адресу ничего не говорит о приватном пути.
Порядок изоляции, который останавливается на первой неисправности
Пройдите по этим пунктам по порядку и остановитесь там, где один не проходит. Каждый шаг исключает один слой, а не все сразу.
- Подтвердите, какую учётную запись использовала сессия и какую группу оценивает endpoint. Сертификат из одного trust store не является тем же субъектом, что утверждение SAML из каталога.
- Подтвердите, что правило авторизации покрывает CIDR ресурса для этой группы.
- Подтвердите, что маршрут endpoint существует и указывает на связанную подсеть, а затем что таблица маршрутов подсети умеет передавать дальше.
- Подтвердите, что группа безопасности разрешает порт из интерфейса endpoint, а не из пула клиентов.
- Проверьте изнутри VPC, с сессией SSM на другом инстансе в той же подсети, чтобы отделить проблему приложения от проблемы клиентского пути.
Когда шаги не решают, я опираюсь на эту таблицу:
| Symptom | Layer to inspect |
|---|---|
| Client shows connected, host times out, no byte growth on the interface | Authorization rule, then security group |
| Ping fails but a TCP connect to the port succeeds | ICMP is blocked; not an access failure |
| Tunnel reconnects every few minutes | Two machines sharing one client certificate |
| Works on one laptop, fails on another | Local profile has route-nopull or stale pushed routes |
Две детали учётной записи дают симптомы, похожие на отказ в правах. Каждому пользователю нужен отдельный клиентский сертификат; общий на двух машинах заставляет сессии вытеснять друг друга, и результатом становится цикл переподключения, а не отказ. Когда создаётся новый endpoint, консоль показывает DNS-имя, которое некоторые версии клиента принимают только со случайным префиксом, отображаемым на странице endpoint, поэтому копируйте полное имя, а не восстанавливайте его.
Если пятый шаг заводит в тупик, выгрузите журнал подключений endpoint и прочитайте записи авторизации, прежде чем что-то менять. Журнал называет проверенное назначение и правило, которое совпало или нет, и это сводит вопрос из четырёх слоёв к одному ответу.