kubectl не может разрешить API приватного кластера через OpenVPN
Работающий туннель не делает приватную зону разрешаемой. Сравните отправку резолвера VNet с записями hosts или условным форвардером, затем проверьте конечную точку API.
kubectl терпит неудачу при поиске имени, хотя туннель поднят и приватный адрес API всё ещё отвечает на ping. Маршрут в порядке; клиент спрашивает резолвер, который никогда не слышал о приватной зоне кластера. Чаще всего применяют две правки: отправить резолвер виртуальной сети каждому VPN-клиенту или закрепить имя локально записью в hosts либо условным форвардером. Они решают один и тот же симптом с разной ответственностью, и их путаница приводит к тому, что команды правят файлы hosts каждый раз, когда конечная точка пересобирается.
Разрешение и доступность отказывают на разных уровнях
Выполните поиск сами, прежде чем что-то менять. getent hosts в Linux или nslookup в Windows покажет, получает ли клиент ответ вообще; тайм-аут или NXDOMAIN указывают на резолвер, а ответ с неверным адресом — на устаревшую запись или публичный проход.
Затем подтвердите, к какому серверу kubectl действительно подключается. Контекст kubeconfig хранит URL, и маршрут VPN его не переписывает: если контекст указывает публичную конечную точку, DNS может быть безупречным, а команда всё равно не выполнится.
getent hosts api.internal.example
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'
kubectl -v=8 get nodes 2>&1 | head -40
Третий сигнал — форма сбоя после поиска. Имя, которое разрешается в приватный адрес, а затем получает тайм-аут TCP, — это проблема межсетевого экрана или авторизованной сети. Имя, которое разрешается в публичный адрес, означает, что запрос вышел из приватной зоны. Держите эти три исхода раздельно; каждый ведёт вас к своему ответственному.
Вариант A: отправить резолвер виртуальной сети в туннель
Когда сервер VPN работает внутри виртуальной сети, клиенты могут использовать тот же резолвер, что и хост сервера. В OpenVPN Community сервер отправляет опцию DNS; Access Server показывает ту же настройку в административном интерфейсе, и клиентам нужно скачать профиль заново, потому что директива DNS путешествует внутри него.
# server.conf
push "dhcp-option DNS 10.0.0.4"
push "route 10.0.0.4 255.255.255.255"
Строка маршрута важна в профилях split tunnel. Отправить адрес резолвера — не то же самое, что сделать его достижимым: если через туннель идёт только подсеть кластера, запрос к 10.0.0.4 выходит через локальный LAN и умирает. Отправьте маршрут хоста для резолвера или включите его подсеть в туннель.
У принимающей стороны тоже есть политика. Резолвер, доступный из диапазона адресов клиента, всё равно может отклонять запросы из него, а приватная зона, связанная с виртуальной сетью, отвечает только клиентам, приходящим по DNS-пути этой сети. Если поиск истекает по тайм-ауту после отправки, посмотрите собственные логи резолвера, прежде чем снова трогать клиента.
На клиенте проверьте, что применилось: resolvectl status в Linux с systemd-resolved, scutil --dns в macOS, ipconfig /all в Windows. Отправленный DNS-сервер, который так и не появился, означает, что профиль не перезагрузили.
Вариант B: записи hosts и условная пересылка
Запись hosts — самая маленькая возможная правка и самая хрупкая. Она сопоставляет одно имя одному адресу на одной машине, поэтому годится для демонстрации и ломается, когда приватную конечную точку или её IP пересобирают. Она также скрывает реальный пробел от остальной команды.
Условный форвардер масштабируется лучше, не отправляя DNS каждому клиенту. dnsmasq может отправить одну зону резолверу VNet и оставить всё остальное в покое: server=/cluster.internal/10.0.0.4. В DNS Windows есть условные форвардеры, и клиенты Windows могут использовать правило NRPT для того же разделения. Форвардеру всё ещё нужен маршрут до резолвера VNet.
Пересылка сохраняет обычный просмотр локальным, что важно в split tunnel. Она также даёт одно место для журналирования запросов приватной зоны и одно место, которое ломается, когда хост форвардера переезжает.
Выбирайте по ответственности, а не по удобству
Отправьте резолвер, если вы управляете профилем VPN и хотите, чтобы работало каждое приватное имя, а не только API. Выберите форвардер, если клиенты должны сохранить локальный DNS для всего остального или если VPN управляет другая команда, а не кластер.
Записи hosts — это диагностика, а не развёртывание. Используйте одну, чтобы доказать доступность API, затем уберите её и почините путь резолвера; если оставить её на месте, вопрос маршрутизации позже превратится в поиск сокровищ. Какой бы вариант вы ни выбрали, запишите зону, адрес резолвера и маршрут, который несёт запрос.
Проверяйте конечную точку API, а не только имя
Когда поиск успешен, получите конечную точку версии API с CA кластера. curl --cacert ca.crt https://api.internal.example:6443/version отделяет сбои TLS и авторизации от DNS. 403 означает, что имя и соединение работают, а идентичность нет.
Проверьте также, разрешён ли диапазон адресов клиента авторизованными сетями или межсетевым экраном кластера. Приватные кластеры часто принимают трафик API только из VNet или peered-диапазонов, поэтому туннель, выдающий адреса из другого пула, подключается на сетевом уровне и отбрасывается на API.
Запишите четыре факта при эскалации: резолвер, которым пользовался клиент, адрес, который он вернул, URL сервера в выбранном контексте kubeconfig и первую неудавшуюся операцию. Эта запись скажет следующему инженеру, менять ли DNS, маршрутизацию или политику межсетевого экрана, и остановит следующую правку файла hosts.
Начните с поиска, выберите путь резолвера, соответствующий владельцу зоны, затем проверьте конечную точку. Если все три проходят, оставшаяся проблема — авторизация, а не разрешение имён.