素の Windows PC から、bat ファイル一つだけで 組織ネットワークに安全に遠隔接続させるには (TUN/TAP デバイス未使用で、OpenSSH で 簡易VPN)

# はじめに
　最近のインターネットでは、**VPN の脆弱性を狙った攻撃**や **パスワード推測攻撃**が続発しており、便利さと裏腹に、危険性も増してきています。
特に、<INS>明確な組織にて 維持・管理されていない VPNサーバーは、非常に危険である</INS>と思います。

今回の手順は、**SSHサーバー側 root権限不要**で、TUN/TAPデバイスを使うこともなく **Windows クライアントPC にインストールされた OpenSSH のポートフォワーディング機能だけを使って、簡易VPN を実現**しています。(<INS>VPNサーバー無しで、VPN 的な事を行える</INS>)

この手順では、接続元PC は **SSHサーバーから直接アクセス可能な「組織内サーバー・NAS 等」にのみアクセス可能**であり、かつ、**TCP しか転送できない**事もあって、<INS>「ID・パスワードのみに頼った VPN」≒ **「多要素認証(MFA)が設定されていない VPN」よりも安全性は高い**</INS>と思われます。
また、**SSH秘密鍵は 接続元(組織外)PC 内にしか無い**わけですが、何らかの理由によって仮に秘密鍵が漏洩する事も想定して、<INS>ssh キーペア作成時にパスフレーズを設定しておけば、**更に安全性が上がる**と思います。</INS>

**SSHサーバー側に脆弱性が無い場合において**、通常の方法で組織ネットワークに接続する為には、<INS>**SSH秘密鍵**に加えて</INS> **接続先 SSHサーバーアドレス**と**SSHユーザー**、**パスフレーズ**も知らなければならない為、容易には組織ネットワークに接続できないと思われる為です。(SSHサーバーアドレスは、スキャンされて既にバレている可能性があります)
<INS>因みに、**接続先 SSHサーバーアドレス**と**SSHユーザー**は、**batファイル内に記述**されていますので、**このbatファイル自体も 漏洩しない工夫や意識が必要**です。</INS>

<INS>**処理概要が理解できる人のみ、使用してください。**</INS>


# 前提条件
・遠隔操作したい組織内サーバー・NAS 等と 通信可能な「**外部公開 SSHサーバー**」があり、インターネット側から一般ユーザーでログインできる事。(**root権限不要**)
・Windows 10 以降の PC に Windows標準の OpenSSH を事前にインストールしておき、かつ、該当 PC に **接続用 batファイル**を設置・チューニングしておく事。
・遠隔利用できるのは、RDC、Windows共有フォルダ機能 (NAS 等)、組織内Webサイトなど、**TCP プロトコルで利用できるもの のみ** 。

![Screenshot 2024-07-07 01.39.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273671/f83199cc-44a4-4bb2-948b-00623596cd09.png)

# batファイル 処理概要
１、接続元PC 実行ユーザーの **ssh公開鍵が Windows上に既に存在するか確認**し、無ければ ED25519キーの作成プロセスに入る。
　キーペア作成後は画面に ssh公開鍵が表示されるので、それを管理者に**何らかの安全な手段で渡し、「外部公開 SSHサーバー」接続ユーザー ホームディレクトリの .ssh/authorized_keys** に登録する。または、自分で登録できるなら、登録しておく。
　元々、PC 内にキーが存在した場合も画面に ssh公開鍵が表示されるので、同様に SSHサーバーの .ssh/authorized_keys に登録しておく。
 <INS>**(この公開鍵登録作業は、初回一回目のみ 必須)**</INS>

２、ssh公開鍵の登録後、**Windows管理者権限で** batファイルを再実行する。
　この batファイルでは、**(NAS 等) Windows 共有フォルダ機能のために 445/tcp の開放が必須**となっており、その為 **LanmanServerサービス(表示名「Server」) の無効化と、PC再起動が必要**となっています。
　もし、**batファイル実行時に LanmanServerサービスが停止していれば、「外部公開 SSHサーバー」に接続可能**となり、TCPポートフォワーディングが機能することで **簡易VPN として利用**できるようになります。

　<INS>ただし LanmanServer が停止することにより、該当PC の **「フォルダ共有、及び、プリンター共有が出来なくなる」** 弊害があります。</INS>
　<INS>PC 自体のサーバー(共有)機能が使えなくなるわけですが、 **NAS等の共有フォルダを覗いたりといった、クライアント機能は問題なく使用可能**です。</INS>
　もし、該当PC のフォルダ共有やプリンター共有が必要になったら、そのタイミングでコントロールパネル等から **LanmanServer サービスを有効にすれば、元に戻ります**。

# 処理手順 (batファイル チューニング方法)
１、以下の batファイルを一読し、処理概要を理解した上で「組織外から遠隔接続に使用するPC」に コピー＆ペーストしておく。
　**特に、日本語コメントの箇所は、よく読んでください。**

```batch:SSH_SIMPLE_VPN_CONNECT.bat
@echo off

set FILENAME=%USERPROFILE%\.ssh\id_*.pub
set SERVICE_NAME=LanmanServer
set HOSTS_PATH=%SystemRoot%\System32\Drivers\etc\hosts

set SSH_USER=sshuser
set SSH_HOST=ssh.example.jp

set RDC_IP=192.168.1.10
set RDC_PORT=33389
set NAS_IP=192.168.1.11
set HTTP_IP=192.168.1.12

rem FW で外部からの接続をブロックする TCPポート
set "ports=3389 139 445 80 443"

if exist %FILENAME% (
   sc query "%SERVICE_NAME%" | find "RUNNING"
   if errorlevel 1 (
      echo "%SERVICE_NAME%" NOT RUNNING...
   ) else (
      echo "%SERVICE_NAME%" RUNNING...
      rem 445/tcp を解放する為、LanmanServer を一次的に無効にする。
      for /f "tokens=3 delims=: " %%i in ('sc qc %SERVICE_NAME% ^| findstr "START_TYPE"') do (
         if /I not "%%i"=="DISABLED" (
            sc config %SERVICE_NAME% start= disabled
            echo ! ! ! ! ! ! ! ! ! !
            echo ! ! ! Caution ! ! !
            echo ! ! ! ! ! ! ! ! ! !
            echo It must be run with Administrator privileges.
            echo If you are not running with Administrator authority and a command error is displayed,
            echo Close the window by pressing the Close button without pressing the Enter key, and reexecute the command with Administrator authority.
            echo ! ! ! ! ! ! ! ! ! !
            echo ! ! ! Caution ! ! !
            echo ! ! ! ! ! ! ! ! ! !
            echo Press Enter to reboot the Windows OS!
            echo Failure to save open data may result in data loss.
            echo Caution!
            pause
            shutdown /r /t 0 /f
            exit
         ) else (
            sc qc %SERVICE_NAME% ^| findstr "START_TYPE"
            echo The %SERVICE_NAME% service must be stopped!
            exit
         )
      )
   )

   rem 3389/tcp リモートデスクトップが上がっている場合は、停止する。
   netstat -an | find "LISTENING" | findstr /c:":3389" > nul
   if not errorlevel 1 (
      net stop "Remote Desktop Services UserMode Port Redirector"
      net stop "Remote Desktop Services"
   )

   rem hosts のバックアップを作った上で、サービス用のホスト名を追記する。
   if not exist "%HOSTS_PATH%.ssh_backup" (
      COPY /B /Y %HOSTS_PATH% %HOSTS_PATH%.ssh_backup
   )
   rem 下の "example.jp" "REMOTE_NAS" "REMOTE_RDC" を、自身が遠隔接続したい 内部ホスト名に変える。
   type %HOSTS_PATH% | findstr /V "example.jp" >%HOSTS_PATH%.ssh_new
   echo %HTTP_IP%          example.jp>>%HOSTS_PATH%.ssh_new
   echo %NAS_IP%          REMOTE_NAS>>%HOSTS_PATH%.ssh_new
   echo %RDC_IP%          REMOTE_RDC>>%HOSTS_PATH%.ssh_new
   move /Y %HOSTS_PATH%.ssh_new %HOSTS_PATH%

   rem サービス用の仮想NIC を作成する。
   echo EXIST!
   TYPE %FILENAME%
   netsh -c Interface ip set dnsservers name="Loopback Pseudo-Interface 1" dhcp
   netsh -c Interface ipv4 add address name="Loopback Pseudo-Interface 1" addr=%RDC_IP% mask=255.255.255.0
   netsh -c Interface ipv4 add address name="Loopback Pseudo-Interface 1" addr=%NAS_IP% mask=255.255.255.0
   netsh -c Interface ipv4 add address name="Loopback Pseudo-Interface 1" addr=%HTTP_IP% mask=255.255.255.0
   timeout /t 5 >nul
   netsh -c Interface ip show conf

   rem 外部接続されないように、一時的に提供サービスの TCPポートを接続禁止にする。
   setlocal enabledelayedexpansion
   for %%p in (%ports%) do (
      echo Creating rule to block TCP port %%p from external networks...
      netsh advfirewall firewall add rule name="Block TCP %%p External" dir=in action=block protocol=TCP localport=%%p remoteip=any profile=any description="Blocks incoming TCP traffic on port %%p from external networks"
   )
   endlocal

   rem ssh でポートフォワーディングする。初回接続時、known_hosts 登録の為、Y を返す必要あり。
   echo To terminate this process, please press the "Ctrl" and "C" keys on the keyboard simultaneously while this window is active.
   echo When the question "Terminate batch job (Y/N)", enter N.
   ssh -N -i %USERPROFILE%\.ssh\id_ed25519 -oExitOnForwardFailure=yes -oServerAliveInterval=60 -L %RDC_IP%:%RDC_PORT%:%RDC_IP%:3389 -L %NAS_IP%:445:%NAS_IP%:445 -L %HTTP_IP%:80:%HTTP_IP%:80 %SSH_USER%@%SSH_HOST%
rem   ssh -i %USERPROFILE%\.ssh\id_ed25519 -oExitOnForwardFailure=yes -oServerAliveInterval=60 -L %RDC_IP%:%RDC_PORT%:%RDC_IP%:3389 -L %NAS_IP%:445:%NAS_IP%:445 -L %HTTP_IP%:80:%HTTP_IP%:80 %SSH_USER%@%SSH_HOST%

   rem サービス終了したので、設定したフィルタルールを削除する。
   setlocal enabledelayedexpansion
   for %%p in (%ports%) do (
      echo Deleting rule to block TCP port %%p from external networks...
      netsh advfirewall firewall delete rule name="Block TCP %%p External"
   )
   endlocal

   rem サービス用の仮想NIC を削除する。
   netsh -c Interface ipv4 delete address name="Loopback Pseudo-Interface 1" addr=%RDC_IP%
   netsh -c Interface ipv4 delete address name="Loopback Pseudo-Interface 1" addr=%NAS_IP%
   netsh -c Interface ipv4 delete address name="Loopback Pseudo-Interface 1" addr=%HTTP_IP%

   rem hosts をバックアップから戻す。
   if exist "%HOSTS_PATH%.ssh_backup" (
      move /Y %HOSTS_PATH%.ssh_backup %HOSTS_PATH%
   )

rem   sc config %SERVICE_NAME% start= auto
   echo Thank you, you are ready to close this window!
   pause
   exit

) else (

   rem ssh のキーペアを作成する。作成後、画面表示された公開鍵を管理者に連絡し、サーバーに登録してもらう。これをやらないと接続できない。
   echo NOT EXIST!
   ssh-keygen -t ed25519
   echo ! ! ! ! ! ! ! ! ! !
   echo ! ! ! Caution ! ! !
   echo ! ! ! ! ! ! ! ! ! !
   echo Please contact your administrator with the string that appears here.
   TYPE %FILENAME%
   pause
   exit

)
```

２、batファイル前半の以下の部分は、**最低限 自身の環境に合わせて 必ず修正が必要**です。
　それ以外にも batファイル中程の、hosts への追記の箇所も、必要に応じてホスト名を変更してください。
<pre>
set SSH_USER=ssh_user
set SSH_HOST=ssh.example.jp

set RDC_IP=192.168.1.10
set RDC_PORT=33389
set NAS_IP=192.168.1.11
set HTTP_IP=192.168.1.12

rem FW で外部からの接続をブロックする TCPポート
set "ports=3389 139 445 80 443"
</pre>

| 　変数名    |                   設定値の意味                   |
|:-----------|:----------------------------------------------:|
| SSH_USER   | sshサーバー側の接続ユーザーID                      |
| SSH_HOST   | sshサーバーのホスト名、又は、IPアドレス             |
| RDC_IP     | リモートデスクトップ接続先の IPアドレス              |
| RDC_PORT   | RDCクライアントでの接続ポート番号(**3389番から変更必要**)|
| NAS_IP     | NAS、又は、Windowsファイルサーバーの IPアドレス     |
| HTTP_IP    | 組織内 Webサーバーの IPアドレス                    |
| ports      | Windows FW で遠隔からの接続をブロックする TCPポート番号|

３、**修正した batファイルを** 一般ユーザー権限で良いので、**ダブルクリック**してください。
　ここで、<INS>ssh 公開鍵が見つからなければ、sshキーペア作成のプロセスに進みます</INS>。

　キーペア作成処理では、**ssh 秘密鍵のファイル名を指定するプロンプト**が出ますので、特に特別な意図がなければ **デフォルトのまま、ENTER** を押してください。
　次に、<INS>ssh キーのパスフレーズの入力</INS> を求められるはずです。
　パスフレーズには、**自分が忘れない<INS>１０文字程度以上の英数字記号文字列</INS>を入力し、ENTER** を押してください。
　次に、<INS>パスフレーズの再入力</INS> を求められるはずなので、**<INS>再度 同じ文字列</INS>を入力し、ENTER** を押してください。

　すると sshキーペアが作成され、画面に作成した公開鍵が表示されますので、それを管理者に連絡するか、または、ご自身で、**「外部公開 SSHサーバー」接続ユーザーホームディレクトリの .ssh/authorized_keys** に登録してください。

４、ENTER を押すと batファイルのウィンドウが閉じると思いますので、もう一度、**今度は Windows管理者権限で batファイルを再実行**してください。　これにより、「外部公開 SSHサーバー」に ssh で接続できるようになります。

　**初回接続時のみ**、known_hosts に登録するか聞いてくるはずなので、**"yes"** と応答する。
　正常に SSH接続できた場合には、何もエラーが表示されないはずなので、**そうなれば、通常通りに Webブラウザや Windowsエクスプローラ等で アクセス可能になっているはず。**
　<INS>RDC に関してだけは、ホスト名でアクセスでは無く「**RDCホスト名:RDCポート番号**」を指定してアクセスしてください。</INS>
　
　
　利用を終了するには、**画面にメッセージ表示されているように**、<INS>コマンドプロンプトにて「**CTRL+C**」を押して SSHコマンドを終了させてください。</INS>