Exponiendo servicios locales HTTP y TCP a través de AWS EC2 con Inlets
Tags: aws, ec2, networking, network
Published: 2023-09-04 21:14:07

**Autor:** Alex Ellis (Fundador OpenFaaS and Inlets)

En este artículo os mostraremos cómo automatizar los dos tipos de servidores de túnel Inlets utilizando AWS EC2, incluyendo IAM, la gestión de claves SSH y la monitorización.

## Introducción

Normalmente, cuando uso inlets, aprovisiono máquinas virtuales para que actúen como servidores de túnel en DigitalOcean o GCP. La razón principal es el bajo coste y la rápida velocidad de arranque, entorno a 10-20 segundos desde que tecleo un comando en nuestra herramienta <u>inletsctl</u>. Incluso es posible <u>crear servidores de túnel como Pods en solo 2-3 segundos dentro de un clúster de Kubernetes</u>. Sin embargo, para algunos de nosotros, AWS es la elección cuando hablamos de nubes; así que, ya tengas créditos cloud gratuitos, infraestructura existente o lo uses por temas de trabajo, esta es una guía para exponer tus servicios locales a través de un servidor de túnel alojado en **AWS EC2**.

Cubriremos cómo configurar los permisos IAM requeridos, cómo tener una clave SSH para hacer troubleshooting, y luego cómo configurar los dos tipos de túneles y cuándo usarlos. Puedes elegir entre HTTPS para un acceso rápido y sencillo a sitios HTTP, o TCP para casos de uso más complejos como SSH, la API de Kubernetes o dispositivos con TLS auto-firmado.

<IMAGEN_>

> Colaborando en un site mkdocs que se está ejecutando en local utilizando un túnel HTTPS de inlets

## Pre-requisitos

- Una cuenta en AWS.
- Una suscripción a inlets.
- CLI de inletsctl - para automatizar VMs en la nube con el servidor de túnel preinstalado con systemd.

## Crear un usuario IAM

A diferencia de DigitalOcean, donde una simple clave de acceso es todo lo que necesitas, AWS está diseñado para empresas y requiere mucha más configuración antes de que puedas acceder a su API desde una herramienta externa como [inletsctl](https://github.com/inlets/inletsctl). Puedes obtener instrucciones para automatizar túneles en diversas nubes en la [guía de referencia de inletsctl](https://docs.inlets.dev/tutorial/manual-http-server/), o [instalarlo tú mismo manualmente](https://docs.inlets.dev/reference/inletsctl/).

Sigue las instrucciones para crear un usuario y credenciales IAM en la [<u>documentación de inlets</u>](https://docs.inlets.dev/reference/inletsctl/#example-usage-with-aws-ec2).

Guarda la clave de acceso y la clave secreta en tus archivos locales, es decir, **~/.inlets-ec2-access-key, ~/.inlets-ec2-secret-key**.

## Crear claves SSH
Disponer de claves SSH no es estrictamente necesario, a no ser que quieras iniciar sesión en la máquina virtual para customizarla o hacer troubleshooting. Sin embargo, es útil, y puedes crear un par de claves SSH y asignárselo a todas las máquinas virtuales de túnel que crees en EC2.

Dirígete a la Consola de AWS, luego a EC2, y bajo la sección de Red y Seguridad, haz clic en **Pares de clave**.

Crea un nuevo par de claves de tipo RSA y dale el nombre **inlets**.

Descarga las claves y guárdalo en tu directorio personal, es decir, **~/.inlets/ec2.pem**.

Cambia los permisos en el archivo de clave: **chmod 400 ~/.inlets/ec2.pem.**

Podrás utilizar esta clave para cualquier máquina virtual de servidor de túnel inlets que crees en un futuro en EC2.

## Crear un servidor de túnel
Hay dos tipos de servidores de túnel que puedes crear, y cada uno tiene casos de uso bastante diferentes.

Para exponer algún servicio HTTP existente a través de HTTPS, crearás un servidor de túnel HTTPS utilizando la opción **--letsencrypt-domain**.

Para exponer tráfico TCP como algo que ya está servido con TLS, como un proxy inverso, SSH o la API de Kubernetes, utiliza la opción **--tcp**.

### Crear un servidor de túnel HTTPS

Para un servidor de túnel HTTPS, trabaja de forma inversa, empezando desde el dominio personalizado que quieres usar. Por ejemplo, si quieres exponer **https://blog.ejemplo.com**, tendrás que crear un servidor de túnel con el dominio **blog.ejemplo.com** y un registro CNAME o un registro A en tu herramienta DNS apuntando al servidor de túnel. En AWS, probablemente querrías usar Route 53 para el mapeo, aunque Cloudflare funcionaría igual de bien.

El servidor de túnel HTTPS puede soportar más de un dominio, por lo que podrías exponer, por ejemplo, openfaas, grafana y un blog a través del mismo servidor de túnel utilizando la opción **--letsencrypt-domain** varias veces.

```
inletsctl create \
  -provider ec2 \
  --secret-key-file ~/.inlets/ec2-secret-key \
  --access-token-file ~/.inlets/ec2-access-key \
  --region eu-west-1 \
  --aws-key-name inlets \
  --letsencrypt-domain blog.example.com \
  --letsencrypt-email webmaster@example.com
```
La región que especifiques aquí debe coincidir con la región donde creaste tus claves SSH, de lo contrario no se encontrará. La opción **--aws-key-name** es opcional, pero recomendada.

Proporciona la ruta a la clave de acceso y la clave secreta, junto con la región que deseas utilizar y cualquier dominio a través de **--letsencrypt-domain**.

Ejemplo de salida:

```
Using provider: ec2
Requesting host: elated-carson0 in eu-west-1, from ec2
Host: i-05cfa985a99435386, status: creating
[1/500] Host: i-05cfa985a99435386, status: creating
[2/500] Host: i-05cfa985a99435386, status: initialising
...
[77/500] Host: i-05cfa985a99435386, status: initialising
[78/500] Host: i-05cfa985a99435386, status: initialising
[79/500] Host: i-05cfa985a99435386, status: active
inlets HTTPS (0.9.21) server summary:
  IP: 52.213.238.52
  HTTPS Domains: [blog.example.com]
  Auth-token: CVxYhvIuD9tUor9y3fiNrqh6tdXd33yDE0vRtHUR02XrWVgRMnyK8KjqqzdjmRTY

Command:

inlets-pro http client --url "wss://52.213.238.52:8123" \
  --token "CVxYhvIuD9tUor9y3fiNrqh6tdXd33yDE0vRtHUR02XrWVgRMnyK8KjqqzdjmRTY" \
  --upstream http://127.0.0.1:8080

To delete:
  inletsctl delete --provider ec2 --id "i-05cfa985a99435386"

```
En AWS tardaremos unos 2-3 minutos en crear e inicializar una máquina virtual; Una vez que esté lista, estará en espera para cualquier momento en que desees utilizarla.

La salida del comando **inletsctl create** te muestra la dirección IP del servidor de túnel y el token de autenticación que necesitarás para conectarte a él.

Crea todos los registros DNS A o CNAME que necesites y luego puedes iniciar el cliente de túnel.

Si hay múltiples dominios que el servidor de túnel está sirviendo, entonces tendrás que pasar la opción **--upstream** varias veces, una vez por cada dominio.

Aquí está lo que añado cuando quiero exponer Jekyll y mkdocs al mismo tiempo, que se ejecutan en los puertos 4000 y 8000 respectivamente:

```
--upstream blog.example.com=http://127.0.0.1:4000 \
--upstream docs.example.com=http://127.0.0.1:8000
```

### Crear un servidor de túnel TCP

Los servidores de túnel TCP son más adecuados para exponer servicios que ya terminan TLS por sí mismos, como nginx, Caddy, Traefik, dispositivos TLS con certificado self-signed (piensa en: GitHub Enterprise Server), SSH, bases de datos, la API de Kubernetes, etc.

Así es cómo puedes crear un servidor de túnel TCP para exponer SSH desde una Raspberry Pi en tu red doméstica:

Inicia sesión en la Raspberry Pi y añade un puerto adicional al demonio SSH en **/etc/ssh/sshd_config**:

Añade la siguiente línea:

```
Port 2222
```

Reinicia el agente SSH:

```
sudo systemctl daemon-reload && sudo systemctl restart sshd
```
Ahora crea un servidor de túnel con la opción **--tcp** y omite la opción de Let's Encrypt:

```
inletsctl create \
  -provider ec2 \
  --secret-key-file ~/.inlets/ec2-secret-key \
  --access-token-file ~/.inlets/ec2-access-key \
  --region eu-west-1 \
  --aws-key-name inlets \
  --tcp
```

Ejemplo de salida:

```
Using provider: ec2
Requesting host: suspicious-mirzakhani8 in eu-west-1, from ec2
Host: i-0ad0bcd7ebca51ed7, status: creating
[1/500] Host: i-0ad0bcd7ebca51ed7, status: creating
[2/500] Host: i-0ad0bcd7ebca51ed7, status: initialising
...
[88/500] Host: i-0ad0bcd7ebca51ed7, status: initialising
[89/500] Host: i-0ad0bcd7ebca51ed7, status: initialising
[90/500] Host: i-0ad0bcd7ebca51ed7, status: active
inlets TCP (0.9.21) server summary:
  IP: 54.170.244.23
  Auth-token: 8ySdPL01XZtWTPwfvGwYHPmjAhYSNLwPd6cfbzRQ0Zi0v8ifOxx0X8rWLgvqlj7A

Command:

inlets-pro tcp client --url "wss://54.170.244.23:8123" \
  --token "8ySdPL01XZtWTPwfvGwYHPmjAhYSNLwPd6cfbzRQ0Zi0v8ifOxx0X8rWLgvqlj7A" \
  --upstream 127.0.0.1 \
  --ports 2222

To delete:
  inletsctl delete --provider ec2 --id "i-0ad0bcd7ebca51ed7"
```
Ejecuta el comando **inlets-pro tcp client** y cambia la opción **--upstream** para que apunte a la dirección IP de tu Raspberry Pi, y la opción **--ports** al puerto que añadiste al demonio SSH.

Para tu cliente, añade el puerto específico y utiliza la dirección IP del servidor de túnel:

```
ssh -p 2222 pi@54.170.244.23
```

### Gestión y eliminación de servidores de túnel

#### Verificación del estado y qué clientes hay conectados

Puedes obtener información detallada sobre los servidores de túnel a través del comando de estado:

```
inlets-pro status --url "wss://52.213.238.52:8123" \
    --token "CVxYhvIuD9tUor9y3fiNrqh6tdXd33yDE0vRtHUR02XrWVgRMnyK8KjqqzdjmRTY"
```
Lo que te dará:

```
inlets server status. Version: 0.9.21 - b0c7ed2beeb6f244ecac149e3b72eaeb3fb00d23

Server info:
Hostname:       ip-172-31-23-1
Process uptime: 1 minute ago
Mode:           http
Version:        0.9.21 b0c7ed2beeb6f244ecac149e3b72eaeb3fb00d23

Connected clients:
Client ID                        Remote Address       Connected Upstreams
efcbfcb3546b4acb956e4f72630afbea 212.229.86.191:52638 7 seconds *=http://192.168.1.15:8080
```

#### Métricas de Prometheus

Las métricas de Prometheus también están disponibles en los servidores de túnel. Puedes configurar Prometheus para que recopile información del endpoint, utilizando autenticación:

```
curl -k -SLs https://52.213.238.52:8123/metrics \
    -H "Authorization: Bearer CVxYhvIuD9tUor9y3fiNrqh6tdXd33yDE0vRtHUR02XrWVgRMnyK8KjqqzdjmRTY"
```
Aquí hay algunos valores de un servidor de túnel que configuré para exponer el sitio mkdocs de OpenFaaS:

```
# HELP http_controlplane_connected_gauge gauge of inlets clients connected to the control plane
# TYPE http_controlplane_connected_gauge gauge
http_controlplane_connected_gauge 1
# HELP http_controlplane_requests_total total HTTP requests processed by connecting clients on the control plane
# TYPE http_controlplane_requests_total counter
http_controlplane_requests_total{code="200",path="/connect"} 2
http_controlplane_requests_total{code="200",path="/metrics"} 1
http_controlplane_requests_total{code="200",path="/status"} 5
# HELP http_dataplane_requests_total total HTTP requests processed
# TYPE http_dataplane_requests_total counter
http_dataplane_requests_total{code="200",host="docs.o6s.io",method="GET"} 3
http_dataplane_requests_total{code="301",host="docs.o6s.io",method="GET"} 7
http_dataplane_requests_total{code="401",host="docs.o6s.io",method="GET"} 9
http_dataplane_requests_total{code="404",host="docs.o6s.io",method="GET"} 15
http_dataplane_requests_total{code="503",host="docs.o6s.io",method="GET"} 2
```
Encontrarás más información sobre las métricas disponibles y la observabilidad en la [documentación de inlets](https://docs.inlets.dev/tutorial/monitoring-and-metrics/).

#### Conectando con SSH

Hay muy pocas razones para iniciar sesión en un servidor de túnel; sin embargo, es posible que desees revisar los logs o solucionar un problema.

Primero, edita el grupo de seguridad del servidor de túnel y añade el puerto 22 a la lista permitida de TCP. Puedes restringir a tu propia dirección IP si lo deseas, o añadir **0.0.0.0/0** si necesitas conectarte desde múltiples ubicaciones.

Luego usa la clave privada que creaste anteriormente para acceder a ella:

```
ssh -i ~/.inlets/ec2.pem ubuntu@$IP_ADDRESS
```

Verifica el servicio de logs:

```
sudo journalctl -u inlets
```
Edita los ajustes para el token o el dominio de Let's Encrypt en **/etc/default/inlets**.

#### Eliminando servidores de túnel VM

Para eliminar cualquier máquina virtual que hayas creado, usa **inletsctl delete** seguido de **--id** y el ID de la VM que deseas eliminar, o **--ip** y su dirección IP pública. También puedes terminar instancias a través de la consola de AWS navegando a EC2, Instancias, y luego seleccionando la instancia que deseas eliminar.

## Conclusión

Hoy hemos cubierto cómo usar AWS EC2 para crear un servidor de túnel, incluyendo la configuración del usuario IAM, el par de claves y DNS.

Una forma de usar un servidor de túnel es configurarlo y dejarlo para cuando lo necesites. Conéctate a él solo cuando necesites compartir trabajo o colaborar. En nuestro equipo, hacemos esto como parte de nuestro desarrollo para [exponer Keycloak para probar OAuth / OIDC](https://inlets.dev/blog/2023/08/23/keycloak-tls.html), o [OpenFaaS](https://inlets.dev/blog/2020/10/15/openfaas-public-endpoints.html), o una publicación de blog para revisión.

También hemos visto a muchos [Developer Advocates recurrir a túneles para demostraciones a clientes y charlas en conferencias](https://inlets.dev/blog/2023/02/22/tunnels-for-developer-advocates.html). Uno de estos Developer Advocates es Nathan Peck, del equipo de contenedores de AWS, quien escribió cómo inlets era una opción más adecuada que una VPN para dar a los clientes de AWS ECS Anywhere acceso a sus servicios locales: [Ingress to ECS Anywhere, from anywhere, using Inlets](https://nathanpeck.com/ingress-to-ecs-anywhere-from-anywhere-using-inlets/).

Puedes probar inlets con una [prueba gratuita](https://inlets.dev/pricing), donde también recibirás una invitación a un servidor de Discord para poder hacer preguntas y charlar con la comunidad.