Ich habe die unten gezeigte Datei nginx.conf.
Ich möchte sowohl SSH als auch einen Webserver auf Port 443/SSL ausführen.
Auch bekannt als SSL-Port-Multiplexing.
Gleichzeitig möchte ich SSL-Passthrough mit SNI verwenden.
Für SSH-Multiplexing verwende ich $ssl_preread_protocol.
Für SSL-SNI-Passthrough verwende ich $ssl_preread_server_name
Wenn ich einstelle proxy_pass $upstream;
, funktioniert SSH einwandfrei, aber die Webseite(n) funktionieren nicht.
Wenn ich einstelle proxy_pass $name;
, funktioniert SSL-SNI-Passthrough, aber auf SSH kann nicht zugegriffen werden.
Wie kann ich die beiden Kartenanweisungen kombinieren? Zum Beispiel so etwas wie
if $upstream = ssh
then proxy_pass $upstream
else proxy_pass $name;
endif
Das Problem besteht darin, dass ich eine Möglichkeit brauche, die Protokollauswahl mit der Servernamenauswahl zu kombinieren.
if(ssh) => forward to port 22
else => forward to port xy depending on server_name
Hier ist meine Konfigurationsdatei:
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;
}
}
Antwort1
Schon die Lösung gefunden?
Ich habe auch dieses Problem und versuche Folgendes. Es scheint in Ordnung zu sein.
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;
}
}
Antwort2
Nekromantie.
Ich beantworte meine eigene Frage zum Nutzen anderer.
Das ist mit nginx NICHT möglich (soweit ich weiß).
Sie können das Ziel jedoch mit HAproxy erreichen.
Die Konfiguration ist nicht ganz so einfach, sehen Sie sich also unten den Hack an, der bei mir funktioniert.
Beachten Sie, dass ich alle Werte mit Suchen und Ersetzen im Editor geändert habe (es können Fehler auftreten).
Diese Konfiguration setzt Folgendes voraus:
Server mit öffentlicher IP 44.33.22.11
lokale HTTP-Server, die auf den Ports laufen (8000+x auf demselben Server, auf dem HAproxy läuft, daher 127.0.0.1)
sshd läuft auf 127.0.0.1:22 (Port 22 derselben Maschine wie HAproxy)
zwei Domänen, jeweils http und https:
http://vorname-nachname.com/
https://vorname-nachname.com/
http://vorname-nachname.com/
https://vorname-nachname.com/
alle diese Domänen werden per DNS auf 44.33.22.11 aufgelöst
Wenn Sie das Proxy-Protokoll verwenden möchten (Proxy v2 ist das neueste), entfernen Sie das Kommentarzeichen # send-proxy-v2
z. B. aus der Zeile
server web0 127.0.0.1:8005 # send-proxy-v2
wird
server web0 127.0.0.1:8005 send-proxy-v2
Beachten Sie, dass sni-passthrough die Proxy-Reihenfolge umkehrt.
In nginx ist die Reihenfolge
-> request -> decrypt -> proxy headering decrypted request -> re-encrypt request -> forward
In haproxy SNI-passthrough wird die Reihenfolge
-> request -> proxy headering encrypted request -> forward
Somit ist die Middleware-Verarbeitungsreihenfolge in Ihren HTTP-Servern (auf Port 8000+x)
bei Verwendung von nginx -> SSL-decrypt -> unheader -> process
bei Verwendung von HAproxy-> unheader -> SSL-decrypt -> process
Dies liegt daran, dass ich auf HAproxy SNI-Passthrough verwende und in Nginx SSL-Schlüssel verwende (kein Passthrough). Diese kleine, unangenehme Tatsache hat mir viel Kopfzerbrechen bereitet.
Beachten Sie auch, dass ich zu Testzwecken example.int, foo.int und bar.int in der Hosts-Datei so eingerichtet habe, dass sie im lokalen Netzwerk auf 10.0.0.2 (interne Netzwerk-IP-Adresse der Maschine mit HAproxy) aufgelöst werden. Sie sehen diese Einträge immer noch in dieser haproxy.cfg-Datei
# /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
Diese Konfiguration leitet alle Anfragen weiter für
ssh [email protected] -p 443
Zu127.0.0.1:22
und alle Anfragen für
http://vorname-nachname.combis 127.0.0.1:800X, wobei X = 2n (gerade)
https://vorname-nachname.combis 127.0.0.1:800X, wobei X = 2n+1 (ungerade)
(die bessere Idee wäre gewesen, 800X für http und 900X für https zu verwenden)