Soy Fernando Muñoz, Cloud Engineer en Platzi, certificado en GitHub Actions y AWS Solutions Architect Associate. Hoy quiero que descubras cómo puedes transformar tu flujo de trabajo al utilizar Cloudflare Tunnels, una tecnología que proporciona una forma simple y segura de interconectar redes.
En este blog, te guiaré paso a paso para conectar GitHub Actions a redes privadas de AWS de manera segura y eficiente. Sin embargo, los Tunnels de Cloudflare van mucho más allá y no se limitan a estos dos únicos proveedores, ya que te permiten conectar prácticamente con cualquier proveedor de la nube actual e incluso puedes conectar con tu red local.
¿Qué conocimientos previos necesitas para este blog?
Para aprovechar al máximo el contenido de este blog, es importante contar con conocimientos en las siguientes áreas:
- VPC y subredes en AWS: comprender cómo funcionan las redes virtuales y las subredes en AWS es crucial para configurar conexiones seguras y eficientes.
- Estructura de flujos de GitHub Actions: estar familiarizado con la organización y ejecución de flujos de trabajo en GitHub Actions permitirá integrar y automatizar procesos de manera efectiva.
Si aún no dominas estos temas, te recomiendo explorar los siguientes cursos para fortalecer tus habilidades:
Estos cursos te proporcionarán una base sólida para seguir adelante con confianza y sacar el máximo provecho de las tecnologías que exploraremos en este blog.
Hicimos una versión en video del blog por si prefieres escuchar la explicación o usarlo como podcast.
¿Qué es Cloudflare Tunnel?
Déjame darte una breve introducción:
Es una solución de software que protege tus servidores web de ataques directos al crear un túnel cifrado entre tu servidor de origen y el centro de datos más cercano de Cloudflare, sin necesidad de abrir puertos públicos.
Esto asegura que las direcciones IP de tus servidores permanezcan ocultas, bloqueando ataques DDoS y brechas de datos. A diferencia de métodos tradicionales como las listas de control de acceso (ACLs) o los túneles GRE, Cloudflare Tunnel es más rápido, seguro y fácil de configurar, proporcionando una protección integral y eficiente para aplicaciones en cualquier infraestructura, ya sea en la nube pública, privada o incluso en dispositivos locales.
Tunnel | Zero Trust App Connector | Cloudflare
Hablemos del problema: cómo conectar los Runners de GitHub con una red privada de AWS

Imagina dos mundos separados: por un lado, la red donde operan los GitHub Actions Runners, y por otro, nuestra red privada en AWS. Estos dos mundos no se conocen ni tienen un camino para comunicarse. Nuestra misión es crear un puente, o mejor dicho, un túnel que permita a los Runners de GitHub interactuar con los recursos privados de AWS.
Para ser más claros, en AWS tengo dos instancias de EC2 dentro de subredes privadas, donde, por ejemplo, no tengo IP pública, sino solo IP privada. Y además en AWS, tengo un EKS.


Si yo intentara hacer ping o SSH a esa máquina en este momento, fallaría porque no hay nada que permita conectarlas entre sí. Debería aparecer un mensaje de error del tipo Connection timed out
o similar.

O, por ejemplo, ¿qué pasa si tenemos un EKS desplegado y queremos interactuar con él desde GitHub Actions?
Como vemos, en ambos casos los Actions nos devuelven un error debido a que no pueden alcanzar esa red privada.
Ahora, podrías preguntarte: ‘Fernando, ¿por qué no simplemente usar GitHub Self-Hosted Runners?’ Y… es una opción válida. Sin embargo, como en todo en ingeniería de software, la elección depende de tus necesidades específicas.
Por qué usar Cloudflare Tunnel
Aquí te explico por qué Cloudflare Tunnel puede ser una opción más ventajosa:
- Simplicidad de Configuración: Cloudflare Tunnel es fácil de configurar y mantener, sin la carga de gestionar infraestructura adicional, a diferencia de los Self-Hosted Runners, cuya gestión recae completamente en ti.
- Seguridad Mejorada: Ofrece una capa adicional de seguridad al cifrar el tráfico y mantener los recursos internos protegidos de la exposición a Internet.
- Escalabilidad: No necesitas preocuparte por escalar la infraestructura de los Runners, ya que GitHub se encarga de ello, permitiendo un escalado automático según la demanda.
- Costos Operativos: Se eliminan los costos de mantener y operar servidores adicionales para los Self-Hosted Runners.
Nuestro objetivo es claro:
- Informar a GitHub de que existe un camino seguro hacia ciertos recursos.
- Utilizar Cloudflare Tunnel como ese camino privado.
- Hacer visible nuestra red de AWS en este mapa de conexiones.

Para lograrlo, introduciremos dos conceptos clave:
- Cloudflare WARP: un cliente que protege dispositivos enviando tráfico de manera segura a la red global de Cloudflare, permitiendo el acceso a orígenes privados detrás de los Tunnels para tráfico de Capa 4 sin comandos adicionales.
- cloudflared: un cliente de línea de comandos para Cloudflare Tunnel que enruta el tráfico desde la red de Cloudflare hacia tus servidores de origen, manteniendo tu infraestructura segura y cerrada.
Entonces, procederemos a:
- Configurar nuestro Cloudflare Tunnel.
- Instalar cloudflared en AWS para abrir un camino desde nuestra red privada hacia el Tunnel.
- Configurar WARP en GitHub Actions para acceder al Tunnel y descubrir las redes privadas disponibles.
¡Manos a la obra! Primero haremos todas las configuraciones necesarias en nuestra cuenta de Cloudflare.
Cómo configurar Cloudflare Tunnel
Ahora, vamos a crear el Tunnel y dejarlo listo para recibir conexiones.
-
Dentro de la sección de Zero Trust de tu cuenta de Cloudflare, nos dirigiremos a la parte de
Networks/Tunnels
y haremos clic enAdd Tunnel
.
-
En
Tunnel type
, seleccionaremoscloudflared
, le pondremos el nombre de nuestra preferencia al túnel y haremos clic en el botón “Save tunnel”.

- Una vez guardado el túnel, aparecerán unas instrucciones para instalar y ejecutar el conector. No te preocupes por esto, ya que aparecerán siempre que intentes modificar el túnel. Básicamente, son los comandos para instalar y el token para ejecutar Cloudflare apuntando a nuestro túnel. Hacemos clic en el botón “Next”.

- En esta última parte de la configuración del túnel, vamos a indicar a qué red privada deseamos crear la conexión. Entonces, hacemos clic en la pestaña que se llama Private Networks y colocaremos el CIDR de nuestra VPC de AWS. Hacemos clic en “Save tunnel”.

- En este punto ya tenemos nuestro túnel creado, pero en estado “Inactive” porque todavía no hay ningún cloudflared conectándose a él. Tu túnel debería verse así.

Configuración del Access Group y Service Token en Cloudflare
En esta sección configuraremos ¿Quién?
y ¿Cómo?
pueden conectarse a nuestra cuenta de Cloudflare.
- Siempre dentro de la sección de
Zero Trust
de nuestra cuenta de Cloudflare, nos dirigimos al apartado deAccess/Service Auth
y hacemos clic enCreate Service Token
."

- Escogemos un nombre para nuestro Service Token y una duración (fecha en la que expirará y será necesario renovarlo). Hacemos clic en Generate Token.

- Se nos mostrarán los detalles del Token, que consisten en un
Header and client ID
y unHeader and client secret
. Estos datos son muy sensibles, por lo cual debes resguardarlos en lugares muy seguros. Hacemos clic en el botón Save. Se nos mostrará el resumen de todos los tokens de nuestra cuenta.


- Ahora nos moveremos a la sección Access/Access Group y haremos clic en el botón Add a group.

- Escogeremos un nombre para nuestro nuevo grupo y en la parte de
Define group criteria
seleccionaremos en el Selector el valor de Service Token y en su Value buscaremos el nombre delService Token
que acabamos de crear. Haremos clic en el botón Save.

- Se nos mostrará el resumen de los Access Groups que tengamos en nuestra cuenta, donde veremos un campo llamado Group ID. Copiaremos este ID y lo tendremos a mano.

Configuración del enrolamiento al cliente WARP de Cloudflare
En esta sección nos centraremos en cómo alguien o algo puede unirse a nuestra cuenta de Cloudflare mediante el cliente WARP.
- Siempre dentro de Zero Trust de Cloudflare, nos moveremos a la sección de
Settings
y buscaremos la opción deWARP Client
. Luego, haremos clic en el botónManage
en la sección deDevice enrollment
.


- Ahora, dentro de Rules, crearemos una nueva regla haciendo clic en Add a rule.

- Aquí le pondremos un nombre a esta nueva regla y en Rule Action seleccionaremos Service Auth. En Selector escogeremos Service Token y en el Value el token que generamos previamente. Finalmente, asignaremos esta nueva política al Access Group que creamos anteriormente. Haremos clic en el botón Save.

- Se nos mostrará el resumen de las políticas del cliente WARP de nuestra cuenta.

Configuración del comportamiento del cliente WARP de Cloudflare
En esta sección nos centraremos en la creación de un perfil para el cliente WARP y en asegurarnos de que todos los usuarios que cumplan los criterios utilicen el túnel y realicen el split del tráfico indicado.
- Siempre dentro de la sección
Zero Trust
de Cloudflare, nos dirigiremos aSettings
y buscaremos la opciónWARP Client
.

- Buscaremos la sección que se llama Device settings y haremos clic en el botón Create profile.

- Aquí configuraremos el nombre de este nuevo perfil y determinaremos qué usuarios entrarán dentro de este perfil. En la sección Build an expression, seleccionaremos User group IDs en Selector, in en Operator y colocaremos el Group ID que obtuvimos en pasos previos en Value. Podemos dejar todos los demás campos como están (o modificarlos según tus necesidades) y al final de la página, haremos clic en el botón Create profile.

- Ahora que nuestro perfil ha sido creado, podemos configurar qué tráfico queremos enviar a nuestro túnel y cuál no. Esto es para evitar que en las computadoras otros servicios y aplicaciones se vean afectados por nuestro cliente WARP y se comporten erróneamente. Para ello, hacemos clic en el botón Configure dentro de nuestro perfil.

- Se nos mostrarán todas las opciones configurables dentro del perfil, buscaremos la sección
Split Tunnels
, por defecto esta enExclude IPs and domains
, daremos click enManage
.
Por cierto es más fácil usar el modo Include IPs and domaians
, pero te dejo de tarea investigar como se utiliza esta opción.

- Dado el modo
Exclude
, aparecerá una lista previa de direcciones que el cliente WARP evitará para no generar conflictos con otras aplicaciones y, de esta manera, garantizar que solamente el tráfico legítimo que queremos que viaje por el cliente WARP y, por ende, por nuestro túnel de Cloudflare, lo haga.
Es importante leer esta documentación de Cloudflare para entender cómo funciona: Change Split Tunnels mode by Cloudflare
En mi caso, mi VPC tiene el CIDR como 10.0.0.0/16 y mis subredes se ven así:
3 subnets privadas:
- private-1: 10.0.48.0/20
- private-2: 10.0.64.0/20
- private-3: 10.0.80.0/20
3 subnets públicas:
- public-1: 10.0.0.0/20
- public-2: 10.0.16.0/20
- public-3: 10.0.32.0/20
Dato geek: el bloque 10.0.0.0 (prefijo 10/8) es un bloque de direcciones IP privadas definido por la RFC 1918, que abarca desde 10.0.0.0 hasta 10.255.255.255. Es uno de los rangos de IPs comúnmente utilizado en redes privadas. https://www.rfc-es.org/rfc/rfc1918-es.txt
Entonces, dado que nuestra VPC utiliza el rango 10.0.0.0/16, vamos a eliminar el rango 10.0.0.0/8 que ya estaba agregado previamente en nuestro Split Tunnel
.

Ahora, excluiremos los rangos que no estamos utilizando explícitamente en nuestras subredes. Esto es para evitar que ese tráfico viaje por nuestro WARP y así no afecte a servicios o aplicaciones que no deberían pasar por aquí.
En mi caso serían:
10.0.96.0/19
10.0.128.0/17
¿Cómo calculamos esto?
a. Identificar el rango total de la VPC; en mi caso, 10.0.0.0/16, con IPs disponibles desde 10.0.0.0 hasta 10.0.255.255.
b. Ordenar las subredes por su dirección de inicio.
10.0.0.0/20 (10.0.0.0 - 10.0.15.255)
10.0.16.0/20 (10.0.16.0 - 10.0.31.255)
10.0.32.0/20 (10.0.32.0 - 10.0.47.255)
10.0.48.0/20 (10.0.48.0 - 10.0.63.255)
10.0.64.0/20 (10.0.64.0 - 10.0.79.255)
10.0.80.0/20 (10.0.80.0 - 10.0.95.255)
c. Identificar si tenemos huecos, que en este caso no tenemos. Pero un hueco sería, por ejemplo, tener una subred 10.0.0.0/20
que cubre de 10.0.0.0 a 10.0.15.255 y que nuestra siguiente subred sea 10.0.32.0/20
, que cubre de 10.0.32.0 a 10.0.47.255, entonces no tenemos ninguna subred que cubra de 10.0.16.0 a 10.0.31.255.
d. Todos esos huecos son los rangos que no utilizamos; los transformamos a notación CIDR y obtendríamos 10.0.16.0/20
.
e. En mi caso, no estoy usando el rango de 10.0.96.0 a 10.0.255.255, de ahí es donde aparecen los CIDR 10.0.96.0/19
y 10.0.128.0/17
.
- Una vez agregados esos CIDR que queremos excluir de nuestro túnel, y que deseamos que nuestro cliente WARP no considere, casi hemos terminado.

¡De momento, felicidades! Hemos terminado de configurar todo lo necesario dentro de nuestra cuenta de Cloudflare. Ahora solo nos falta configurar el cloudflared
en una instancia dentro de nuestra cuenta de AWS y configurar el warp-cli
en GitHub Actions.
Configuración de cloudflared
en nuestra VPC de AWS
- Desde una instancia pública, nos conectamos a la instancia privada donde queremos instalar nuestro daemon
cloudflared
.

- Ahora seguiremos una serie de comandos para instalar
cloudflared
en esta instancia privada. En mi caso, para las EC2 con Amazon Linux, los comandos son los siguientes:
Puedes ver los comandos para otros OS aquí: Download and install cloudflared
curl -fsSL https://pkg.cloudflare.com/cloudflared-ascii.repo | sudo tee /etc/yum.repos.d/cloudflared.repo
sudo yum update
sudo yum install cloudflared

- Una vez instalado cloudflared, podemos verificar su instalación con el comando cloudflared version.

- Ahora solo faltaría hacer join de este daemon a nuestro túnel de CF. Para ello, dentro de nuestra cuenta de Cloudflare en la sección de Zero Trust, vamos a editar el túnel que creamos y copiamos el código que aparece en el apartado
If you already have cloudflared installed on your machine
.

- Ejecutamos ese código en nuestra EC2 donde hemos instalado cloudflared.

- Y listo, ya nuestro túnel debe aparecer con un estado Healthy. Esto indica que hemos completado uno de los caminos de nuestro túnel. Ese daemon sirve como conector para nuestro túnel e indica a qué dirección llevarnos para descubrir esos recursos privados.

Configuración del warp-cli en GitHub Actions
Bien, ahora por fin vamos a ver el resultado de todo nuestro trabajo. Como último paso en las ejecuciones de GitHub Actions, tenemos que configurar el warp-cli
para que nuestro Runner pueda interactuar con los recursos privados de AWS. Primero desglosaré por partes el action para explicar algunas cosas.
- Instalación de warp-cli
- name: Install CF WARP
run: |
curl https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list
sudo apt-getupdate && sudo apt-getinstall cloudflare-warp
-
Generamos un archivo
mdm.xml
dentro del directorio/var/lib/cloudflare-warp
, con el contenido que nos generó el Service Token que creamos al inicio. Donde:organization
corresponde al nombre de nuestra organización en Zero Trust.auth_client_id
es el CF-Access-Client-Id que nos generó el Service Token.auth_client_secret
es el CF-Access-Client-Secret que nos generó el Service Token.
Guardé esos valores dentro de GitHub como secretos.
- name: Generate mdm.xml file in /var/lib/cloudflare-warp
run: |
sudo mkdir -p /var/lib/cloudflare-warp
echo '
organization
${{ secrets.ORGANIZATION }}
auth_client_id
${{ secrets.AUTH_CLIENT_ID }}
auth_client_secret
${{ secrets.AUTH_CLIENT_SECRET }}
' | sudo tee /var/lib/cloudflare-warp/mdm.xml
sudo chmod 777 /var/lib/cloudflare-warp/mdm.xml
- Reiniciamos el servicio de warp y hacemos una pausa de 5 segundos para garantizar que el servicio esté habilitado antes de continuar con los siguientes pasos del action.
- name: Restart cloudflare-warp service
run: sudo systemctl restart warp-svc.service && sleep 5
- Procedemos a indicarle al warp que se conecte e inicie sesión. Esto debería devolvernos un éxito.
- name: warp-cli connect
run: warp-cli --accept-tos connect && sleep20
- Ya en este punto deberíamos poder ver dentro de la lista de dispositivos en Cloudflare Zero Trust, nuestro runner. Esto indica que nuestro **warp-cli **se conectó correctamente a nuestra cuenta y, por ende, puede utilizar nuestro túnel.


- Genial, ahora solo nos falta indicarle a la tabla de rutas de la máquina del Runner de Action que todo el tráfico que intente dirigirse a nuestra CIDR de la VPC de AWS, debe salir por el WARP. Para lograr esto, ejecutamos el siguiente comando.
- name: Set route ip
run: sudo ip route add CIDR_DE_TU_VPC dev CloudflareWARP
- Y listo, ya en este punto nuestro GitHub Actions debería poder interactuar con los recursos privados de nuestra cuenta de AWS. Veamos cómo se comportan ahora los dos casos que planteamos al inicio de este blog.
Conexión SSH a una EC2

Conexión al EKS

- Como último paso, es muy recomendable ejecutar los siguientes comandos para desconectar el WARP y limpiar todos los recursos que hemos creado con claves privadas.
- name: warp-cli disconnect
if: always()
run: warp-cli --accept-tos disconnect
- name: Delete cloudflare-warp folder
if: always()
run: |
sudo rm -rf /var/lib/cloudflare-warp
¿Qué aprendiste después de leer este blog?
Hemos terminado y me gustaría darte los puntos concretos de lo que hemos logrado:
- De Cloudflare, aprendiste a utilizar Zero Trust creando un Service Token y un Access Group.
- Creaste tu primer Cloudflare Tunnel y aprendiste cómo configurar el enrolamiento de Cloudflare WARP.
- Configuraste
cloudflared
en una instancia privada para darle acceso al túnel a una red privada. - Viste el flujo de un GitHub Actions para instalar y autenticar el WARP CLI de Cloudflare.
Sigue al pendiente del blog de Platzi; próximamente habrá un nuevo artículo como este de Engineering by Platzi. Pero mientras tanto, también puedes leer este otro blog: Cloudflare Pages: Cómo construimos una librería para hacer despliegues
Comparte el artículo si te pareció útil y crees que a alguien más le podría servir; y por supuesto, nos encantaría leerte en los comentarios.
Curso de Introducción a AWS: Redes, Gobernanza y Machine Learning