Basic auth пропал на 80-м порту после переезда с Ingress на Gateway API
Все статусы зелёные, мой curl возвращал 401. А вход в WordPress был открыт всем: Gateway API привязывает политику к одному listener'у, а аннотации Ingress покрывали все порты.
Через две недели после того, как мы перевели публичные маркетинговые сайты Optimacros с ingress-nginx на Envoy Gateway — миграцию, проверенную хост за хостом, — страница входа WordPress на всех девяти сайтах оказалась доступна без пароля. Прямо из браузера.
Неприятнее всего то, что все проверки говорили обратное:
- каждая
SecurityPolicyбылаAccepted: True; - каждый
HTTPRoute—AcceptedиResolvedRefs; - проверка Gateway через
curl --resolve <host>:443:<gateway-ip>возвращала 401, ровно как задумано.
Манифесты были правильными, статусы — зелёными, а моя собственная проверка воспроизводила «правильный» ответ. Не соглашался только браузер.
Маршрут жил на одном listener’е
Защищённый маршрут был привязан так:
parentRefs:
- kind: Gateway
name: <gateway>
sectionName: https # только порт 443
Но эта платформа намеренно отдаёт контент на listener’е :80. Внешний nginx-фронт терминирует TLS и ходит в кластер по обычному HTTP, а безусловный редирект на :80 давал ERR_TOO_MANY_REDIRECTS — фильтры Gateway API не умеют «редиректить, только если запрос ещё не HTTPS», потому что не читают X-Forwarded-Proto.
Значит, реальный путь клиентов — порт 80. А на порту 80 маршрута для страницы входа не было вовсе. Запросы проваливались в общее правило PathPrefix: / и попадали в WordPress без всякой аутентификации.
Покрытие не переводится один к одному
Вот концептуальная разница, которая всё и вызвала. ingress-nginx применял аннотации auth-* к Ingress независимо от порта: один объект покрывал и 80, и 443. Gateway API привязывает маршрут — а значит, и любую политику, которая на него нацелена, — к конкретному listener’у. Перевести пути и аннотации один к одному не значит перевести один к одному покрытие.
А проверка через --resolve …:443 перепроверяла ровно тот путь, которым никто не пользуется.
Фикс
Парный HTTPRoute на sectionName: http с тем же Exact-совпадением, тем же бэкендом, тем же секретом basic auth и своей SecurityPolicy. Фильтр заголовка X-Forwarded-Proto: https тоже пришлось скопировать, иначе WordPress, у которого адрес сайта HTTPS, отвечает 301, и фронт уходит в петлю.
Приоритеты по-прежнему на нашей стороне: Gateway API ставит Exact выше PathPrefix, так что AJAX-эндпоинту, на который опираются публичные формы, позже можно дать свой маршрут без аутентификации, не открывая страницу входа. Изменение шло через Git — GitOps-контроллер откатывает всё, что сделано руками, — и было чисто добавочным, так что откат не затронул бы рабочий путь на :443.
Выводы
Accepted: Trueу политики значит, что она привязалась к цели, а не что цель покрывает трафик. Поля статуса «у этого listener’а нет защищённого маршрута» не существует.- Проверяйте тем путём, которым ходят реальные клиенты. За фронтом, терминирующим TLS,
--resolveна 443 — неправильная проверка. Добавьте контрольный хост, который не меняли. - После любого переезда с Ingress на Gateway API проверьте всё, что раньше приходило из аннотаций, не зависящих от порта: аутентификацию, allowlist’ы источников, rate limit, правила WAF.
- Закрыть страницу входа — не значит закрыть WordPress:
xmlrpc.phpаутентифицирует сам и тоже должен быть закрыт на обоих listener’ах.