2017年8月11日金曜日

次回予定

・Chromeブラウザでパスワード管理しないための設定
・パスワード管理ソフトKeePassの使用
・KeepassデータベースファイルをDropboxではなく自前のサーバーに置いてSFTP・公開鍵認証でアップロードダウンロード

SSHでトンネルを掘りVPS経由で実家のPCへVNC接続する(その2)

利便性だけを優先すれば、このような目的にはTeamviewerを使い、アカウントに二段階認証を設定すれば問題ないのかもしれない。だが、二段階認証を設定してないTeamviewerアカウントのパスワードリセットの手順があまりにも脆弱なこと、第三者に侵入される可能性のあるマネジメントコンソールの存在、アカウント情報の流出の懸念など、Teamviewer使うには多くの不安がある。
もちろん、自らバックドアを踏んでしまえは元も子もないが、それはWindows Firewallで対応するなど別の課題となる。今回は、パスワード管理もコネクションフローもすべて自分の管理下にあるより閉じた方法でリモートデスクトップ接続をおこなう方法を試す。
使うもの:
  Windows 10 Home 64bit デスクトップPC(こっち)
  Windows 10 Home 32bit タブレットPC(あっち)
  VPSサーバー CentOS 5.4 (sshdの公開鍵認証が有効になっていること)
  TigerVNC 1.8.0
  Open SSH Win 32/64

VPS=Virtual Private Server なので、「VPSサーバー」と書いたけれどもそれは冗長である。VPSとは要するにLinuxが動作する格安レンタルサーバーだ。具体的には「DTI SERVERSMAN@VPS エントリープラン」を使っている。こういった趣味の実験用途には打って付けのサービスで、格安のたった504円/月(税込み)で自分だけの固定グローバルIPアドレスとルート権限がもらえる。
VNCには色々なバージョンがあるが、本家RealVNCの最新バージョン6はTeamviewerのようにクラウドを使う仕組みのようなので除外する。今回TigerVNCを使っているが、UltraVNCでも構わない。UltraVNCの場合、Mirror Driverという専用のディスプレイドライバをインストールすることで描画の高速性が実現するというのだが、やってみたところ大差ないように感じ、ドライバも古臭くWindows10との相性が不安なため、それを使わないシンプルなTigerVNCを選択した。
WindowsでSSHトンネリングをする場合、クライアントソフトはPuTTYを使う場合が多いが、以下の問題により、今回はVNCサーバー側になるあっち側PCではOpen SSH Winを使う。PuTTYの問題点は以下のとおり。

・リモートデスクトップ上でトンネルを張っているPuTTYのウィンドウをドラッグしたり最小化するためにタイトルバーを左クリックすると、マウス左ボタンが押下状態のままリモート側に制御が奪われ、リモート側でマウス左ボタンを物理操作しない限りコントロールがロックされる。クライアントからVNCを切断してもリモート側は切断されず再接続が不可能になる。TigerVNCだけでなくUltraVNCサーバー・ビューワでも同様。コマンドプロンプトや他のプログラム、接続後に開いた別のPuTTYウィンドウに触れてもこの現象は発生しない)
・タスクスケジューラでシステム起動時にPuTTYを起動したときに、PuTTYプロセスは起動されるもののどうしてもトンネルが張れない。コマンドラインオプションがうまく渡されていないのかもしれない。

OpenSSH Winの場合、トンネルを起動しているウィンドウに触れてもPuTTYのようにハングアップすることはなく、また、タスクスケジューラでWindows起動時にスタートさせたときにはOpenSSHの実行ウィンドウ自体が非表示となり、ウィンドウに触れる心配がない。Windows UpdateでPCが勝手に再起動されてもリモート操作でWindowsへのログイン操作を可能にするため、システム起動時にトンネルを張って(掘って?)おく必要があるのだ。VNCクラアント側PCからのトンネル作成にPuTTYを使用することについてはとくに問題はないが、今回は両側ともOpen SSHというシンプルな方法にする。

TigerVNCの設置(あっち側PC)
ダウンロード
tigervnc-1.8.0.exe
tigervnc64-1.8.0.exe
環境に合わせていずれかのファイルをインストール。

Register VNC Serviceを実行(あっち側PC)
ユーザーがWindowsからログアウトしてもVNCサーバーが終了しないように、ユーザーモードではなくWindows起動時にTigerVNCサーバーをサービスで起動すように設定する。

Register VNC Serviceを実行

Configure VNC Serviceを開く(あっち側PC)


SecurityタブでVNCパスワードを設定する(あっち側PC)

SSHトンネリングで暗号化されるため、VNC間でSession encryptionをするのは冗長なのでNoneにする。

ConnectionタブでAccessControlを設定(あっち側PC)
トンネルからの接続だけを受け入れるように、"Only accept connections from the local machine"をチェックする。VNCサーバーの動作確認のために、同じLAN内の別のPCからトンネルを使わずに接続するには、ここにチェックを入れないか、チェックを入れない上に更にAddで192.168.0.0/8のようにローカルネットワークを追加する。運用時は上の状態にしておき、LAN内の別のPCから接続する場合もVPS経由のトンネルで接続するのが安全。

Desktopタブの設定(あっち側PC)
Remove wallpaperをチェックする。この設定は意外に重要で、VNCサーバーが着信しているときは一目でわかるように、デスクトップの壁紙が削除されるようにしておかなければならない。(ただしVNCではない別のバックドアで侵入された場合は無意味)
When last client disconnectsでVNC切断後の挙動を設定できるので、必要に応じて、Lock workstationやLogoff userを設定しておけばいい。今回の方法ならLoggoff userを行ってもリモートデスクトップ操作でWindowsにログインできる。

Start VNC Serviceを実行(あっち側PC)

ディスプレイのスケーリングが設定されている場合(あっち側PC)
今回VNCサーバー側になるタブレットPCは ASUS T100Chiという機種で、ディスプレイのサイズが10.1インチと小さい割に解像度が1,920×1,200ドット (WUXGA)と高く、デスクトップPCと同じ設定では文字が小さく扱い辛いので、デフォルトでは150%の拡大表示が設定されている。このままVNCサーバーを起動するとリモートデスクトップ時にマウスを動かしてもあっちのPCとカーソルが一致せず、ポイントする位置がずれる現象が起こる。解像度を落としてスケーリングを100%にすればマウスのズレはなくなるがそれでは高解像度ディスプレイの性能がもったいない。

スケーリング設定を変更せずにVNC接続時にマウスカーソルのズレを解決するには、エクスプローラーでVNCサーバー側PCの実行ファイル C:\Program Files\TigerVNC\winvnc4.exeを右クリックし、プロパティを変更する。互換性タブの「高いDPIスケールの動作を上書きします」のチェックを有効にし、拡大縮の実行元「アプリケーション」を選択して適用する。
これでOK。
備考:
TigerVNC Viewerはあっちの画面がこっちのよりもでかい場合、縮小スケーリング表示する機能がないため、あっちの画面がこっち側の画面からはみ出してしまい扱い辛くなる。Viewerについては互換性のある別のVNCクライアントを使う手もある。
また、Tiger VNC ViewerはX11サーバー相手の場合にウィンドウをリサイズするとリモート側のデスクトップサイズをダイナミックに変化させるする機能があるが、WindowsのVNCサーバーが相手の場合は機能しない。

OpenSSH Winを設置(ここではあっち側PCのみ。後程の手順でこっち側PCもおこなう)
ダウンロード
https://github.com/PowerShell/Win32-OpenSSH/releases
OpenSSH-Win32.zip
OpenSSH-Win64.zip
環境に合わせていずれかのファイルをダウンロード。インストーラーは無いので任意のフォルダに展開する。ここではC:\Users\Downloads\OpenSSH-Win32 に展開。

SSH接続用の公開鍵を作成する(ここではあっち側PCのみ。後程の手順でこっち側PCもおこなう)
鍵の作成にはOpenSSH-Win32 を展開したフォルダ内にあるssh-keygen.exeを使う。
元々サーバーへログインするために使っている鍵がpassphrase無しの場合は、新しい鍵やサーバ側に新しいユーザーを作成せずに、それをそのままトンネル用に使ってもいい。
元々サーバーへログインするために既に使っている鍵がこのフォルダーにある場合は、新しい鍵を上書きしてしまうとサーバーへログインできなくなり大変なことになる。既存の鍵をバックアップし、新しい鍵を作成する前にはPuTTYやTeratermなどであらかじめサーバーのコンソールへログインしておいた方がいい。
ssy-keygen.exeコマンドは、既存の鍵を上書きしないように、コマンドラインから-fオプションをつけて、作成される鍵のファイル名を指定して実行する。
例)C:\Users\Downloads\OpenSSH-Win32\ssh-keygen -f tunnel1_id_rsa
この場合、カレントディレクトリにtunnel1_id_rsaとtunnel1_id_rsa.pubが作成されるので、Windowsのユーザーフォルダー内の.sshフォルダ内へ2つのファイルをコピーする。
現在サーバーへの接続にパスワード認証だけを使っている場合には、新しく鍵を作成する。展開したフォルダ内のssh-keygen.exeをダブルクリックで実行れば、鍵のペアがWindowsのユーザーフォルダー内の.sshフォルダ内に作成されるのでこれを使う。

いずれの場合も、ssh-keygen実行時にpassphraseは無しに設定する。


ssh-keygen.exeを実行
(既存の鍵がない場合のみ)

エクスプローラーの表示オプションで隠しファイルを表示させる




id_rsa   が秘密鍵
id_rsa.pub が公開鍵
秘密鍵はサーバー側に登録する必要は無く、自分がサーバーに接続する際にSSHクライアントに読み込ませて使う。

トンネル専用ユーザーの作成(VPSサーバー)
普段サーバーで使っているユーザーでトンネルを張るのでも構わないが、サーバー側にトンネル専用ユーザーを作成しておいた方が良い気がする。
[root]$ useradd tunnel1
Pwassword:  これは公開鍵認証でログインする際のpassphraseとは別なので、ユーザーのパスワードを任意に指定する。別のユーザーでログインし、cu -コマンドでこのユーザーになるときにこのパスワードを使う。
シェルコマンドの実行ができないようにrbashが起動されるタイプのユーザーにすればより安心だが、サーバー側のsshd_configでpassword認証を禁止してしまえば、第三者が秘密鍵を持っていない限りSSHログインすることはほぼ不可能と考えられるので、rbashにする設定は必ずしも必要ないと思う。
備考:
PuTTYを使えばコマンドラインオプションにパスワード/パスフレーズを指定し、非対話でログインできるが、前述の事情により今回PuTTYが使えない。sshpassというプログラムを使えば、ユーザー名とパスワードまたはパスフレーズを指定して、一行でssh接続をすることができるが、これのWindows版を探してみたものの見つからなかった。

authorized_keysファイルへの追加(VPSサーバー)
id_rsa.pubはテキストファイルなので、id_rsa.pubファイルをメモ帳で開いてクリップボードにコピーし、VPSサーバー側の端末ウィンドウ内で開いたviエディタに張り付ける。
サーバーに自分のユーザー名または作成したトンネル専用ユーザーでログインし、

$ vi ~/.ssh/authorized_keys
~./.ssh/authorized_keys ファイルの最後にクリップボードにコピーしたものをペーストして追加する。
ファイルの最後にid_rsa.pubの内容をペーストしてセーブする。

トンネル専用のユーザーを今回作成したばかりの場合や、これまでパスワード認証だけを使っていたユーザーの場合は、~/.ssh/authorized_keys ファイルがないので作成し、パーミッションを644にする。

$ touch ~/.ssh/authorized_keys
$ chmod 644 ~/.ssh/authorized_keys 
$ls -la ~/.ssh/
drwx------ 2 user1 user1 4096 Aug  6 13:16 .
drwx------ 3 user1 user1 4096 Aug  5 23:48 ..
-rw-r--r-- 1 user1 user1  816 Aug  6 13:16 authorized_keys

後ほど、「こっち側PC」でも同様にssh-keygen.exeを使用して鍵を作成し、公開鍵の文字をこのファイルの最後にそれを追加する。

備考:
sshdで公開鍵認証を有効にするためには
 /etc/ssh/sshd_config の設定でPubkeyAuthentication yes になっている必要がある。
パスワード認証を禁止するために PasswordAuthentication no にするのが安全。

うまくログインできない場合は、/var/log/secure ファイルを確認する。
成功した場合:
Aug 12 11:10:52 myserver sshd[14223]: Connection from 202.101.103.114 port 51701
Aug 12 11:10:52 myserver sshd[14223]: Found matching RSA key: 86:3d:25:67:9f:4f:86:83:ec:cb:0b:8f:71:fa:aa:aa
Aug 12 11:10:52 myserver sshd[14224]: Postponed publickey for tunnel1 from 202.101.103.114 port 51701 ssh2
Aug 12 11:10:52 myserver sshd[14223]: Found matching RSA key: 86:3d:25:67:9f:4f:86:83:ec:cb:0b:8f:71:fa:aa:aa
Aug 12 11:10:52 myserver sshd[14223]: Accepted publickey for tunnel1 from 202.101.103.114 port 51701 ssh2
Aug 12 11:10:52 myserver sshd[14223]: pam_unix(sshd:session): session opened for user tunnel1 by (uid=0)

パスワード認証が無効なサーバーにパスワード認証でログインして失敗した場合:
Aug 12 11:12:01 myserver sshd[14228]: Connection from 202.101.103.114 port 51703
Aug 12 11:12:02 myserver sshd[14229]: Received disconnect from 202.101.103.114: 1: User Auth Failure


接続テスト (あっち側PC)
パスフレーズ無しでログインできれば成功。
C:\Users\ore\Downloads\OpenSSH-Win32\ssh.exe tunnel1@123.123.123.12 -p 22 -i C:\Users\ore\.ssh\tunnel1_id_rsa
Last login: Sun Aug  6 13:19:49 2017 from xxx.xxx.xxx.xxx
-rbash-3.2$

・-i オプションで、秘密鍵のファイル名をフルパスで指定する。
・-p オプションはサーバー側sshdのポート番号。SERVERS@MANの場合、sshは標準の 22ではなく3843になる。

トンネルを張るコマンドをテスト
C:\Users\ore\Downloads\OpenSSH-Win32\ssh.exe -N -R 6666:localhost:5900 tunnel1@123.123.123.12 -p 22 -i C:\Users\ore\.ssh\tunnel1_id_rsa
新しく黒いウィンドウが開いてそのままになればOK。切断するにはウィンドウ右上のバッテンをクリックする。
・-N オプションをつけることで、サーバー側のコマンドラインを表示しないようにする。(notty)
・-R 6666 サーバー内で中継に使用する任意のリッスンポート番号。使われていないポート番号を任意で決める。このポートはサーバー内部でループバック接続に使われるだけなので、ファイアーウォール(iptables)に外部からの接続ルールを追加する必要は無い。
・localhost このまま記入。
・5900 WindowsPC VNCサーバーのリッスンポート番号。5900はデフォルトの値で、VNC Server ConfigのConnectionタブで変更することができる。

トンネルを張るコマンドをタスクスケジューラーに登録(あっち側PC)
これはをやるのは後でも構わない。差し当たりコマンドプロンプトでトンネルを張るコマンドを手動で実行し、こっち側PCからVNC Viewerを使っての接続テストを先にやるのがいいかもしれない。

タスクスケジューラを起動する。

タスクスケジューラの右側ウィンドウ内のメニューで「タスクの作成」を選択。
タスクの名前は任意。ここではtunnel_vncという名前にしている。
「全般」タブの設定

「ユーザーがログオンしているかどうかにかかわらず実行する」を選択し、「最上位の特権で実行する」にチェックを入れる。Windows 10 Homeは、Windows Updateの際に強制的に再起動が実行されるため、VNCを使ってWindowsにユーザーがログイン(ログオン?)するにはこのようにしてシステム起動時にトンネルを張っておく必要がある。

「トリガー」タブの設定

ネットワークへの接続が完了していないと、トンネルを張るのに失敗してしまう。Wi-Fiの接続が完了し、DHCPサーバーからアドレスの取得が完了するまで少し時間がかかることを想定し、「遅延時間を指定する」にチェックを入れ、「30秒間」を指定する。もしインターネット接続やWi-Fi接続が切れた場合はプロセスが終了してしまうため、プロセスが自動的に再起動されるように「繰り返し間隔」に「30分間」にチェックを入れ、定期的にコマンドが実行されるように設定する。プロセスを重複起動しないための設定は、この後の「設定」タブでおこなう。

「操作」タブの設定
「プログラム/スクリプト」のボックスにSSHコマンドをフルパスで入力。
C:\Users\ore\Downloads\OpenSSH-Win32\ssh.exe
「引数の追加」のボックスにコマンドラインオプションを入力。
 -N -R 6666:localhost:5900 user1@123.123.123.12 -p 22 -i C:\Users\ore\.ssh\tunnel1_id_rsa

「条件」タブの設定
電源の項目は任意に設定する。今回はAC電源でもバッテリー動作時でも挙動を違わせる必要は無く、いずれの場合も実行して構わないと思う。
ネットワークの項目は、チェックを入れないことにした。システム起動時にネットワーク接続が完了していなければトリガー条件で設定した30分後に再度プロセスが起動される。

「設定」タブの設定

プロセスが重複起動されないように、一番下で「新しいインスタンスを開始しない」を選択する。
「タスクが失敗した場合の再起動の間隔」を指定することができるが、トリガータブの設定で30分毎に繰り返されるので、ここで設定すると冗長なためチェックをOFFにする。
全てのタブを設定し終えたら、PCを再起動し自動的にトンネルが張られているか確認する。スケジューラでssh.exeを起動すると、手動でテストした際のような黒いウィンドウは現れずにバックグラウンドでssh.exeが起動する。
Windowsにログインし、タスクマネージャーで「ssh.exe」が起動していることを確認する。
タスクマネージャーの表示



TigerVNC Viewerのインストール(こっち側PC)
ダウンロード
vncviewer-1.8.0.exe
vncviewer64-1.8.0.exe
環境に合わせていずれかのファイルをインストール。

OpenSSH Winを設置(こっち側PC)
ダウンロード
https://github.com/PowerShell/Win32-OpenSSH/releases
OpenSSH-Win32.zip
OpenSSH-Win64.zip
環境に合わせていずれかのファイルをダウンロード。インストーラーは無いので任意のフォルダに展開する。

SSH接続用の公開鍵を作成する(こっち側PC)
先にやった、あっち側PCでの作成手順と同じ。サーバーへログインするために既に公開鍵認証を使っている場合は既存のユーザーと鍵が使える。トンネル専用に新しいユーザーを作成する場合は、そのユーザー用に新たにssh-keygen.exeを使って接続用の鍵のペアを作成する。
あっち側PCではタスクスケジューラーにより非対話でSSHログインをおこなう必要があるため、Passphrase無しの鍵を使う必要があるが、こっち側PCでトンネルを張るのは手動操作なので、鍵はPassphrase付きのものでも構わない。

authorized_keysへの追加(VPSサーバー)
サーバーへログインするために既に公開鍵認証を使っている場合はこの手順は不要。
これまでパスワード認証だけを使っていた場合や、トンネル専用に新しいユーザーを作成した場合におこなう。
先にやった、あっち側PCの公開鍵を追加する手順と同じ。サーバー側で先ほどあっち側PCの公開鍵を追加したのと同じ~./.ssh/authorized_keysファイルの最後に、こっち側PCの公開鍵(.pub)の内容を追加してセーブする。

OpenSSH Winの起動(こっち側PC)
VNC Viewerで接続を開始する前に、こっち側PCからもサーバーにトンネルを張っておく必要がある。
コマンドプロンプトでSSHコマンドを実行する。

C:\Users\kotti\Downloads\OpenSSH-Win64\ssh.exe -N -L 7701:123.123.123.12:6666 tunnel1@123.123.123.12 -p 22 -i C:\Users\kotti\.ssh\tunnel1_id_rsa

・-N オプションをつけることで、サーバー側のコマンドラインを表示しないようにする。(notty)
・-L 7701 こっち側PCの内のポート番号を任意で決める。
・-i オプションで、秘密鍵のファイル名をフルパスで指定する。
・-p オプションはサーバー側sshdのポート番号。
サーバーのIPアドレスとポート番号、サーバーへログインするユーザー名は「あっち側PC」と同じ。
このコマンドはVNC Viewerで接続する前に毎回実行することになるので、バッチファイルにしてショートカットをTigerVNC Viewerアイコンの隣にでも置いておけばいい。

tunnel_client.bat
CD /C %~dp0
START /MIN C:\Users\kotti\Downloads\OpenSSH-Win64\ssh.exe -N -L 7701:123.123.123.12:6666 tunnel1@123.123.123.12 -p 22 -i C:\Users\kotti\.ssh\tunnel1_id_rsa

TigerVNC Viewerの起動
TigerVNC Viewerを起動する。

Real VNC 5.3.3のViewerも使える
ダウンロード
https://www.realvnc.com/download/file/vnc.files/VNC-5.3.3-Windows.zip
TigerVNCは縮小スケーリングができないが、Real VNCのViewerは可能なので、向こうの画面の方がでかいという今回場合はこちらの方が適している。
TigerVNC Serverへ接続する場合、Encryptionの互換性がないようでNoneにしかできないが、今回の環境の場合SSHトンネリングを使っているのでEncryptionの必要は無い。
Real VNCのインストールファイルにはVNC ServerとVNC Viewerの両方が含まれているが、インストール時にはVNC Viewerだけを選択し、VNC Serverのチェックボックスは外す。Real VNCのバージョン5.x.xはVNCサーバーを起動するためのトライアルライセンス配布が終了しており、VNCサーバーをインストールしても起動することができない。(VNC Connectライセンスなるものを購入すると5.x.xのライセンスをもらえるようだが)

TigerVNC Viewerで接続
接続先に「localhost:7701」を入力し、Connectボタンを押す。

VNC Authenticationのウィンドウがすぐに表示されれば接続は成功している。
あっち側PCのConfigure VNC Serverの手順で、Securityタブで設定したVNCパスワードを入力し、OKボタンを押す。
あっち側PCの起動時にトンネルを張るのが成功していれば、Windowsにログインしていない状態でも接続することができる。


 ログイン時はデスクトップの壁紙が削除される設定にしてある。

接続中は、F8 キーを押すとコンテキストメニューが表示され、特殊キーの送信などができる。

コンテキストメニューではIMEをON/OFFできるキーを送ることができず、日本語が入力できない。こちらのメモ帳に記入した日本語をコピーしてVNC Viewerウィンドウ内にペーストすると、???となり、クリップボード経由では送ることができないようだ。あっち側PC全角/半角キーを手動で押してIME ONの状態にしてやるとVNC Viewerから日本語入力ができるようになる。なので、あっち側PCのIMEのキー割り当てを変更しておけばVNC ViewerからIMEのON/OFF操作をすることができる。送れるキーは英語版キーボードに存在するキーだけだと思わるので、あまり使うことのないファンクションキーの一つを割り当てることにする。

IMEのキー割り当て追加(あっち側PC)
タスクトレイのIMEアイコンを右クリックしてプロパティを表示させる。
詳細設定を押す。

全般タブの「編集操作」の変更ボタンを押す。

キー設定タブを選択。
既存の「全角/半角」を選んでから「キー追加」ボタンを押すと、同じ機能をコピーして別のキーに割り当てることができる。

元々一体なんの機能があるのかわからない「F12」キーを割り当てることにする。

これでF12キーでIMEのON/OFFを切り替えることができるようになった。

「SSHでトンネルを掘りVPS経由で実家のPCへVNC接続する」は以上で終了です。