TCP Port Sharing – Multi-Serviços em SSL

Bom dia a todos,

Foi me recentemente colocado um desafio interessante sobre reutilização de portos TCP.
O Cliente que me colocou o desafio tem um VDC, com apenas um IP publico, e necessita correr no mesmo porto (TCP 443) dois serviços distintos. Um https e um serviço TLS sem ser https.

Utilizar o  mod_proxy de um apache, ou um reverse squid proxy está fora de questão por quebrar o protocolo aplicacional não https

Então como proceder?

Por sorte, este cliente tem uma pfSense virtual a frente do seu VDC o que nos auxiliou em muito na tarefa, pois bundled na pfsense vem o software haproxy que será fundamental para esta resolução.

Em primeiro lugar foi necessário instalar o HAproxy através do package manager da pfSense:

1

2

Como podem notar, o pacote instalado foi o haproxy-devel. A razão desta escolha prende-se com a interface de configuração da mesma que nos permite escolher backends específicos em relação a condições (acls). A versão haproxy simples não permite esta configuração.

Já no menu de configuração do HAProxy, foi necessário definir os backend servers:

Foram definidos dois, um para o tráfego https “normal” e o outro para o serviço TLS encapsulado:

3
Dentro de cada um dos backends, temos a definição de cada um dos servidores-destino que irão responder pelo servico:

4

5
Nota: Cada um dos servidores embora esteja a funcionar em TLS/SSL, não está definido como tal.
Não nos interessa que o pfSense faça de tcpoffload ao SSL pois isso iria quebrar o protocolo da aplicação (como aconteceria se se utiliza-se um reverse proxy normal).
Notem igualmente que o balance mode é none pois estamos apenas a balançar para um host.

Finalmente, na secção de frontend iremos definir as regras de onde e como encaminhar o tráfego:

Em primeiro lugar definimos o VIP (onde o serviço irá ser disponibilizado e a porta do mesmo).

6

Depois, configuramos o tipo de balanceador.  No caso especifico, como o protocolo não pode sofrer um ssl offload, e consequentemente um man in the middle, colococamos este balanceador em tcp forward only:

10
Em seguida, é necessário definir as ACL’s:

7
O name é o nome pelo qual a ACL é conhecida, a expressão em custom acl referente ao valor.
No caso presente, a primeira valida se é efetivamente uma ligação TLS, e a segunda valida se o URL onde se estão a tentar ligar depois do -i é o FQDN pretendido (no fim deste post colocarei a config em texto para que entendam melhor).

Em seguida, colocaremos as ações quando as ACLS’s são encontradas.

8
Nota: A ultima ação deverá ser sempre o servidor de https e a primeira o serviço que responde em SSL.
O motivo disto é simples. Se colocarem a regra do https primeiro, ele vai sempre encaminhar para lá o tráfego – todo o tráfego é efetivamente em ssl.
Se colocarem a regra do serviço primeiro, ele vai validar para onde estão a encaminhar o pedido (FQDN) e desvia o tráfego nessa direção.

Finalmente adicionar as seguintes linhas na secção advanced

9

Embora o post tenha sido fortemente censurado na parte gráfica, acrescento a configuração em texto de forma a que possam entender melhor o que foi feito e em BOLD as notas sobre os pontos:

frontend port-4443
        bind 0.0.0.0:4443
        mode tcp
        tcp-request inspect-delay 5s
        tcp-request content accept if { req.ssl_hello_type 1 }

        # SSL connection
        acl proto_tls req.ssl_hello_type 1
        acl ocserv req.ssl_sni -i xmpp.domain.com  (O FQDN que será utilizado para rencaminhar o tráfego, quando a condição se confirmar)

        use_backend b_xmpp if xmpp (utilizar o backend b_xmpp quando o ACL se confirmar)
        use_backend b_https if proto_tls

        default_backend b_https

backend b_https
        mode tcp
        option tcplog
        server https 10.16.0.14:443
        timeout server 2h

backend b_xmpp
        mode tcp
        option tcplog
        server https 10.16.3.150:443
        timeout server 2h

Caso tenham duvidas como sempre estou disponível para vos ajudar. Já sabem onde me encontrar.

Até já.

Abraço
Nuno