Hace poco trabajando en un proyecto me encontré con una situación curiosa: tenía que acceder una serie de recursos que se encontraban publicados por HTTP tras el puerto 8080. El acceso a estos recursos no era puntual, sino que tenía que realizarse de forma continuada. Dejando de lado la conveniencia de usar SSL en este acceso, me encontraba con un problema bastante más elemental: desde mi oficina no se permiten conexiones salientes al puerto 8080, de hecho tenemos una política de conexiones salientes bastante restrictiva.

La forma más sencilla de saltarnos esta restricción es establecer la conexión mediante alguna tecnología de tunneling, como VPN. La infraestructura de mis redes domésticas se encuentran gobernadas en su mayor medida por el espectacular SoftEther VPN, y para no interferir los puertos del HTTP y HTTPS, acostumbro a utilizar túneles basados en L2TP/IPsec. ¡Pero problema! La red de mi oficina también filtra las conexiones salientes L2TP. Con un cortafuegos tan exquisito no me quedaba más remedio que intentar utilizar el protocolo mas firewall-friendly: el SSTP.

¿Qué es el SSTP?

El SSTP, Secure Socket Tunneling Protocol, es un protocolo VPN desarrollado por Microsoft y que debutó en el lanzamiento de Windows Server 2008 y Windows Vista SP1. Establece un canal de transporte PPP bajo una capa de cifrado TLS a través del puerto TCP 443, estableciendo una sesión HTTPS. Estas características le otorgan la bondad de atravesar con relativa facilidad los cortafuegos y proxies más restrictivos, ya que el puerto 443 saliente debe estar habilitado para las muy necesarias conexiones HTTPS. Filtrar el SSTP de manera específica requiere un dispositivo que opere en Layer 7.

Aunque durante varios años ha sido un protocolo exclusivo de sistemas operativos basados en Windows, los esfuerzos de la comunidad open-source han llevado tanto servidores como clientes a virtualmente casi cualquier sistema operativo, incluyendo GNU/Linux, OSX, BSD y los firmwares de algunos routers.

¿Puedo construirme un servidor SSTP en mi red doméstica?

La forma estándar y original de implementar un servidor VPN con este protocolo es utilizar el rol de Routing and Remote Access de Windows Server, aunque a día de hoy también lo podemos construir con otras tecnologías ya mencionadas, como el poderoso SoftEther VPN o el RouterOS de MikroTik.

Sea como sea, terminaremos con un requerimiento muy obvio: necesitamos escuchar en el puerto 443, por lo que si queremos conectarnos desde fuera de la red local, deberemos configurar nuestro router o dispositivo de gateway para que haga NAT del puerto 443 hasta nuestro servidor. Afortunadamente SSTP es totalmente compatible con NAT.

El problema viene aquí: ¿que ocurre si tenemos un servidor HTTPS en nuestra red y sólo tenemos una dirección IP pública? (algo muy común en los entornos de red domésticos). Como hemos dicho que en esencia el SSTP es HTTPS, ¡seguramente un proxy inverso pueda manejarlo! Mi infraestructura doméstica actualmente se parece a lo siguiente:

Sin embargo, a pesar de que el proxy inverso funciona correctamente y compruebo que los paquetes SSTP se entregan correctamente al servidor, no es posible establecer la conexión.

Examinando la conversación HTTPS entre ambos encuentro algo peculiar, al parecer, el protocolo SSTP utiliza un verbo HTTP que no se encuentra dentro del estándar del protocolo:

Method: SSTP_DUPLEX_POST
URI: /sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/
Protocol Version: HTTP/1.1
Content-Length: 18446744073709551615 (ULONGLONG_MAX)
Host: <Server Name>
SSTPCORRELATIONID: <GUID>

Este SSTP__DUPLEX__POST es lo que no se lleva bien con los proxies inversos, habiendo probado: Microsoft Web Application Proxy, Microsoft ARR, nginx y Apache Web Server; por lo que parece que esta aproximación no es posible.

Sé que una alternativa fácil habría sido construir el servidor en Microsoft Azure, donde no tenemos esa escasez de direcciones IP, sin embargo, un servidor VPN de cliente en Azure con objeto de salir al exterior tiene el peligro de incurrir en costes de ancho de banda, dependiendo del uso que le demos.

Una posible solución

Como habrás podido suponer, el servidor SSTP de Microsoft no se vale de IIS para escuchar conexiones, sino que utiliza directamente HTTP.SYS para ello. Esto quiere decir que a priori, SSTP e IIS no interfieren en absoluto.

Así que una posible solución es establecer nuestro servicio SSTP de RRAS en la misma máquina que nos hace de proxy inverso. Windows Server será suficientemente inteligente como para direccionar conexiones entrantes a un servicio u otro en función de si se trata de HTTPS estándar o bien SSTP.

El dibujo quedaría así:

Desafortunadamente esta opción sólo la tenemos usando el servidor oficial de Microsoft, ya que si optamos por otras tecnologías, el binding del puerto HTTPS compite con el de SSTP y no podemos establecer ambos servicios.

¿Y finalmente en la oficina?

La intención de todo esto era poder establecer un tunel SSTP desde mi oficina hasta mi red doméstica, donde no me veo cuartado el filtrado de puertos y puedo finalmente acceder a los recursos en el puerto 8080. Tras establecer el escenario aquí descrito, ¡pude conectar sin problemas!

Bonus: Let's Encrypt, SSTP y certificados SAN en Microsoft RRAS

Uno de los elementos a gestionar como administrador de un servicio SSTP, es que exactamente igual que ocurre con el HTTPS, es necesario gestionar certificados para cifrar las conexiones mediante SSL. Si a la hora de conectarnos a un servidor SSTP, el certificado que nos expone no es de confianza, el cliente de Microsoft rechazará amablemente la conexión por no considerarla segura.

Si trabajamos con un certificado autofirmado no tenemos más remedio que instalarlo en todas las máquinas cliente desde las que vayamos a conectarnos. Afortunadamente a día de hoy tenemos alternativa a usar autofirmados y a estar pagando cantidades ingentes a entidades certificadores por algo que tendría que ser un derecho por defecto: la seguridad de nuestras conexiones.

Aquí es donde entra Let's Encrypt. Se trata de una iniciativa del Internet Security Research Group y patrocinada por un importante número de empresas bien conocidas para constituir una entidad certificadora de confianza, automatizada y gratuita. Esto evidentemente, no le ha gustado a todo el mundo. Let's Encrypt plantea dos retos:

  • No soporta certificados con comodines (wildcards). Ej: *.calnus.com. La alternativa es utilizar certificados SAN, que permiten tener varios nombres. Ej: calnus.com, msx.calnus.com, aoe.calnus.com
  • Los certificados caducan a los 3 meses, los que nos obliga a llevar a cabo la buena práctica de automatizar todo el proceso de renovación.

Si nos lo llevamos al terreno del servidor SSTP de Microsoft, nos encontramos un reto adicional: a RRAS y DirectAccess no le gustan los certificados SAN y su configuración fallará si utilizamos como nombre de dominio otro distinto al del Subject.

¡Pero afortunadamente tenemos alternativa! Este artículo del Wiki de Technet explica como superar la restricción en el difunto UAG, pero aplica exactamente igual en Windows Server 2012 R2. Los cambios a implementar son sencillos:

Servidor DirectAccess/VPN

Abrir una línea de comandos como administrador y ejecutar lo siguiente:

netsh Interface HTTPStunnel Set Interface https://vpn.contoso.com:443/IPHTTPS
netsh Interface HTTPStunnel show interface

Si sólo estamos configurando el tunel SSTP y no DirectAccess no tenemos nada más que hacer.

Cliente DirectAccess

Crear una GPO que modifique la siguiente política:
Computer Configuration/Policies/Administrative Templates/Network/TCPIP Settings/IPv6 Transition Technologies/IP-HTTPS State

En IPHTTPS Url tendremos que escribir la dirección HTTPS que escribimos con el comando netsh en el servidor.

Si implementamos los cambios tendremos nuestro SSTP funcionando con certificado SAN de Let's Encrypt sin problemas y sin tener que instalar certificados autofirmados en nuestros equipos.

Happy tunneling!