Development
16 min read
50 views

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

IT
InstaTunnel Team
Published by the InstaTunnel team | Editorial policy
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 get para 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:

  1. Un agente o operador corre dentro de tu clúster.
  2. Abre una conexión saliente hacia la red de borde del proveedor, sin necesidad de reglas de firewall entrantes ni IP pública.
  3. Un controlador observa objetos de Kubernetes y configura al proveedor a través de su API.
  4. 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.net de 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 funnel en 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 service abre 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 tunnel crea una ruta en tu máquina a servicios LoadBalancer y 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 dev y staging, otorgando permisos solo allí. Para reglas más finas (como qué hostnames puede reclamar un namespace), usa ValidatingAdmissionPolicy, 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 cloudflared como 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


Registro de cambios (notas editoriales: eliminar antes de publicar)

Correcciones principales

  1. 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ía Ingress estándar es cubierto por el operador de Tailscale.
  2. 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: un AgentEndpoint de ngrok y un Ingress de Funnel de Tailscale.
  3. El manifiesto de Webhook Relay estaba incompleto. Tenía un inputs (endpoint público) pero no outputs, así que no reenviaba a ningún lado. Se añade el bloque outputs con destination, lockPath, y responseStatusCode. El campo secretRefName es válido: la documentación del proyecto lo indica (con secretRefNamespace opcional) 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.
  4. “minikube tunnel” se confundió con exposición pública. minikube tunnel enruta servicios LoadBalancer solo a la máquina local; minikube service cubre NodePort. Ninguno crea una URL pública. Se reescribe en consecuencia.

Reducción de exageraciones

  1. 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.
  2. 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.
  3. 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.
  4. 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

  1. 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+).
  2. Se aclara que el operador de Webhook Relay y su controlador de ingreso son productos separados.
  3. Se añade problema de orden en CRD para Argo CD (SkipDryRunOnMissingResource, ondas de sincronización) y gestión de secretos.
  4. 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.

Continue from this article into the most relevant product guides and workflows.

Related Topics

#Webhook Relay Kubernetes Operator, KubeSail reverse proxy, expose local Minikube custom resource, Kubernetes tunnel automation, Kubernetes CRD operator tunneling, GitOps reverse proxy automation, Kubernetes custom resource definitions, local Kubernetes webhook tunneling, cloud native tunnel automation, Minikube external ingress operator, Webhook Relay CRD guide, KubeSail tunnel operator, DevOps GitOps tunneling, platform engineering reverse proxy, Kubernetes ingress alternative, expose localhost to internet Kubernetes, Minikube webhook forwarding, k8s operator tunnel management, Declarative Kubernetes tunneling, YAML driven reverse proxy, Kubernetes local environment tunneling, Kubernetes developer tooling, Webhook Relay installation guide, KubeSail deployment tutorial, Minikube external access setup, Kubernetes webhook listener, Kubernetes custom controller development, cloud native developer workflow, GitOps webhook proxy setup, k8s CRD architecture breakdown, Kubernetes local cluster exposure, secure Kubernetes tunneling, Kubernetes API server extensions, Webhook Relay vs KubeSail, Kubernetes developer productivity, microservices local tunneling, local development cluster ingress, Kubernetes operator pattern tutorial, Minikube tunnel operator, automated local endpoint exposure, Kubernetes external traffic routing, k8s operator lifecycle manager, Kubernetes continuous deployment proxy, infrastructure as code tunneling, cloud native proxy automation, Kubernetes cluster webhook relay, local testing Kubernetes operator, Kubernetes YAML tunnel configuration, edge proxy Kubernetes operator, devops Kubernetes tunnel workflows, Kubernetes local host reverse proxy, KubeSail custom resources, Webhook Relay k8s configuration, Kubernetes native edge ingress, cloud native reverse proxy operator

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles