Saltando bloqueos de los ISP: HAProxy y autossh

¡Este último mes podríamos decir que he estado muy entretenida! Hace ya casi dos años, un cliente vino a mi harto de que los proveedores de hosting le cerrasen el servidor, durante todo este tiempo de maravilla, hasta que hace un mes y medio Movistar y Vodafone bloquearon el dominio. Ahí es cuando el cliente me contactó de nuevo para realizar un análisis y un informe pericial. El motivo es que el cliente no está realizando ningún acto delictivo que lleve a los proveedores de hosting e ISP a bloquear el servicio, aún así, lo hacen, estamos delante de un caso de Internet Blackout, bloqueo interesado de un servicio en concreto para que los usuarios no puedan acceder a él. ¿Algo ha tenido que ver el recién finalizado y polémico Mundial de Fútbol en Qatar?.

En la fecha del bloqueo del dominio del cliente, mi propuesta al identificar que el bloqueo se estaba realizando a nivel de dominio (que no de DNS, ya que estos si resolvían), le propuse al cliente de registrar otro dominio. La solución funcionó durante 2 semanas más hasta que Movistar y Vodafone bloquearon la dirección IP, como tal, la solución de añadir mas dominios apuntando al servidor, ya no era útil. Por mas INRI, el bloqueo se extendió a más ISP, aislando casi por completo el servidor de Internet (y no sólo en España, otros países de Europa y LatinoAmérica se vieron afectados), pero no todos lo bloquearon!

A partir de aquí se empezó a analizar qué soluciones teníamos para hacer llegar de nuevo el servicio a los usuarios (y a los propios servidores que conforman el servicio que algunos también perdieron comunicación). Lo primero era plantear usar un cdn, el mas conocido cloudflare.com, ¿a que no hay cojones de volver a bloquear un servicio de estos enteros?, pero los servidores de este servicio no llegaban a la IP del servidor. Así que opción descartada.

Se barajó la opción de usar un servidor o router intermedio con un operador que no estuviese realizando el bloqueo ilegal. Finalmente se optó por un servidor y VPN Wireguard.

Al realizar la configuración, al contratar el servidor más barato posible, evidentemente, una cosa de estas será un VPS, un servidor virtualizado con vete a saber qué tecnología (interfaz de red venet0), al levantar la interfaz wireguard dijo que na’ de na’:

# apt install wireguard
# ip link add wg0 type wireguard

Por aquí no se podía seguir, además en un entorno de pruebas sin límite, las reglas de iptables conseguí que se mandasen los paquetes pero no que estos volviesen por donde yo quería.

Así que la solución, gracias a una recomendación de un amigo, fue usar haproxy. Así que veremos como lo he desarrollado:

HAProxy

Lo primero será instalarlo:

# apt -y install haproxy

Y lo siguiente configurarlo:

# cd /etc/haproxy/
# mv haproxy.cfg{,.old}
# vi haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    log /dev/log    local0 info info
    log /dev/log    local1 notice info
    pidfile     /var/run/haproxy.pid
    maxconn     4096
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

#############  SSL  ###################
    # Tunning secure HTTPS
    ssl-default-bind-options no-sslv3 no-tls-tickets no-sslv3 no-tlsv10 no-tlsv11
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:!aNULL:!MD5:!DSS
    tune.ssl.default-dh-param 2048
########################################

defaults
    mode                    http
    # log                     global
    # option                  httplog
    option                  dontlognull
    option                  redispatch
    retries                 3
    timeout http-request    100s
    timeout queue           1m
    timeout connect         300s
    timeout client          10m
    timeout server          10m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

#---------------------------------------------------------------------
# Stats
#---------------------------------------------------------------------
listen stats
        bind *:8083
        mode http
        stats enable
        stats uri /
        stats realm HAProxy\ Statistics
        stats auth haproxy:***************
        stats refresh 10s


#---------------------------------------------------------------------
# Frontend
#---------------------------------------------------------------------
frontend http-in-cliente
        mode http
        bind :::80 v4v6
	bind *:443 ssl crt /etc/ssl/cliente/cliente.pem

	# comentat per laura (no funciona la renovacio de certificats amb això)
        #option  forwardfor except 127.0.0.0/8
	http-response set-header Server cliente-proxy

	# comentat per laura
	#acl is-blocked-ip src -f /usr/local/scripts/ipsfirewall1.conf
        #http-request deny if is-blocked-ip

        # Test URI to see if its a letsencrypt request
	acl letsencrypt-acl path_beg /.well-known/acme-challenge/
	use_backend letsencrypt-backend if letsencrypt-acl

	# Redirects
	# comentat per laura
        #redirect prefix https://clientemalo.eu    code 301 if { hdr(host) -i -f /etc/haproxy/clientemalo_eu_trusted.cfg }
	redirect scheme https if !{ ssl_fc }

	# Security Hardening
        http-response del-header (^Server.*|^X-Powered-By:.*|^X-Runtime.*|^X-Version.*|^X-AspNet-Version.*)
	http-response set-header Server cliente-proxy
        http-response set-header X-Content-Type-Options nosniff
        http-response set-header X-XSS-Protection 1;\ mode=block

        # ACLS
	# headers
	acl host_no_X_Frame_Options res.hdr(X-Frame-Options) -m found
	http-response set-header X-Frame-Options SAMEORIGIN if !host_no_X_Frame_Options 

	# webserver hosts
	acl host_otrodominio_eu hdr(host) -i otrodominio.eu
	acl host_clientemalo_eu hdr(host) -i clientemalo.eu
	
	# backends
        # define backends
        use_backend backend_otrodominio_eu if host_otrodominio_eu
	use_backend backend_clientemalo_eu if host_clientemalo_eu
		
#---------------------------------------------------------------------
# Backends WWW
#---------------------------------------------------------------------

# LE Backend
backend letsencrypt-backend
	server letsencrypt 127.0.0.1:8888


backend backend_otrodominio_eu
        option forwardfor
        http-request set-header X-Forwarded-Host %[req.hdr(Host)]
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        server server_otrodominio_eu X.X.X.X:XXXX check maxconn 1024 


backend backend_clientemalo_eu
        option forwardfor
        http-request set-header X-Forwarded-Host %[req.hdr(Host)]
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
	server server_clientemalo_eu X.X.X.X:XXXX check maxconn 1024

Aquí en esta configuración tengo generado el certificado usando letsencrypt y varios dominios en el mismo certificado:

# certbot certonly --standalone -d otrodominio.eu -d clientemalo.eu --non-interactive --agree-tos --email info@clientemalo.net --http-01-port=8888 --expand

Le indicamos que en lugar de usar el puerto 80 o 443 por defecto, use el puerto 8888 (que no lo hemos definido en el frontend ni tampoco tenemos ningún nginx o apache instalado en el servidor, el puerto lo crea internamente haproxy y no se hace ningún bind en el sistema)

En este post del foro de serverfault, hablan de varias formas de como usar certificados independientes para cada dominio.

En mi caso, he creado un script para adaptar los certificados de letsencrypt para que los pueda interpretar haproxy

# vi /root/scripts/renew_le.sh
#!/bin/bash

# Renew the certificate
certbot renew --force-renewal --http-01-port=8888

# Concatenate new cert files, with less output (avoiding the use tee and its output to stdout)
bash -c "cat /etc/letsencrypt/live/clientemalo.eu/fullchain.pem /etc/letsencrypt/live/clientemalo.eu/privkey.pem > /etc/ssl/cliente/cliente.pem"

# Reload  HAProxy
service haproxy reload

Le damos permisos de ejecución y le indicamos que se actualice cada primer día del mes

# chmod +x /root/scripts/renew_le.sh
# vi /etc/crontab
# renew certificates
* * 1 * * root /root/scripts/renew_le.sh

Y listos! una de las dudas que tenía era si Movistar había llegado a bloquear el dominio nuevo, y parece que no ;) así que durante unos días es posible saltar el bloqueo ilegal y digo ilegal porqué en estos casos es un juez quien debe dictar bloquear un servicio y no alguien a quien le pica la entrepierna y menos alguien fuera de la UE.

Ahora vamos a ver la segunda parte de este post, autossh.

autossh

El otro problema que se encontró el cliente es que los distintos servidores que ofrecían el servicio no se podían “ver” entre ellos. Así que se hizo uso de este servidor donde se configuró el HAProxy y se habilitó el servicio autossh, que sirve para tunelizar conexiones ssh.

Lo primero, instalarlo

# apt -y install autossh

Lo siguiente, generar el par de claves pública y privadas ssh en el servidor

# cd /root/.ssh
# ssh-keygen -t rsa

Añadimos el contenido de id_rsa.pub al fichero /root/.ssh/authorized_keys del servidor al que queremos conectar y realizamos la conexión por SSH:

# ssh root@ip_servidor_1
# ssh root@ip_servidor_2

Ahora realizamos la conexión con autossh para comprobar que funciona:

# autossh -f -N -L \*:2XXX:localhost:22   ip_servidor_1 -i /root/.ssh/id_rsa
# autossh -f -N -L \*:2XXX:localhost:22   ip_servidor_2 -i /root/.ssh/id_rsa
# netstat -lanp |grep 'LISTEN ' |grep ssh        
tcp        0      0 0.0.0.0:2XXX            0.0.0.0:*               LISTEN      21284/ssh           
tcp        0      0 0.0.0.0:2XXX            0.0.0.0:*               LISTEN      16070/ssh                     
tcp        0      0 127.0.0.1:62XXX         0.0.0.0:*               LISTEN      21299/autossh       
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      297/sshd: /usr/sbin           
tcp        0      0 127.0.0.1:58XXX         0.0.0.0:*               LISTEN      16069/autossh       
tcp6       0      0 ::1:54208               :::*                    LISTEN      21284/ssh           
tcp6       0      0 :::2XXX                 :::*                    LISTEN      21284/ssh           
tcp6       0      0 :::2XXX                 :::*                    LISTEN      16070/ssh                     
tcp6       0      0 :::22                   :::*                    LISTEN      297/sshd: /usr/sbin  

Como podemos ver aparecen los dos puertos que hemos indicado a autossh

Para aplicar esta configuración al iniciar el sistema añadiremos un par de líneas en el fichero /etc/rc.local

# vi /etc/rc.local

# Servidor 1
autossh -f -N -L \*:2XXX:localhost:22   ip_servidor_1 -i /root/.ssh/id_rsa

# Servidor 2
autossh -f -N -L \*:2XXX:localhost:22   ip_servidor_2 -i /root/.ssh/id_rsa

Y todo accesible y conectado de nuevo! ;)

A ver cuál es el siguiente bloqueo que nos realizan, de momento todos han sido técnicos y ninguno jurídico, almenos nosotros como operador no hemos recibido ninguna petición de bloquear el servicio del cliente y aún sin ningún procedimiento judicial abierto.

PS: El cliente me ha dado permiso para publicar su caso
PS2: El abogado recomienda omitir la mención al cliente, por lo que ha sido reemplazado por clientemalo. El contenido de este post es para fines educativos y todo lo mencionado técnicamente es lo que se usa diariamente en sistemas de nube. Aprovecho para recordar que no me hago responsable del uso que le hagan los lectores de mi blog con su contenido.

One Comment

  1. Buenísimo de verdad aprendí mucho, y tengo muchas ganas de ser mejor sysadmin

    Respon

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

Aquest lloc utilitza Akismet per reduir els comentaris brossa. Apreneu com es processen les dades dels comentaris.