Helm으로 MCP 터널 배포하기
Anthropic Helm 차트를 사용하여 Kubernetes 클러스터에 터널 스택을 설치합니다.
Anthropic Helm 차트는 터널 스택을 단일 Deployment로 설치하고 이를 터널에 연결합니다. 연결 대상은 차트의 설정 훅이 생성해 주는 터널이거나, Claude Console에서 직접 생성한 기존 터널입니다.
시작하기 전에
다음이 필요합니다:
- 터널. 프로그래밍 방식 액세스를 사용하는 경우, 터널 ID를 제공하지 않으면 차트의 설정 훅이 터널을 생성해 줍니다. 대신 기존 터널에 연결하려면 Console에서 터널을 생성하고 터널 ID(
tnl_...)를 기록해 두세요. 수동 프로비저닝은 항상 Console에서 생성한 터널에서 시작하며, 해당 터널의 터널 토큰과 터널 도메인도 필요합니다. - 차트가 Tunnels API에 인증하는 방법.
- 프로그래밍 방식 액세스(권장). 설정 컴포넌트가 Workload Identity Federation을 통해 인증하고, 터널 토큰을 가져오고, CA를 생성하여 Anthropic에 등록한 다음, 모든 것을 Secret에 저장합니다.
workspace:manage_tunnels범위로 지정된 페더레이션 규칙이 필요합니다. - 수동. 프로그래밍 방식 액세스를 건너뜁니다. Console에서 터널 토큰을 가져오고, CA와 서버 인증서를 직접 생성하고, Console에 CA를 등록한 다음, 자격 증명을 Secret으로 클러스터에 제공합니다.
- 프로그래밍 방식 액세스(권장). 설정 컴포넌트가 Workload Identity Federation을 통해 인증하고, 터널 토큰을 가져오고, CA를 생성하여 Anthropic에 등록한 다음, 모든 것을 Secret에 저장합니다.
helm및kubectl로 배포할 수 있는 Kubernetes 클러스터. 프로그래밍 방식 액세스 없이 탭에서는openssl(1.1.1 이상)도 사용합니다.- 클러스터에서
api.anthropic.com(443 TCP) 및 터널 엣지(7844 TCP 및 UDP)로의 아웃바운드 네트워크 연결. 전체 네트워크 요구 사항을 참조하세요. gateway.config.routes아래에 구성할 주소에서 클러스터로부터 접근 가능하며 실행 중인 하나 이상의 MCP 서버. 아직 없다면 샘플 서버를 사용하세요.
선택 사항: 샘플 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이어지는 설치 단계에서 해당 라우트를 추가할 위치를 안내합니다.
설치
설정 컴포넌트는 페더레이션 규칙을 통해 클러스터의 projected ServiceAccount 토큰을 교환하고, 터널 토큰을 가져오고, CA와 서버 인증서를 생성하고, CA를 Anthropic에 등록합니다. 매일 실행되는 CronJob이 필요에 따라 서버 인증서를 갱신하므로 시크릿을 직접 다룰 필요가 없습니다.
클러스터에 대한 Workload Identity Federation 설정
Kubernetes에서 WIF 사용을 따라 클러스터의 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는 서비스 계정의 워크스페이스 멤버십을 기준으로 권한을 부여합니다).
규칙의 ID(
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을 편집하여 페더레이션 규칙 ID와 조직 ID로api.wif.*키를 설정하고, 각 업스트림 MCP 서버에 대한routes항목을 추가하세요: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을 표준 사설 대역 밖에 할당합니다. 라우트가 클러스터 내부 Service를 대상으로 하는 경우, 업스트림 IP 검증에 설명된 대로 여기에gateway.config.upstream.allowed_ips를 추가하세요.렌더링된 매니페스트 검토
차트를 렌더링하고 조직의 검증 관행에 따라 출력을 검토하세요:
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설정 컴포넌트는 Helm pre-install 훅 Job으로 실행되므로
helm install은 완료될 때까지 대기합니다. 성공하면 Helm이 Job을 자동으로 삭제합니다.helm install이 훅 오류로 실패하면 설정 컴포넌트 인증 실패를 참조하세요.tunnel.id가 비어 있으면 설정 컴포넌트는 페더레이션 규칙이 대상으로 하는 워크스페이스(api.wif.workspaceId를 설정하지 않은 경우 조직의 기본 워크스페이스)에 터널을 생성하고, 그 ID와 도메인을mcp-tunnelSecret에 저장합니다. 검증에 필요한 도메인은 터널의 상세 페이지에서 확인할 수 있으며, 이 페이지는 Console의 MCP 터널 페이지(platform.claude.com/settings/workspaces/default/mcp-tunnels)에서 열 수 있습니다. 사이드바의 워크스페이스 선택기에서 터널이 있는 워크스페이스를 선택하세요. Secret에서 도메인을 읽을 수도 있습니다:kubectl -n mcp-tunnel get secret mcp-tunnel \ -o jsonpath='{.data.tunnel-domain}' | base64 -d설정 컴포넌트를 다시 실행하면(업그레이드 또는 토큰 교체 중) 이 Secret에 저장된 터널 ID를 재사용하며, 두 번째 터널을 생성하지 않습니다.
이 모드(setup.enabled: false)에서는 차트가 API 호출을 하지 않습니다. 설정 컴포넌트가 실행되지 않으며 cert-renew CronJob도 없습니다. 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을 사용하면(OpenSSL 3.0+ 전용인 # -copy_extensions 대신) 다음 버전에서도 계속 동작합니다: # 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.extConsole에
data/ca.crt를 등록하세요.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을 표준 사설 대역 밖에 할당합니다. 라우트가 클러스터 내부 Service를 대상으로 하는 경우, 업스트림 IP 검증에 설명된 대로 여기에
gateway.config.upstream.allowed_ips를 추가하세요.렌더링된 매니페스트 검토
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 측에서 엔드 투 엔드로 검증하세요. Managed Agent 세션 또는 Messages API 요청에서 https://<route>.<your-tunnel-domain>/<path>를 사용합니다. 여기서 <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를 설정하고, 업스트림 MCP 서버를 포함하는 파드 레이블 셀렉터 또는 CIDR 범위로 networkPolicy.egress.mcpServers를 채우세요. 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 토큰을 프로젝션합니다. 다른 ID 공급자(예: SPIFFE, Vault 또는 클라우드 SDK 사이드카)의 토큰을 사용하려면 setup.extraVolumes 및 setup.extraVolumeMounts로 마운트하세요. 그런 다음 api.wif.tokenFile이 마운트 경로를 가리키도록 설정하세요. 차트는 ANTHROPIC_IDENTITY_TOKEN_FILE을 해당 경로로 설정하며, 설정 컴포넌트는 그곳에서 토큰을 읽습니다.
업그레이드
예기치 않게 최신 차트를 가져오지 않도록 helm upgrade에 항상 --version을 전달하세요.
차트 1.x에서 업그레이드
차트 2.0.0은 터널 ID를 api.wif.tunnelId에서 tunnel.id로 이동합니다. 업그레이드하기 전에 values.yaml을 편집하세요. tnl_... 값을 tunnel.id로 옮기고 api.wif.tunnelId를 제거합니다. tunnel.id를 설정하지 않은 채로 두어도 안전하지만(설정 컴포넌트는 재실행 시 mcp-tunnel Secret에 이미 저장된 터널 ID를 재사용합니다), 명시적으로 옮기면 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터널 토큰 교체
프로그래밍 방식 액세스를 사용하는 경우, values.yaml에서 tunnel.tokenVersion을 증가시키고 --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 토큰이 없습니다.
프로그래밍 방식 액세스 없이 사용하는 경우, Console의 터널 상세 페이지에서 Rotate token을 클릭한 다음 mcp-tunnel-token Secret을 업데이트하세요:
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인증서 갱신
차트가 자동화를 제공하지만, 만료를 모니터링하고 갱신이 완료되었는지 확인하는 책임은 여전히 사용자에게 있습니다.
프로그래밍 방식 액세스를 사용하는 경우 인증서 갱신은 자동입니다. 차트는 setup renew-cert를 매일(serverCert.cronSchedule, 기본값 0 0 * * * UTC) 실행하는 CronJob(Helm fullname에 -cert-renew 접미사를 붙인 이름)을 배포합니다. 이 작업은 인증서가 만료 전 serverCert.renewBefore(기본값 30일) 이내에 있지 않으면 아무 작업도 하지 않습니다. 갱신은 로컬에서 이루어집니다. 작업은 Secret에 이미 저장된 CA로 새 인증서에 서명하고, 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?