Túneles nativos de Kubernetes: Ingress declarativo con operadores y CRDs

Quick answer
Túneles nativos de Kubernetes: Webhook Relay y operadores CRD: webhook testing answer
For local webhook testing, run your app locally, expose it with a public HTTPS tunnel, and paste the stable callback URL into the provider dashboard.
How do I test webhooks on localhost?
Start your local server, open a public HTTPS tunnel to that port, configure the provider webhook URL, and inspect events in your local logs.
Why does a stable webhook URL matter?
Stable URLs prevent provider dashboards from needing manual callback updates every time you restart a tunnel.
Las equipos cloud-native describen infraestructura en YAML y dejan que los controladores la hagan realidad. Sin embargo, la forma en que la mayoría de los desarrolladores conectan un clúster privado a internet sigue siendo imperativa: abrir una terminal, ejecutar un binario de túnel, dejarlo en ejecución.
Un conjunto creciente de herramientas cierra esa brecha. Un controlador dentro de tu clúster observa objetos de Kubernetes (un recurso personalizado, un Ingress, una ruta de Gateway API, o un Service anotado), se conecta a la red de borde del proveedor, y mantiene el túnel en reconciliación con lo que dicen tus manifiestos. Si eliminas el objeto, el túnel desaparece.
Esta guía cubre lo que realmente existe hoy, con manifiestos funcionales, advertencias honestas, y los detalles de GitOps que suelen causar problemas. También cubre un proyecto que solía estar en todas las listas de “operadores de túneles de Kubernetes” y que ya no existe.
Por qué los túneles imperativos no encajan en Kubernetes
Herramientas como la CLI de ngrok, localtunnel, o un proxy SSH reverso hecho a mano, sirven para sesiones de depuración de diez minutos. En un clúster tienen tres problemas:
- Sin ciclo de vida. Si un nodo se drena o un pod es evicted, un túnel en proceso separado o en un sidecar no gestionado muere con él. Nada en Kubernetes sabe que el túnel existe, por lo que nada lo recrea.
- Sin fuente de verdad. El túnel vive en el historial de shell de alguien, no en Git. El clúster y el repositorio se desincronizan.
- Sin visibilidad. No puedes
kubectl getpara verificar la salud de un túnel.
Exponer cada servicio de la forma tradicional (un LoadBalancer en la nube, IPs estáticas, reglas de firewall) es costoso y a menudo imposible en laboratorios caseros, clústeres on-premises, sitios en el borde, y laptops tras NAT. Esa es la brecha que llenan los túneles gestionados por operadores.
Cómo funcionan los túneles gestionados por operadores
El patrón compartido es simple:
- Un agente o operador corre dentro de tu clúster.
- Abre una conexión saliente hacia la red de borde del proveedor, sin necesidad de reglas de firewall entrantes ni IP pública.
- Un controlador observa objetos de Kubernetes y configura al proveedor a través de su API.
- Si la conexión se cae o el objeto cambia, el controlador reconcilia. Si el objeto se elimina, limpia.
Bajo ese patrón, las herramientas difieren en qué escribes:
| Herramienta | Qué escribes | Mejor para | Advertencia |
|---|---|---|---|
| Webhook Relay Operator | recurso personalizado WebhookRelayForward |
Webhooks y callbacks API en un clúster privado | Solo webhooks; última versión etiquetada 0.6.0 (nov 2022) |
| Webhook Relay Ingress Controller | recursos estilo Ingress (producto separado) | Túneles bidireccionales a servicios como Grafana o Prometheus | Producto diferente del Operator |
| ngrok Kubernetes Operator | CRDs AgentEndpoint / CloudEndpoint, Ingress, o Gateway API |
Ingreso público completo con política de borde (restricciones IP, límites de tasa) | Requiere cuenta ngrok y dominio reservado |
| Tailscale Kubernetes Operator | Ingress estándar con ingressClassName: tailscale, o Service anotado |
Acceso privado a tailnet, con exposición pública opcional vía Funnel | Funnel tiene puertos y límites de ancho de banda fijos |
| Cloudflare Tunnel | despliegue cloudflared (oficial); operadores comunitarios existen |
Ingreso HTTP(S) público en la red de Cloudflare | La vía oficial es un despliegue simple, no un CRD |
| Pangolin (Newt) | Helm chart | Ingreso tunelado auto-hospedado | Newt es un agente desplegado con Helm, no un operador CRD |
| KubeSail | n/a | n/a | Descontinuado |
Webhook Relay: el operador en forma de webhook
El Webhook Relay Operator está diseñado para una tarea: recibir webhooks y solicitudes API (de GitHub, Stripe, Slack) en un clúster sin IP pública ni balanceador de carga. Su README menciona despliegues on-premises, en el borde, y K3s como entornos objetivo. Se instala con Helm y se describen endpoints públicos y destinos de reenvío en un recurso WebhookRelayForward.
Instálalo, pasando la clave y secreto del token de acceso desde tu cuenta de Webhook Relay:
helm repo add webhookrelay https://charts.webhookrelay.com
helm repo update
helm upgrade --install webhookrelay-operator --namespace=default webhookrelay/webhookrelay-operator \
--set credentials.key=$RELAY_KEY --set credentials.secret=$RELAY_SECRET
Luego declara el reenvío. Una entrada inputs crea el endpoint público, y una outputs indica a dónde van las solicitudes. Sin una salida, tienes un endpoint que no reenvía a ningún lado.
apiVersion: forward.webhookrelay.com/v1
kind: WebhookRelayForward
metadata:
name: stripe-webhook-forwarder
namespace: payment-services
spec:
buckets:
- name: k8s-operator
inputs:
- name: public-endpoint
description: "Receptor de webhooks de Stripe"
responseBody: "OK"
responseStatusCode: 200
outputs:
- name: stripe-receiver
lockPath: true
destination: http://stripe-receiver.payment-services:8080/webhooks/stripe
Si varios equipos usan el operador, puedes omitir las credenciales a nivel Helm y referenciar un Secret en cada recurso, usando secretRefName (y opcionalmente secretRefNamespace) en spec. El Secret contiene los valores key y secret para el token de acceso.
El operador asegura que el bucket, inputs y outputs existan, emite eventos de Kubernetes para las acciones, y escribe el estado en el recurso. Lee la URL pública para entregarla al remitente del webhook:
kubectl get webhookrelayforwards.forward.webhookrelay.com stripe-webhook-forwarder \
-n payment-services -o 'jsonpath={.status.publicEndpoints[0]}'
Dos notas prácticas:
- Es el producto de webhook, no el general. La documentación de Webhook Relay describe un controlador de ingreso separado como la forma recomendada de abrir túneles bidireccionales a servicios como Grafana o Prometheus. No esperes que el Operator exponga servicios arbitrarios.
- Es estable pero silencioso. La última versión etiquetada es 0.6.0 de noviembre de 2022. La documentación del proveedor aún lo recomienda para reenviar webhooks a un clúster, pero fija la versión del chart y revisa el repositorio antes de usarlo en algo crítico.
Cualquiera que sea el transporte, verifica la firma del remitente (para Stripe, el encabezado de firma) dentro de tu aplicación. El túnel recibe la solicitud, pero no prueba quién la envió.
ngrok Kubernetes Operator: CRDs, Ingress, y Gateway API
El operador de ngrok es la opción más flexible de esta lista. Ofrece dos recursos personalizados nativos, AgentEndpoint y CloudEndpoint. También traduce recursos estándar Ingress y Gateway API en esos mismos tipos. ngrok afirma que el operador está disponible para todos sin costo adicional; solo pagas por los recursos que provisiona.
helm repo add ngrok https://charts.ngrok.com
helm repo update
helm install ngrok-operator ngrok/ngrok-operator \
--namespace ngrok-operator \
--create-namespace \
--set credentials.apiKey=$NGROK_API_KEY \
--set credentials.authtoken=$NGROK_AUTHTOKEN
Necesitarás una cuenta ngrok y un dominio reservado. La exposición más sencilla es un AgentEndpoint único:
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
name: auth-service-endpoint
namespace: dev
spec:
url: https://TU-DOMINIO-RESERVADO
upstream:
url: http://auth-service.dev:8080
Como la política del endpoint forma parte del recurso, la seguridad también puede gestionarse en Git. Esto añade una lista blanca de IPs:
spec:
url: https://TU-DOMINIO-RESERVADO
upstream:
url: http://auth-service.dev:8080
trafficPolicy:
inline:
on_http_request:
- actions:
- type: restrict-ips
config:
enforce: true
allow:
- 203.0.113.10
Para varios servicios tras un mismo hostname, ngrok combina un CloudEndpoint público con AgentEndpoints internos y rutas entre ellos usando la acción forward-internal en trafficPolicy. Si usas Gateway API, cada hostname de Gateway se vuelve un CloudEndpoint, y cada servicio upstream referenciado por un HTTPRoute se vuelve un AgentEndpoint interno. Los filtros de espejo de solicitud aún no son soportados.
Tailscale Kubernetes Operator: Ingress estándar, privado por defecto
El operador de Tailscale adopta un enfoque diferente: no necesita un CRD específico para túneles para exposición básica. Usa un Ingress estándar con ingressClassName: tailscale, y crea pods proxy que reenvían tráfico a tu Service. La instalación por defecto también crea una clase tailscale y CRDs incluyendo ProxyClass, Connector, ProxyGroup, DNSConfig, y Recorder.
Instala con Helm tras crear un cliente OAuth y etiquetas en la consola de administración:
helm repo add tailscale https://pkgs.tailscale.com/helmcharts
helm repo update
helm upgrade --install tailscale-operator tailscale/tailscale-operator \
--namespace=tailscale --create-namespace \
--set-string oauth.clientId="<ID OAuth>" \
--set-string oauth.clientSecret="<Secreto OAuth>" \
--wait
Un Ingress por sí solo expone el servicio solo a tu tailnet. Para acceder a internet público, debes activar la opción con la anotación tailscale.com/funnel:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auth-service-funnel
namespace: dev
annotations:
tailscale.com/funnel: "true"
spec:
ingressClassName: tailscale
defaultBackend:
service:
name: auth-service
port:
number: 8080
tls:
- hosts:
- auth-dev
El valor tls.hosts se vuelve el nombre MagicDNS, por ejemplo auth-dev.<tu-tailnet>.ts.net. Revisa kubectl get ingress y lee la columna ADDRESS.
Funnel tiene restricciones que debes considerar:
- Solo puede usar nombres DNS bajo el dominio
ts.netde tu tailnet. - Solo escucha en puertos 443, 8443, y 10000, y solo sobre TLS.
- El tráfico tiene límites de ancho de banda que no puedes configurar.
- La política de tu tailnet debe permitir Funnel (atributo
funnelen nodo), y MagicDNS y HTTPS deben estar habilitados.
Para producción, Tailscale recomienda modo de alta disponibilidad: un ProxyGroup con múltiples réplicas en lugar de un solo proxy. También planifica los límites de certificados al crear muchos hostnames cortos. El operador provee certificados de Let’s Encrypt, y la documentación lista límites de 50 certificados por semana para hostnames únicos. Se recomienda usar un ProxyClass con entorno de staging de Let’s Encrypt para pruebas.
Una propiedad de seguridad importante: Tailscale documenta que los servidores relé de Funnel reenvían el flujo cifrado sin descifrarlo, y TLS termina en tu propio nodo.
Cloudflare Tunnel y Pangolin
Cloudflare Tunnel. La guía oficial de Cloudflare para Kubernetes ejecuta cloudflared como un Deployment normal autenticado con un token de túnel en un Secret. Recomienda correr cloudflared en su propio Deployment, junto a tus despliegues, para escalar independientemente. Los réplicas comparten carga, y cada réplica puede acceder a todos los servicios del clúster. Cloudflare advierte contra autoscaling de cloudflared, porque eliminar una réplica rompe las conexiones que llevaba. Para recursos personalizados como túneles y registros DNS, proyectos comunitarios como adyanth/cloudflare-operator ofrecen CRDs Tunnel y TunnelBinding, aunque en fase alpha.
Pangolin. Pangolin es un proxy reverso tunelado auto-hospedable. Su agente Kubernetes, Newt, se despliega con Helm (versión 1.4.0 al momento) y requiere Kubernetes 1.30.14 o superior. La documentación de Pangolin lista Helm, Kustomize, y herramientas GitOps (Argo CD y Flux) como métodos soportados, incluyendo ejemplo HelmRelease para Newt. El chart del servidor Pangolin aún es pre-lanzamiento, así que fija versiones exactas. También recomienda mantener las credenciales de Newt en un Secret existente, no en los valores de Helm.
Qué pasó con KubeSail
Versiones antiguas de este tema (incluyendo un borrador anterior) presentaban a KubeSail como ejemplo: un operador casero que observaba recursos Ingress estándar y asignaba subdominios públicos con TLS. KubeSail ha cerrado. Su página ahora muestra un aviso de despedida, y reportes comunitarios indican que sus gateways hospedados cerraron a mediados de septiembre de 2025. Un mensaje de los fundadores, en Lemmy, recomienda Tailscale Funnel y Cloudflare Tunnel para acceso remoto.
Si encuentras una guía que diga que debes instalar el agente de KubeSail, considérala obsoleta. El flujo de trabajo que popularizó (escribir un Ingress normal, obtener una URL pública) continúa en el operador de Tailscale mencionado arriba.
Minikube: tres cosas diferentes llamadas “tunnel”
Probar callbacks OAuth o webhooks de terceros en un clúster local es un caso clásico, y los comandos de Minikube generan confusión:
minikube serviceabre servicios NodePort. La documentación muestra que en algunos casos con el driver Docker funciona creando un proceso SSH que reenvía un puerto local al servicio. El rango por defecto de NodePort es 30000-32767.minikube tunnelcrea una ruta en tu máquina a serviciosLoadBalancery asigna su IP externa. Debe mantenerse en ejecución, y detenerlo (Ctrl+C) elimina el acceso. Solo hace que los servicios sean alcanzables desde tu máquina local, no desde internet.- Add-on de Ingress y ediciones en hosts-file funciona solo si tu máquina resuelve el dominio.
Ninguno de estos crea una URL pública para un colaborador remoto o webhook externo. Para eso, ejecuta uno de los operadores arriba dentro de Minikube. Con ngrok, usa el AgentEndpoint mostrado antes, y ngrok tiene guía para clústeres locales. Con Tailscale, el Ingress de Funnel funciona igual, siempre que el clúster pueda acceder a la red de Tailscale.
Como el túnel está definido por un recurso, su ciclo de vida sigue al recurso. kubectl delete en el AgentEndpoint o Ingress elimina el endpoint público, sin dejar un terminal abierto.
GitOps: túneles junto a tus Deployments
Cuando las definiciones de túneles están en YAML, pueden estar junto a tu Deployment y Service en el mismo repositorio, y Argo CD o Flux los aplican juntos. Si el clúster se reconstruye, volver a aplicar el repositorio recrea los operadores y los recursos personalizados, y los túneles vuelven.
El principal problema es el orden. Un recurso personalizado no puede aplicarse antes de que exista su CRD. En Argo CD, el CRD suele llegar con el chart del operador, y el modo de prueba (dry-run) falla con “el servidor no encontró el recurso solicitado” si el CRD aún no está en el clúster. Dos configuraciones ayudan: poner el operador en una onda de sincronización anterior (o en una aplicación separada), y agregar la opción SkipDryRunOnMissingResource en sync-options:
apiVersion: forward.webhookrelay.com/v1
kind: WebhookRelayForward
metadata:
name: stripe-webhook-forwarder
namespace: payment-services
annotations:
argocd.argoproj.io/sync-wave: "2"
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
La documentación de Argo CD indica que el modo de prueba aún corre si el CRD ya existe, así que esto solo relaja la verificación en la primera instalación.
Mantén las credenciales fuera de Git. Cada operador necesita un token, API key, o secreto OAuth. Guárdalos en Secrets creados fuera de banda, o con una herramienta de gestión de secretos, y refiérecelos en tus manifiestos.
Seguridad: lo que solo outbound puede y no puede hacer
Las conexiones solo salientes son una mejora real. No hay puertos entrantes que abrir en un firewall corporativo, ni LoadBalancer en la nube por servicio. Pero algunas afirmaciones comunes requieren cuidado:
- El hostname público sigue siendo público. La red del clúster está cerrada, pero la URL que publicas es accesible por cualquiera a menos que pongas control de acceso. La política de tráfico de ngrok (como
restrict-ips) es una forma, y una verificación a nivel de aplicación otra. La superficie DDoS se traslada al proveedor y a tu hostname; no desaparece. - Alguien termina TLS. Los proveedores que aplican políticas en el borde deben descifrar HTTP, por lo que ven el texto plano. Es una decisión de confianza consciente. Tailscale Funnel es la excepción, porque TLS termina en tu propio nodo.
- El filtrado en el borde no es sanitización. No asumas que el tráfico que llega por un túnel está autenticado o limpio. Valida entradas y firmas en la aplicación.
- RBAC solo concede permisos; no los niega. Puedes limitar recursos que crean túneles a
devystaging, otorgando permisos solo allí. Para reglas más finas (como qué hostnames puede reclamar un namespace), usaValidatingAdmissionPolicy, que está en GA desde Kubernetes 1.30. - Tokens son credenciales portadoras. Quien tenga un token de túnel puede ejecutar su propio agente en ese túnel. Limítalos y haz rotar.
Cómo elegir un enfoque
- ¿Solo necesitas webhooks en un clúster privado? El operador de Webhook Relay está hecho para eso.
- ¿Quieres ingreso público completo con política en Git? El operador de ngrok, con
AgentEndpoint,Ingress, o Gateway API. - ¿Principalmente quieres acceso privado, con URL pública ocasional? El operador de Tailscale, y trata Funnel como excepción deliberada.
- ¿Ya usas Cloudflare? Ejecuta
cloudflaredcomo Deployment, y solo mira operadores comunitarios si aceptas software en fase alpha. - ¿Quieres auto-hospedar el borde? Pangolin con el Helm chart de Newt.
- ¿Quieres usar KubeSail? No puedes. Ya no existe.
La tendencia es clara: expón servicios declarando recursos, deja que un controlador mantenga la conexión, y mantén todo en control de versiones. Los detalles varían por herramienta, así que revisa la documentación actual antes de comprometerte. Este espacio evoluciona rápido, como mostró el cierre de KubeSail.
Fuentes
- Webhook Relay Operator: https://github.com/webhookrelay/webhookrelay-operator y https://webhookrelay.com/docs/installation/kubernetes/
- ngrok Kubernetes Operator: https://ngrok.com/docs/getting-started/kubernetes/crds y https://ngrok.com/docs/k8s/guides/using-gwapi
- Tailscale Kubernetes Operator: https://tailscale.com/docs/kubernetes-operator/install-operator y https://tailscale.com/docs/kubernetes-operator/ingress
- Tailscale Funnel con Kubernetes: https://tailscale.com/docs/kubernetes-operator/ingress/expose-workload-to-internet
- Tailscale Funnel (límites y comportamiento TLS): https://tailscale.com/docs/features/tailscale-funnel y https://tailscale.com/blog/tailscale-funnel-beta
- Cloudflare Tunnel en Kubernetes: https://developers.cloudflare.com/tunnel/deployment-guides/kubernetes/
- Operador comunitario de Cloudflare: https://github.com/adyanth/cloudflare-operator
- Pangolin Helm y Newt: https://docs.pangolin.net/self-host/manual/kubernetes/helm y https://docs.pangolin.net/self-host/manual/kubernetes/newt/helm
- Despedida de KubeSail: https://kubesail.com/ y hilo comunitario https://lemmy.world/post/38039322
- Minikube: https://minikube.sigs.k8s.io/docs/handbook/accessing/ y https://minikube.sigs.k8s.io/docs/commands/tunnel/
- Opciones de sincronización de Argo CD: https://argo-cd.readthedocs.io/en/release-2.9/user-guide/sync-options/
- ValidatingAdmissionPolicy GA: https://kubernetes.io/blog/2024/04/24/validating-admission-policy-ga/
Registro de cambios (notas editoriales: eliminar antes de publicar)
Correcciones principales
- KubeSail está descontinuado. El borrador describía el operador de KubeSail, subdominios
my-app.kubesail.io, y TLS en el borde en presente como opción funcional. La página de kubesail.com ahora muestra aviso de despedida, y reportes comunitarios indican cierre de gateways en septiembre 2025. La sección se reemplaza con una nota breve de “qué pasó”, y el rol de ingreso víaIngressestándar es cubierto por el operador de Tailscale. - El CRD
LocalTunnel(tunneling.example.com/v1alpha1) era un marcador de posición, no un producto real. El ejemplo de Minikube se reemplaza con manifiestos reales: unAgentEndpointde ngrok y unIngressde Funnel de Tailscale. - El manifiesto de Webhook Relay estaba incompleto. Tenía un
inputs(endpoint público) pero nooutputs, así que no reenviaba a ningún lado. Se añade el bloqueoutputscondestination,lockPath, yresponseStatusCode. El camposecretRefNamees válido: la documentación del proyecto lo indica (consecretRefNamespaceopcional) para credenciales por recurso en entornos multiinquilino. El error del borrador fue presentarlo como único modo; las credenciales a nivel Helm son la opción predeterminada. También se corrige el comando de estado para usar el nombre completo del recurso según la documentación de Webhook Relay. - “minikube tunnel” se confundió con exposición pública.
minikube tunnelenruta servicios LoadBalancer solo a la máquina local;minikube servicecubre NodePort. Ninguno crea una URL pública. Se reescribe en consecuencia.
Reducción de exageraciones
- Se elimina “Inmune a escaneo de puertos, DDoS, y ataques de fuerza bruta”. El hostname que publicas sigue siendo público, y la superficie expuesta se traslada al borde del proveedor.
- Se elimina “El tráfico que llega al servicio ya está descifrado, autenticado y sanitizado”. La terminación TLS en el borde significa que el proveedor ve texto plano (Tailscale Funnel es la excepción documentada), y el filtrado en el borde no reemplaza validación en la aplicación.
- Se corrige “Negar estrictamente la creación de CRDs de túneles en producción”. RBAC en Kubernetes es solo aditivo; otorgas permisos y no los niegas. Se añade
ValidatingAdmissionPolicy(GA en 1.30) para reglas más finas. - Se añade contexto de mantenimiento para el operador de Webhook Relay: última versión 0.6.0, noviembre 2022, mientras la documentación del proveedor aún lo recomienda.
Contenido añadido
- Nuevas secciones sobre el operador de ngrok (
AgentEndpoint,CloudEndpoint,Ingress, Gateway API; gratis para instalar; dominio reservado requerido), el operador de Tailscale (clase de Ingress, anotación Funnel, HA con ProxyGroup, límites de puertos y ancho de banda, límites de certificados), Cloudflare Tunnel en Kubernetes (enfoque oficial, sin autoscaling, en fase alpha), y Helm chart de Newt para Pangolin (versión 1.4.0, Kubernetes 1.30.14+). - Se aclara que el operador de Webhook Relay y su controlador de ingreso son productos separados.
- Se añade problema de orden en CRD para Argo CD (
SkipDryRunOnMissingResource, ondas de sincronización) y gestión de secretos. - Se incluye tabla comparativa y guía de decisión.
Lo que no se verificó / se dejó fuera a propósito
- Precios actuales y límites de uso gratuito de cada proveedor (cambian con frecuencia; enlaza a páginas de precios si los añades).
- Si Tailscale Funnel aún lleva etiqueta beta; el artículo no hace afirmación.
- Funciones nuevas de Webhook Relay más allá del Operator y controlador de ingreso.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.