Tengo el archivo nginx.conf que se muestra a continuación.
Quiero ejecutar ssh y un servidor web en el puerto 443/SSL.
También conocido como multiplexación de puertos SSL.
Al mismo tiempo, quiero utilizar SSL-passthrough con SNI.
Para multiplexación ssh, uso $ssl_preread_protocol.
Para SSL-SNI-passthrough, uso $ssl_preread_server_name
Si configuro proxy_pass $upstream;
, entonces ssh funciona bien, pero las páginas web no funcionan.
Si configuro proxy_pass $name;
, entonces el paso SSL-SNI funciona, pero no se puede acceder a ssh.
¿Cómo puedo combinar las dos instrucciones del mapa? por ejemplo, algo como
if $upstream = ssh
then proxy_pass $upstream
else proxy_pass $name;
endif
El problema es que necesito una forma de combinar la selección de protocolo con la selección de nombre_servidor.
if(ssh) => forward to port 22
else => forward to port xy depending on server_name
Aquí está mi archivo de configuración:
stream{
upstream ssh
{
server 127.0.0.1:22;
}
upstream https_default_backend
{
server 127.0.0.1:443;
}
upstream daniel_backend
{
server 127.0.0.1:5005;
}
map $ssl_preread_protocol $upstream
{
default ssh;
"TLSv1.3" https_default_backend;
"TLSv1.2" https_default_backend;
"TLSv1.1" https_default_backend;
"TLSv1" https_default_backend;
}
map $ssl_preread_server_name $name
{
localhost daniel_backend;
prodesk daniel_backend;
daniel-steiger.ch daniel_backend;
www.daniel-steiger.ch daniel_backend;
default https_default_backend;
}
# SSH and SSL on the same port
server {
listen 443;
ssl_preread on;
#proxy_protocol on;
# proxy_pass $upstream;
proxy_pass $name;
}
}
Respuesta1
¿Ya encontraste la solución?
Yo también tengo este problema y lo intento. Parece aceptable.
stream {
upstream ssh {
server 127.0.0.1:22;
}
upstream https_default_backend {
server 127.0.0.1:443;
}
upstream daniel_backend {
server 127.0.0.1:5005;
}
map $ssl_preread_protocol $upstream {
"" ssh;
default $name;
"TLSv1.3" $name;
"TLSv1.2" $name;
"TLSv1.1" $name;
"TLSv1" $name;
}
map $ssl_preread_server_name $name {
localhost daniel_backend;
prodesk daniel_backend;
daniel-steiger.ch daniel_backend;
www.daniel-steiger.ch daniel_backend;
default https_default_backend;
}
server {
listen 443;
ssl_preread on;
proxy_pass $upstream;
}
}
Respuesta2
Nigromancia.
Respondiendo a mi propia pregunta en beneficio de los demás.
Esto NO es posible con nginx (AFAIK).
Sin embargo, puedes lograr el objetivo con HAproxy.
La configuración no es tan fácil, así que mira a continuación el truco que me funciona.
Tenga en cuenta que cambié todos los valores con buscar y reemplazar (puede haber errores) en el bloc de notas.
Esta configuración asume lo siguiente:
Servidor con IP pública de 44.33.22.11
servidores http locales que se ejecutan en puertos (8000+x en el mismo servidor donde se ejecuta HAproxy, por lo tanto 127.0.0.1)
sshd ejecutándose en 127.0.0.1:22 (puerto 22 de la misma máquina que HAproxy)
dos dominios, cada uno http y https:
http://nombre-apellido.com/
https://nombre-apellido.com/
http://nombre-familia.com/
https://nombre-familia.com/
todos estos dominios DNS se resuelven en 44.33.22.11
Si desea utilizar el protocolo proxy (el proxy v2 es el más nuevo), descomente, # send-proxy-v2
por ejemplo, la línea
server web0 127.0.0.1:8005 # send-proxy-v2
se convierte
server web0 127.0.0.1:8005 send-proxy-v2
Tenga en cuenta que sni-passthrough invierte el orden del proxy.
En nginx, el orden es.
-> request -> decrypt -> proxy headering decrypted request -> re-encrypt request -> forward
Sin embargo, en haproxy SNI-pass, el orden se convierte en
-> request -> proxy headering encrypted request -> forward
Por lo tanto, el orden de procesamiento del middleware en sus servidores http (en el puerto 8000+x)
usando nginx es -> SSL-decrypt -> unheader -> process
mientras usa HAproxy, es-> unheader -> SSL-decrypt -> process
Esto se debe al uso de sni-passthrough en HAproxy y al uso de claves SSL en nginx (sin passthrough). Este pequeño y desagradable hecho me causó muchos dolores de cabeza.
También tenga en cuenta que configuré example.int, foo.int y bar.int en el archivo de hosts resolviendo en 10.0.0.2 (dirección IP de red interna de la máquina con HAproxy) en la red local para fines de prueba. Todavía ves estas entradas en este archivo haproxy.cfg
# /etc/haproxy/haproxy.cfg
# Validate:
# haproxy -c -V -f /etc/haproxy/haproxy.cfg
# Another way is to
# sudo service haproxy configtest
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_comACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http
bind *:80
mode http
option forwardfor
# option httpchk /check.cfm
# use-server server1 if { hdr(host) -i server1.domain.net }
# use-server server2 if { hdr(host) -i server2.domain.net }
# server server1 localhost:22201 check
# server server2 localhost:22202 check
# default_backend nodes
# redirect scheme https code 301 if !{ ssl_fc }
# http://10.0.0.2/.well-known/acme-challenge/token.txt
# http://44.33.22.11/.well-known/acme-challenge/token.txt
# http://firstname-lastname.com/.well-known/acme-challenge/token.txt
# http://forename-familyname.com/.well-known/acme-challenge/token.txt
# https://www.haproxy.com/documentation/aloha/12-5/traffic-management/lb-layer7/acls/
# For ACLs sharing the same name, the following rules apply:
# It is possible to use the same <aclname> for many ACLs, even if they do not have the same matching criterion
# A logical OR applies between all of them
# acl firstname_lastname_com dst 10.0.0.2
# acl firstname_lastname_com dst 44.33.22.11
acl firstname_lastname_com hdr(host) -i 44.33.22.11
acl firstname_lastname_com hdr(host) -i 10.0.0.2
acl firstname_lastname_com hdr(host) -i firstname-lastname.com
acl firstname_lastname_com hdr(host) -m end .firstname-lastname.com
acl forename_familyname_com hdr(host) -i forename-familyname.com
acl forename_familyname_com hdr(host) -m end .forename-familyname.com
#use_backend http_firstname_lastname_com if { hdr(host) -i firstname-lastname.com }
#use_backend http_firstname_lastname_com if { hdr(host) -m end .firstname-lastname.com }
use_backend http_firstname_lastname_com if firstname_lastname_com
use_backend http_forename_familyname_com if forename_familyname_com
backend http_firstname_lastname_com
mode http
balance roundrobin
server web0 127.0.0.1:8006
backend http_forename_familyname_com
mode http
balance roundrobin
server web0 127.0.0.1:8008
#backend nodes
# mode http
# balance roundrobin
# option forwardfor
# reqirep ^Host: Host:\ node1.myapp.mycompany.com
# server web01 node1.myapp.mycompany.com:80
# sudo systemctl stop nginx
# sudo systemctl disable nginx
# sudo systemctl enable haproxy
# service haproxy start
# sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg
# service haproxy restart
frontend https
bind *:443
mode tcp
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
#tcp-request content accept if { req_ssl_hello_type 1 }
# https://datamakes.com/2018/02/17/high-intensity-port-sharing-with-haproxy/
# systemctl restart sshd
# systemctl disable sshd
# systemctl enable sshd
# sudo apt-get install openssh-server
# sudo systemctl status ssh
# sudo ufw allow ssh
# sudo ufw enable
# sudo ufw status
# ufw allow 443/tcp
# ufw allow 8443/tcp
# /etc/ssh/sshd_config ==> PermitRootLogin yes + PasswordAuthentication no + ChallengeResponseAuthentication no ~/.ssh/id_rsa.pub ==> ~/.ssh/authorized_keys
acl ssh_payload payload(0,7) -m bin 5353482d322e30
# /mnt/sshfs/var/www/.dotnet/corefx/cryptography/crls/
# sudo apt-get install exfat-utils exfat-fuse
# https://10.0.0.2/.well-known/acme-challenge/token.txt
# https://44.33.22.11/.well-known/acme-challenge/token.txt
# http://firstname-lastname.com/.well-known/acme-challenge/token.txt
# http://forename-familyname.com/.well-known/acme-challenge/token.txt
# https://www.haproxy.com/documentation/aloha/12-5/traffic-management/lb-layer7/acls/
# For ACLs sharing the same name, the following rules apply:
# It is possible to use the same <aclname> for many ACLs, even if they do not have the same matching criterion
# A logical OR applies between all of them
# sequence matters !
use_backend openssh if ssh_payload
use_backend openssh if !{ req.ssl_hello_type 1 } { req.len 0 }
# having these two lines here blocks ssh if use_backend openssh comes afterwards ...
# also, this fucks up SNI ...
# acl firstname_lastname_com dst 10.0.0.2
# acl firstname_lastname_com dst 44.33.22.11
acl firstname_lastname_com req_ssl_sni -i firstname-lastname.com
acl firstname_lastname_com req.ssl_sni -m end .firstname-lastname.com
acl forename_familyname_com req_ssl_sni -i forename-familyname.com
acl forename_familyname_com req.ssl_sni -m end .forename-familyname.com
# wildcard
use_backend https_firstname_lastname_com if firstname_lastname_com
use_backend https_forename_familyname_com if forename_familyname_com
# use_backend example_int if { req_ssl_sni -i example.int }
# use_backend example_int if { req_ssl_sni -m end .example.int }
# use_backend example_int if { req_ssl_sni -i example.int }
# use_backend foo_int if { req_ssl_sni -i foo.int }
# use_backend bar_int if { req_ssl_sni -i bar.int }
# sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg
backend https_firstname_lastname_com
mode tcp
balance roundrobin
server web0 127.0.0.1:8005 # send-proxy-v2
backend https_forename_familyname_com
mode tcp
balance roundrobin
server web0 127.0.0.1:8007 # send-proxy-v2
backend foo_int
balance roundrobin
server web1 127.0.0.1:8005 send-proxy
backend bar_int
balance roundrobin
server web2 127.0.0.1:8005 ##send-proxy
backend openssh
mode tcp
# option tcplog
# option tcp-check
# tcp-check expect string SSH-2.0-
timeout server 3h
# server openssh 127.0.0.1:22 check
server openssh 127.0.0.1:22
Esta configuración reenvía todas las solicitudes de
ssh [email protected] -p 443
a127.0.0.1:22
y todas las solicitudes de
http://nombre-apellido.coma 127.0.0.1:800X donde X = 2n (par)
https://nombre-apellido.coma 127.0.0.1:800X donde X = 2n+1 (impar)
(la mejor idea hubiera sido usar 800X para http y 900X para https)