Skip to content

Instantly share code, notes, and snippets.

@haproxytechblog
Created December 21, 2020 14:53
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save haproxytechblog/da49a99809c14a47042ac9b3ff04c549 to your computer and use it in GitHub Desktop.
Save haproxytechblog/da49a99809c14a47042ac9b3ff04c549 to your computer and use it in GitHub Desktop.
Route SSH Connections with HAProxy
frontend fe_ssh
bind *:2222 ssl crt /etc/haproxy/certs/ssl.pem
mode tcp
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dst:%[var(sess.dst)] "
tcp-request content set-var(sess.dst) ssl_fc_sni
use_backend %[ssl_fc_sni]
backend server1
mode tcp
server s1 192.168.0.201:22 check
backend server2
mode tcp
server s2 192.168.0.202:22 check
backend server3
mode tcp
server s2 192.168.0.203:22 check
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername server1" dummyName1
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername server2" dummyName2
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername server3" dummyName3
frontend fe_ssh
bind *:2222 ssl crt /etc/haproxy/certs/ssl.pem
mode tcp
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dst:%[var(sess.dst)] "
tcp-request content set-var(sess.dst) ssl_fc_sni
default_backend ssh-all
backend ssh-all
mode tcp
tcp-request content set-dst var(sess.dst)
server ssh 0.0.0.0:22
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername 192.168.0.201" dummyName1
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername 192.168.0.202" dummyName2
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:2222 -servername 192.168.0.203" dummyName3
backend ssh-all
mode tcp
acl allowed_destination var(sess.dst) -m ip 192.168.0.201
acl allowed_destination var(sess.dst) -m ip 192.168.0.202
acl allowed_destination var(sess.dst) -m ip 10.0.12.0/24
tcp-request content set-dst var(sess.dst)
tcp-request content accept if allowed_destination
tcp-request content reject
server ssh 0.0.0.0:22
resolvers internal
accepted_payload_size 8192
nameserver dns1 192.168.0.20:53
resolve_retries 3
timeout resolve 1s
timeout retry 1s
hold other 30s
hold refused 30s
hold nx 30s
hold timeout 30s
hold valid 10s
hold obsolete 30s
frontend fe_ssh
bind *:2222 ssl crt /etc/haproxy/certs/ssl.pem
mode tcp
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dstName:%[var(sess.dstName)] dstIP:%[var(sess.dstIP)] "
tcp-request content do-resolve(sess.dstIP,internal,ipv4) ssl_fc_sni
tcp-request content set-var(sess.dstName) ssl_fc_sni
default_backend ssh-all
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:222 -servername ssh-server1.example.local" dummyName1
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:222 -servername ssh-server2.example.local" dummyName2
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:222 -servername ssh-server3.example.local" dummyName3
backend ssh-all
mode tcp
acl allowed_destination var(sess.dstIP) -m ip 192.168.0.201
acl allowed_destination var(sess.dstIP) -m ip 192.168.0.202
acl allowed_server_names var(sess.dstName) -i -- ssh-server3.example.local
tcp-request content set-dst var(sess.dstIP)
tcp-request content accept if allowed_server_names
tcp-request content accept if allowed_destinations
tcp-request content reject
server ssh 0.0.0.0:22
frontend fe_ssh
# ...other settings...
tcp-request inspect-delay 5s
acl valid_payload req.payload(0,7) -m str "SSH-2.0"
tcp-request content reject if !valid_payload
tcp-request content accept if { req_ssl_hello_type 1 }
frontend fe_ssh
bind *:222 ssl crt /etc/haproxy/certs/ssl.pem ca-file /etc/haproxy/certs/LabCA.pem verify required
mode tcp
log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dstName:%[var(sess.dstName)] dstIP:%[var(sess.dstIP)] user:%[ssl_c_s_dn(CN)]"
tcp-request content do-resolve(sess.dstIP,internal,ipv4) ssl_fc_sni
tcp-request content set-var(sess.dstName) ssl_fc_sni
default_backend ssh-all
backend ssh-all
mode tcp
tcp-request content set-dst var(sess.dst)
acl authorized_users ssl_c_s_dn(CN),concat(:,sess.dst) -i -f /etc/haproxy/user_authorization.acl
tcp-request content reject if !authorized_users
server ssh 0.0.0.0:22
$ ssh -o ProxyCommand="openssl s_client -quiet -connect 172.16.0.10:222 -servername 192.168.0.201 -cert mycert.crt -key mykey.key" dummyName1
acl authorized_users ssl_c_s_dn(OU),concat(:,sess.dst) -i -f /etc/haproxy/user_authorization.acl
@jcw778
Copy link

jcw778 commented Oct 15, 2022

What is the dummyName1/2/3?
How can I use this for scp upload?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment