ホスト・クライアント共にHTTPプロキシ配下にある環境にて,RDP接続を行ってみました.
タイトルの文字数を気にするあまり意味不明な感じになっていますが,要はHTTPプロキシのCONNECTを通じた443/TCP以外の自由な通信が許されない環境にてRDPしてみたという話です.
プロキシ要素を取り除けばモバイル回線やCATVといったCGNAT下でもそのまま(RDPに限らず)応用可能なので,割と便利なんじゃないかと思います.
構成図
(スペルチェッカーが写ってるのは気にしない)
必要な物
- 踏み台サーバ
- RDPホスト
- RDPクライアント
- ドメイン
nginxのストリームプロキシを使ってfrpとwebsocketを同じポートで動かしています.
なので既存のウェブサーバがあればそのまま挿入することも可能
frp
https://github.com/fatedier/frp
frpはローカルのポートを踏み台経由で公開するソフトウェアで,サーバであるfrpsとクライアントであるfrpcから構成されます.
現在G-Clusterの実験でも使用しており,規制中のpovo回線でも圧倒的な安定感を誇ります.
Gost
https://github.com/ginuerzh/gost
Goで書かれた,トンネル技術を網羅したソフトウェアです.
これ1つで様々なトンネルやプロキシに対応できますが,今回は踏み台からRDPクライアントまでをWebSocketで繋いで貰います.
TCPからWebSocketに変換,逆変換が出来るので大変便利です.
今回の環境
場所 | OS |
---|---|
踏み台サーバ | Rocky Linux(SELinux無効) |
RDPホスト | Windows 10 Pro |
RDPクライアント | Windows 10 Pro |
1. サーバ設定
では踏み台から.
frp
- 実行ファイルの用意
|
|
- frps.iniの編集
|
|
|
|
*トークンは認証に利用するfrpcと共通の文字列です.適当に生成したbase64あたりで良いと思います.
*証明書は https://github.com/fatedier/frp#encryption-and-compression を見ながら作る
- 実行
|
|
Gost
- 実行ファイルの用意
|
|
- 実行
|
|
nginx
- ドメインの用意
サブドメインでいいので用意しとくと楽です.
Let’s Encryptあたりでドメインの証明書を用意して下さい.
- CA/証明書の用意
セキュリティのため,TLSクライアント認証を利用します.
https://qiita.com/tarosaiba/items/9fa3320b633e0f5e87b5
あたりを参考にしながら/etc/nginx/rdp-ca/に用意して下さい.
- 設定
|
|
stream {
upstream frp {
server 127.0.0.1:8882;
}
upstream web {
server 127.0.0.1:8443;
}
map $ssl_preread_protocol $upstream {
default frp;
"TLSv1.3" web;
"TLSv1.2" web;
"TLSv1.1" web;
"TLSv1.0" web;
}
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
proxy_protocol on;
}
server {
listen 127.0.0.1:8882 proxy_protocol;
proxy_pass 127.0.0.1:8880;
}
}
|
|
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server 127.0.0.1:8883;
}
server {
listen 80;
listen [::]:80;
server_name <ドメイン>;
if ($request_uri !~ ^/.well-known/) {
return 301 https://$host$request_uri;
}
}
server {
listen 127.0.0.1:8443 ssl http2 proxy_protocol;
server_name <ドメイン>;
real_ip_header proxy_protocol;
set_real_ip_from 127.0.0.1;
ssl_certificate /etc/letsencrypt/live/<ドメイン>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<ドメイン>/privkey.pem;
ssl_verify_client on;
ssl_client_certificate /etc/nginx/rdp-ca/ca.crt;
location / {
return 401;
}
location /ws {
proxy_http_version 1.1;
proxy_pass http://websocket;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 61s;
proxy_buffering off;
}
}
- nginx 再起動
|
|
2. RDPホスト設定
ホストでは転送のためにfrpcを利用します.
https://github.com/fatedier/frp/releases/tag/v0.44.0 から適切なバイナリを用意して展開します.
SSHあたりで証明書を持ってきて,frpc.iniをこんな感じに
|
|
後は普通に
|
|
で起動すればOK
3. RDPクライアント設定
クライアントではWebSocketを使用して接続します.
https://github.com/ginuerzh/gost/releases/tag/v2.11.2 から適当なバイナリをダウンロードして展開
なぜかWindows版がウイルス判定を食らいます.心配なら自分でビルドすればOK
nginxのクライアント証明書を同じディレクトリにコピーし,
|
|
SNIが重要なのでちゃんとドメインで指定して下さい.
繋ぐ
Windowsの内蔵RDPクライアントで127.0.0.1:12345に接続するとリモートサーバに繋がります. さすがRDPだけあって,コピペできるしレスポンスもまあまあ良い感じ.
実験用プロキシサーバのログでも,きちんと443のみで通信している事が確認できます.
おわりに
無事,踏み台を利用する事でプロキシ環境下でもRDPする事ができました.
使用している主要ソフトウェアが2つとも中国で開発されているという所に,この分野では圧倒的な差をつけられている事を実感させられますね…
ちなみに,RDPをVNCに,GostをnoVNCに置き換えることでブラウザを使ったリモートVNCアクセスが可能になりますが,あまりにレスポンスがアレだった為ボツになりました.
⚠ファイアウォールは絶対有効にして下さい.⚠
一応bindが127.0.0.1のみとなっていますが,サーバには暗号化されていないポートが転送され,見えている状態です.
暗号化された通信以外を許可しないで下さい.