Развёртывание туннелей MCP с помощью Helm
Установите стек туннеля в кластер Kubernetes с помощью Helm-чарта Anthropic.
Helm-чарт Anthropic устанавливает стек туннеля как единый Deployment и подключает его к вашему туннелю: либо к тому, который создаёт для вас хук настройки чарта, либо к существующему туннелю, созданному вами в Claude Console.
Перед началом работы
Вам понадобится:
- Туннель. При программном доступе хук настройки чарта создаёт туннель для вас, если вы не указали ID туннеля; чтобы вместо этого подключиться к существующему туннелю, создайте его в Console и запишите ID туннеля (
tnl_...). Ручная подготовка всегда начинается с туннеля, созданного в Console; вам также понадобятся его токен туннеля и домен туннеля. - Способ аутентификации чарта в Tunnels API.
- Программный доступ (рекомендуется). Компонент настройки проходит аутентификацию через Workload Identity Federation, получает токен туннеля, генерирует CA, регистрирует его в Anthropic и сохраняет всё в Secret. Вам нужно правило федерации с областью действия
workspace:manage_tunnels. - Вручную. Без программного доступа. Вы получите токен туннеля в Console, самостоятельно сгенерируете CA и серверный сертификат, зарегистрируете CA в Console и передадите учётные данные в кластер в виде Secret.
- Программный доступ (рекомендуется). Компонент настройки проходит аутентификацию через Workload Identity Federation, получает токен туннеля, генерирует CA, регистрирует его в Anthropic и сохраняет всё в Secret. Вам нужно правило федерации с областью действия
- Кластер Kubernetes, в который вы можете выполнять развёртывание с помощью
helmиkubectl. На вкладке Без программного доступа также используетсяopenssl(версии 1.1.1 или новее). - Исходящее сетевое подключение из кластера к
api.anthropic.com(443 TCP) и к периметру туннеля (7844 TCP и UDP). См. полные сетевые требования. - Один или несколько серверов MCP, запущенных и доступных из кластера по адресам, которые вы настроите в
gateway.config.routes. Если у вас его ещё нет, используйте пример сервера.
Необязательно: использование примера сервера MCP
Если у вас нет сервера MCP для тестирования, используйте этот минимальный сервер:
kubectl create namespace mcp-tunnel --dry-run=client -o yaml | kubectl apply -f -
kubectl -n mcp-tunnel apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-mcp-src
data:
hello_server.py: |
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-server", host="0.0.0.0", port=9000)
@mcp.tool()
def hello(name: str = "world") -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-mcp
spec:
replicas: 1
selector:
matchLabels: { app: hello-mcp }
template:
metadata:
labels: { app: hello-mcp }
spec:
containers:
- name: hello-mcp
image: python:3.13-slim
command: ["sh", "-c", "pip install --quiet mcp && python /app/hello_server.py"]
volumeMounts:
- { name: src, mountPath: /app }
ports:
- { containerPort: 9000 }
volumes:
- name: src
configMap: { name: hello-mcp-src }
---
apiVersion: v1
kind: Service
metadata:
name: hello-mcp
spec:
selector: { app: hello-mcp }
ports:
- { port: 9000, targetPort: 9000 }
EOFВ последующих шагах установки указано, где добавить соответствующий маршрут.
Установка
Компонент настройки обменивает проецируемый токен ServiceAccount кластера через ваше правило федерации, получает токен туннеля, генерирует CA и серверный сертификат и регистрирует CA в Anthropic. Ежедневный CronJob при необходимости обновляет серверный сертификат, поэтому вам не нужно обращаться с секретами вручную.
Настройте Workload Identity Federation для кластера
Следуйте инструкциям Использование WIF с Kubernetes, чтобы зарегистрировать OIDC-издателя вашего кластера и создать правило федерации. Компонент настройки работает под собственным ServiceAccount в пространстве имён релиза; точное имя формируется по соглашению Helm
fullname, поэтому для любого имени релиза, отличного отmcp-tunnel, выполнитеhelm template <release> ... | grep -A2 'kind: ServiceAccount', чтобы проверить его перед созданием правила. Далее в этом руководстве предполагается имя релизаmcp-tunnelв пространстве имёнmcp-tunnel, где ServiceAccount называетсяmcp-tunnel-setup.Поле Значение Subject system:serviceaccount:mcp-tunnel:mcp-tunnel-setupAudience api.anthropic.com(значение чарта по умолчанию; без схемы)Scope workspace:manage_tunnelsЕсли туннель находится в рабочем пространстве, отличном от рабочего пространства организации по умолчанию, также добавьте сервисный аккаунт правила в это рабочее пространство (Tunnels API выполняет авторизацию на основе членства сервисного аккаунта в рабочих пространствах).
Запишите идентификатор правила (
fdrl_...); вы укажете его вapi.wif.federationRuleId.Получите значения по умолчанию
helm show values \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 > values.yamlНастройте подключение к туннелю и маршруты
Отредактируйте
values.yamlи задайте ключиapi.wif.*с идентификатором правила федерации и идентификатором организации, а также записьroutesдля каждого вышестоящего сервера MCP:values.yamlapi: wif: federationRuleId: "fdrl_..." organizationId: "00000000-0000-0000-0000-000000000000" # Set when the tunnel is in a non-default workspace and the # rule's service account is a member of that workspace. # workspaceId: "wrkspc_..." tunnel: # Leave empty to have the setup hook create a tunnel during install. # Set to attach to an existing tunnel from the Console. id: "" # Increment to rotate the tunnel token on the next upgrade. # See the "Rotate the tunnel token" section. tokenVersion: "1" gateway: config: routes: docs: http://docs-mcp.internal:8080 search: http://search-mcp.internal:8080С этими маршрутами Claude обращается к серверам по адресам
docs.<your-tunnel-domain>иsearch.<your-tunnel-domain>. Некоторые управляемые дистрибутивы Kubernetes выделяют Service CIDR вне стандартных частных диапазонов; если ваши маршруты указывают на Services внутри кластера, добавьте здесьgateway.config.upstream.allowed_ips, как описано в разделе Проверка IP-адресов вышестоящих серверов.Проверьте сгенерированные манифесты
Сгенерируйте чарт и проверьте результат в соответствии с практиками проверки вашей организации:
helm template mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 \ -n mcp-tunnel \ -f values.yaml > rendered.yamlУстановите
helm install mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 \ --namespace mcp-tunnel --create-namespace \ -f values.yamlКомпонент настройки запускается как Job pre-install-хука Helm, поэтому
helm installблокируется до его завершения. При успешном выполнении Helm автоматически удаляет Job. Еслиhelm installзавершается ошибкой хука, см. Ошибки аутентификации компонента настройки.Если
tunnel.idпуст, компонент настройки создаёт туннель в рабочем пространстве, на которое нацелено ваше правило федерации (рабочее пространство организации по умолчанию, если вы не задалиapi.wif.workspaceId), и сохраняет его идентификатор и домен в Secretmcp-tunnel. Домен, который понадобится вам для проверки, можно найти на странице сведений о туннеле, которая открывается со страницы MCP tunnels (platform.claude.com/settings/workspaces/default/mcp-tunnels) в Console. В селекторе рабочих пространств на боковой панели выберите рабочее пространство, содержащее туннель. Вы также можете прочитать домен из Secret:kubectl -n mcp-tunnel get secret mcp-tunnel \ -o jsonpath='{.data.tunnel-domain}' | base64 -dПовторный запуск компонента настройки (во время обновлений или ротации токена) повторно использует идентификатор туннеля, сохранённый в этом Secret; второй туннель никогда не создаётся.
В этом режиме (setup.enabled: false) чарт не выполняет вызовов API; компонент настройки не запускается, и CronJob cert-renew отсутствует. Используйте этот путь, если вы предпочитаете не настраивать Workload Identity Federation.
Получите токен и домен туннеля
Сгенерируйте CA и серверный сертификат
Прокси прослушивает обычный WebSocket, а внутренний TLS передаётся внутри этого потока с использованием сертификата, который вы генерируете здесь. SAN серверного сертификата должен включать
*.<tunnel-domain>, как описано в требованиях к сертификатам.export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE mkdir -p mcp-tunnel/data cd mcp-tunnel # Самоподписанный CA. Расширения заданы явно, чтобы сертификат удовлетворял # требованиям независимо от настроек openssl.cnf по умолчанию в дистрибутиве. openssl req -x509 -newkey rsa:2048 -nodes \ -keyout data/ca.key -out data/ca.crt \ -days 3650 -subj "/CN=mcp-tunnel-ca" \ -addext "basicConstraints=critical,CA:TRUE" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -addext "subjectKeyIdentifier=hash" # Файл расширений для сертификата сервера. Использование -extfile (вместо # -copy_extensions, доступного только в OpenSSL 3.0+) сохраняет работоспособность на # OpenSSL 1.1.x. cat > data/tls.ext <<EOF subjectAltName = DNS:${TUNNEL_DOMAIN},DNS:*.${TUNNEL_DOMAIN} authorityKeyIdentifier = keyid,issuer extendedKeyUsage = serverAuth EOF # Сертификат сервера, подписанный CA openssl req -newkey rsa:2048 -nodes \ -keyout data/tls.key -out /tmp/server.csr \ -subj "/CN=${TUNNEL_DOMAIN}" openssl x509 -req -in /tmp/server.csr \ -CA data/ca.crt -CAkey data/ca.key -CAcreateserial \ -out data/tls.crt -days 90 \ -extfile data/tls.extЗарегистрируйте
data/ca.crtв Console. Хранитеdata/ca.keyв надёжном и защищённом месте; он понадобится вам для подписи нового серверного сертификата при обновлении.Создайте два Secret
Чарт считывает определённые ключи; имена Secret настраиваются, а ключи — нет. Следующая команда создания пространства имён ничего не делает, если пространство имён уже существует (например, после шага с примером сервера MCP).
kubectl create namespace mcp-tunnel --dry-run=client -o yaml | kubectl apply -f - kubectl -n mcp-tunnel create secret generic mcp-tunnel-token \ --from-literal=tunnel-token='eyJ...' kubectl -n mcp-tunnel create secret generic mcp-tunnel-cert \ --from-file=tls.crt=data/tls.crt \ --from-file=tls.key=data/tls.keyПолучите значения по умолчанию
helm show values \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 > values.yamlНастройте значения для ручной подготовки
Отредактируйте
values.yamlи задайте следующие ключи:values.yamlsetup: enabled: false external: tunnelTokenSecretName: mcp-tunnel-token # must contain key: tunnel-token serverCertSecretName: mcp-tunnel-cert # must contain keys: tls.crt, tls.key gateway: config: # Required when setup.enabled is false. Replace the placeholder with # the $TUNNEL_DOMAIN value you exported earlier. When setup.enabled # is true the chart injects this from the Secret as a -tunnel-domain # flag instead. tunnel_domain: YOUR_TUNNEL_DOMAIN_HERE routes: docs: http://docs-mcp.internal:8080 search: http://search-mcp.internal:8080Некоторые управляемые дистрибутивы Kubernetes выделяют Service CIDR вне стандартных частных диапазонов; если ваши маршруты указывают на Services внутри кластера, добавьте здесь
gateway.config.upstream.allowed_ips, как описано в разделе Проверка IP-адресов вышестоящих серверов.Проверьте сгенерированные манифесты
helm template mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 \ -n mcp-tunnel \ -f values.yaml > rendered.yamlУстановите
helm install mcp-tunnel \ oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \ --version 2.1.0 \ --namespace mcp-tunnel --create-namespace \ -f values.yaml
Проверка развёртывания
Выполните сквозную проверку со стороны Anthropic: используйте https://<route>.<your-tunnel-domain>/<path> в сеансе Managed Agent или в запросе к Messages API, где <route> — ключ из gateway.config.routes, а <path> — путь, по которому обслуживает запросы вышестоящий сервер MCP. Для примера сервера MCP это https://echo.<your-tunnel-domain>/mcp. Форматы запросов см. в разделе Использование туннелированных серверов MCP.
Если проверка не удалась, просмотрите журналы пода (kubectl -n mcp-tunnel logs deploy/mcp-tunnel -c mcp-proxy и -c cloudflared) и обратитесь к разделу Устранение неполадок.
Дополнительная настройка
Ограничение исходящего трафика с помощью NetworkPolicy
Входящий трафик к поду прокси по умолчанию запрещён (networkPolicy.ingress.enabled: true). Чтобы дополнительно ограничить исходящий трафик пода, задайте networkPolicy.egress.enabled: true и заполните networkPolicy.egress.mcpServers селекторами меток подов или диапазонами CIDR, охватывающими ваши вышестоящие серверы MCP. Исходящий трафик от cloudflared к периметру туннеля разрешается отдельно через networkPolicy.egress.cloudflaredEgressCIDRs.
Настройка прокси
Поля в gateway.config.* передаются в файл конфигурации прокси. Типичные настройки включают upstream.allowed_ips, log_level и upstream.tls. Полный список полей см. в справочнике по конфигурации прокси. Чарт всегда задаёт listen_addr, tls.cert_file и tls.key_file; их указание в gateway.config не имеет эффекта.
Использование собственного токена OIDC
По умолчанию чарт проецирует токен Kubernetes ServiceAccount для компонента настройки. Чтобы использовать токен от другого поставщика удостоверений (например, SPIFFE, Vault или sidecar облачного SDK), смонтируйте его с помощью setup.extraVolumes и setup.extraVolumeMounts. Затем укажите путь монтирования в api.wif.tokenFile. Чарт задаёт ANTHROPIC_IDENTITY_TOKEN_FILE равным этому пути, и компонент настройки считывает токен оттуда.
Обновления
Всегда передавайте --version в helm upgrade, чтобы неожиданно не получить более новую версию чарта.
Обновление с чарта 1.x
Чарт 2.0.0 переносит идентификатор туннеля из api.wif.tunnelId в tunnel.id. Перед обновлением отредактируйте ваш values.yaml: перенесите значение tnl_... в tunnel.id и удалите api.wif.tunnelId. Оставить tunnel.id незаданным безопасно (при повторном запуске компонент настройки повторно использует идентификатор туннеля, уже сохранённый в Secret mcp-tunnel), но явный перенос сохраняет точность вашего values.yaml. Также измените в Console область вашего правила федерации с org:manage_tunnels на workspace:manage_tunnels.
Изменение конфигурации
Для рутинных изменений, таких как маршруты, количество реплик или NetworkPolicy:
helm upgrade mcp-tunnel \
oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \
--version 2.1.0 \
-n mcp-tunnel \
-f values.yamlРотация токена туннеля
При программном доступе увеличьте tunnel.tokenVersion в values.yaml и выполните обновление с --set setup.force=true. Компонент настройки повторно запускается при обновлениях только принудительно:
helm upgrade mcp-tunnel \
oci://us-docker.pkg.dev/anthropic-public-registry/charts/mcp-tunnel \
--version 2.1.0 \
-n mcp-tunnel \
-f values.yaml \
--set setup.force=trueКомпонент настройки проходит аутентификацию с помощью Workload Identity Federation; токена API, который нужно отзывать, нет.
Без программного доступа нажмите Rotate token на странице сведений о туннеле в Console, затем обновите Secret mcp-tunnel-token:
kubectl -n mcp-tunnel create secret generic mcp-tunnel-token \
--from-literal=tunnel-token='eyJ...' --dry-run=client -o yaml | kubectl apply -f -
kubectl -n mcp-tunnel rollout restart deploy/mcp-tunnelОбновление сертификата
Чарт обеспечивает автоматизацию, но вы по-прежнему отвечаете за отслеживание срока действия и подтверждение завершения обновления.
При программном доступе обновление сертификата выполняется автоматически. Чарт развёртывает CronJob (названный по Helm fullname с суффиксом -cert-renew), который ежедневно запускает setup renew-cert (по расписанию serverCert.cronSchedule, по умолчанию 0 0 * * * UTC). Задание ничего не делает, если до истечения срока действия сертификата остаётся больше serverCert.renewBefore (по умолчанию 30 дней). Обновление выполняется локально: задание подписывает новый сертификат с помощью CA, уже сохранённого в Secret, не выполняет вызовов API и нуждается только в Kubernetes RBAC, который предоставляет чарт. Прокси выполняет горячую перезагрузку сертификата из смонтированного Secret, поэтому перезапуск Deployment не требуется.
Без программного доступа CronJob отсутствует. Находясь в каталоге mcp-tunnel/, сохранённом после установки, подпишите новый серверный сертификат существующим CA (не генерируйте CA заново):
export TUNNEL_DOMAIN=YOUR_TUNNEL_DOMAIN_HERE
openssl req -new -key data/tls.key -out /tmp/server.csr \
-subj "/CN=${TUNNEL_DOMAIN}"
openssl x509 -req -in /tmp/server.csr \
-CA data/ca.crt -CAkey data/ca.key -CAcreateserial \
-out data/tls.crt -days 90 -extfile data/tls.ext
kubectl -n mcp-tunnel create secret generic mcp-tunnel-cert \
--from-file=tls.crt=data/tls.crt --from-file=tls.key=data/tls.key \
--dry-run=client -o yaml | kubectl apply -f -Прокси выполняет горячую перезагрузку сертификата из смонтированного Secret.
Следующие шаги
Подключите вышестоящий сервер MCP к Managed Agent или к Messages API.
Рекомендации по усилению защиты, ротация учётных данных и реагирование на инциденты.
Диагностика проблем с подключением, TLS и маршрутизацией.
Was this page helpful?