6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Haproxyを用いて443ポートで複数サービスをホストする

Last updated at Posted at 2020-04-16

#はじめに
グローバルIPが1つしかないプライベートなサーバーで443ポートはかなり貴重です。

元々SSH,OpenVPN,HTTPSといった各サービスの標準ポートを使えば何ら問題はないんですが、80,443しか通さない強固なプロキシや◯盾等のけしからんネットワークを掻い潜るためには、どうしても443ポートを使用してHTTPSに偽装する必要が生じます。

それらのサービスを同時にホストするためのプロキシとしてSSLHがありますが、プロトコル判定ルールがソースレベルで定義されているため、定義にないプロトコルを追加することは少々難しいです。

拙記事 SSLHでSoftether(SSTP)とApacheを共存
https://qiita.com/Shachihoko/items/64a519b930b26ee4e81e

そこで今回はDPIっぽい挙動ができる汎用プロキシである Haproxy を用いていくつかのプロトコルの通信を同時にホストする方法を模索します。

参考サイト
WebサーバーとSSHサーバーが同一ポートで待ち受けるSSLHの動作原理とは
https://blog.millenary.net/archives/48

2020/04/24 フロントエンドサーバーの設定に1行追記しました。

#環境
今回対象とするプロトコル
・HTTPS
・SSTP
・OpenVPN
・Softether VPN
・SSH

現状443ポートをリッスンしているサービスがあれば変更しておきます
ここでは各サービスのアドレスを以下として進めます.

・Nginx(HTTPS) 127.0.0.1:10443
・sshd 127.0.0.1:22
・Softether(SSTP,OpenVPN,SoftetherVPN) 127.0.0.1:1194

※SSTPとSoftetherVPNプロトコルの判別にSNIホスト名を使用するので、加えてvpn.foo.barというホスト名で正引きできるようにしておきます

#HAproxyの設定
インストール

$sudo apt-get install haproxy

設定

/etc/haproxy/haproxy.cfg
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
        crt-base

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        # An alternative list with additional directives can be obtained from
        #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

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

[global]で書き換えが必要なのは以下だけです

# Default SSL material locations
        ca-base #SSL証明書の公開鍵
        crt-base #SSL証明書の秘密鍵

末尾にプロキシの設定を追記していきます。

###フロントエンドサーバーの設定

/etc/haproxy/haproxy.cfg
frontend https
    mode                tcp #TCPプロキシとして稼働させるのでtcpを指定
    bind                *:443 #443で待受
    tcp-request         inspect-delay 5s #遅延を5秒まで許可(SSLでは必要)

###SSHプロトコルの判別
SSHプロトコルの最初のペイロードパケットはSSH-2.0の7文字で始まるため、これを16進数表記にした5353482d322e30で始まるという条件を acl 属性で設定し、これにマッチする接続をbk-ssh-serverに転送

    acl                 ssh-server req.payload(0,7) -m bin 5353482d322e30
    tcp-request         content accept if ssh-server
    use_backend         bk-ssh-server if ssh-server

###SSTP,SoftetherVPNプロトコルの判別
SSTPプロトコルのパケットには通常のHTTPS通信と同様にSNIのためのホスト名情報が含まれているので、これをHAproxyで読み取り、事前にVPN用として設定したホスト名vpn.foo.barと一致すればbk-sstp-serverに転送

    use_backend bk-sstp-server if { req_ssl_sni -i vpn.foo.bar }

###HTTPSプロトコルの判別
SSTPプロトコルを分岐した後に、SSLのClient Helloを通知してきた残りのパケットをbk-nginx-serverに転送

    use_backend bk-nginx-server if { req.ssl_hello_type 1 }

###OpenVPNの判別
(WireSharkでキャプチャしても尻尾が掴めなかったので)
以上の条件にマッチしなかったパケットは全てbk-openvpn-serverに転送

    default_backend     bk-ovpn-server

以下がフロントエンドの設定です

/etc/haproxy/haproxy.cfg
frontend https
    mode                tcp
    bind                *:443
    tcp-request         inspect-delay 5s

    tcp-request content accept if { req.ssl_hello_type 1 } #これを明示的に記述しないと判定が安定しなかった

    acl                 ssh-server req.payload(0,7) -m bin 5353482d322e30
    tcp-request         content accept if ssh-server
    use_backend         bk-ssh-server if ssh-server

    use_backend bk-sstp-server if { req_ssl_sni -i vpn.foo.bar }
    
    use_backend bk-nginx-server if { req.ssl_hello_type 1 }
    
    default_backend     bk-ovpn-server

###バックエンドサーバの設定
フロントエンドの設定に続ける形で書き込む
各自の環境に合わせて設定してください、ここでは前述の仮定環境を想定しています

/etc/haproxy/haproxy.cfg
backend bk-sstp-server
    mode                        tcp
    server                      default 127.0.0.1:1194

backend bk-ssh-server
    mode                        tcp
    server                      default 127.0.0.1:22

backend bk-nginx-server
    mode                        tcp
    server                      default 127.0.0.1:10443

backend bk-ovpn-server
    mode                        tcp
    server                      default 127.0.0.1:1194

###HAproxyの起動

$ sudo systemctl start haproxy
$ sudo systemctl enable haproxy

#最後に
※このプロキシを設定した状態で、SoftetherVPNクライアントから接続する場合はクライアントの設定でUDP高速化機能を無効にするにチェックを入れてください。

SSLHを使用するのが設定としては簡単ですが、この方法だと判別ルールさえ設定できれば独自プロトコルを含めた柔軟なTCPプロキシサーバーが構築できるので応用は効くのではないかと思います。

6
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?