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:
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:
Dentro de cada um dos backends, temos a definição de cada um dos servidores-destino que irão responder pelo servico:
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).
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:
Em seguida, é necessário definir as ACL’s:
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.
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
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