Visual Studio Code Remote Development を使って Windows7 から Ubuntu に SSH接続(公開鍵認証) してみた

#始めに
競技プログラミングが好きで、コンテストに参加しています。

仕事で従事する案件で、使用する言語が変わることが多い為
コンテストに参加する時の言語は、案件に合わせて意欲的に言語を学習しています。

言語が変わるたびに、その言語での実行環境の準備であったり
コーディングに使用するエディタを変更する、デバッグの方法が変わるなど
苦労することが多いです。

2019年5月、Visual Studio Code の Remote Development 拡張機能が
利用可能になりました。

画期的な出来事で、以下のようなことが可能になりました。

・仮想マシン内に複数の言語の実行環境を構築する。(作業環境に影響が無い。)

・コーディングやデバッグは、あたかも仮想マシン内で行うように作業環境で行う。

・言語が変わっても、エディタ操作やデバッグ操作は Visual Studio Code で完結の為
　新たに覚える必要がない。

今回、作業端末から Visual Studio Code の Remote Development 拡張機能を使い
Ubuntu の 仮想マシンに対して 公開鍵認証 による SSH接続を行いました。

気付いたことをメモしていきます。

※2019年7月7日
当記事は、Remote Development(SSH) の接続方法に特化したものです。

実際のコーディングやデバッグについては、下記の記事を投稿しました。
もし良ければ参照下さい。

Visual Studio Code Remote Development(SSH) を使って C++、Java、Python を試してみた
https://qiita.com/ShinjiSHIBATA/items/fddda2a101cc7f309cce

#環境
##Windows
Panasonic Let's note CF-SX1GEPDR
Windows 7 Professional Service Pack 1
Intel Core i5-2540M CPU @ 2.60GHz
メモリー 8GB
64bit

##仮想マシン
Oracle VM VirtualBox バージョン 6.0.8 r130520 (Qt5.6.2)
Ubuntu 18.04.2 LTS (Bionic Beaver)

#1. 作業前の状態
・Windows7
　ホストOS。

・Ubuntu 18.04.2 LTS (Bionic Beaver)
　ホストOS上に、ゲストOSとして構築済みの状態。

・Open-SSH
　ホストOS上に、インストール前の状態。
　Windows 10 では、デフォルトでインストールされているが
　Windows 7 では、インストールされていない。

・Visual Studio Code 
　ホストOS上に、インストール前の状態。

・SSH接続、ネットワークアダプタ
　ゲストOS上に、作成前の状態。

・公開鍵 秘密鍵
　ホストOS上に、秘密鍵が無い状態。
　ゲストOS上に、公開鍵が無い状態。

#2. ゲストOS (Ubuntu 18.04.2 LTS) の ネットワーク を作成する
以下、Oracle VM VirtualBox のバージョンによって、メニューの場所などが異なる。

Oracle VM VirtualBox バージョン 6.0.8 で説明する。

Oracle VM VirtualBox マネージャを起動し、Ubuntu の 仮想マシンを選択する。

画面上部の 歯車マーク [設定] を選択する。

設定の子画面が起動する。

[一般] が初期表示される。

設定の子画面、左部の [ネットワーク] を選択する。

[アダプター1] タブを選択する。[割り当て] が NAT になっている、そのままにする。

[アダプター2] タブを選択する。

[割り当て] を ホストオンリーアダプター を選択する。

[高度] を選択する。

[MACアドレス] をハードコピーあるいは、テキストエディタにメモするなど記録する。

OKボタンを押し、設定の子画面を閉じる。

設定の子画面、左上部 [ファイル] メニュ から [ホストネットワークマネージャ] を選択する。

ホストネットワークマネージャの子画面が起動する。

[DHCP サーバー] 有効チェックボックスが チェックされている場合は チェックをはずす。

[アダプタ] タブ、ラジオボタン [アダプタを手動で設定] を選択する。

[IPv4 アドレス]、[IPv4 ネットマスク] をハードコピーあるいは、テキストエディタにメモするなど記録する。

閉じるボタンを押し、ホストネットワークマネージャの子画面を閉じる。

#3. ゲストOS の ネットワーク を設定する
以下、Ubuntu のバージョンによって、メニューの場所などが異なる。

Ubuntu 18.04.2 LTS で説明する。

Ubuntu に ログインする。

デスクトップ画面、右上部 System Menu をクリック、工具マークをクリック。

設定画面が表示される。

設定画面、左部の [ネットワーク] を選択する。

前述の [アダプタ1] と [アダプタ2] に該当するネットワークがあり
[アダプタ2] が 構成されていないネットワークとなっている。

構成されていないネットワークの歯車マークをクリック。

[詳細] タブに表示されている [ハードウェアアドレス] が
先に記録した [アダプタ2] の [MACアドレス] と一致していることを確認する。

[IPv4] タブ、IPv4 メソッド [手動] を選択する。

[アドレス] に 先に記録した [IPv4 アドレス] と 同一のネットワークで
これから使用するIPを入力する。

[アドレス] は [IPv4 アドレス] の最末尾の数字を +1 したものとした。

後の設定に使用する為、ハードコピーあるいは、テキストエディタにメモするなど記録する。

[ネットマスク] に 先に記録した [IPv4 ネットマスク] を入力する。

[ゲートウェイ] は 空欄のままとする。 

[DNS] に 先に記録した [IPv4 アドレス] を入力する。

適用ボタンを押す。

コマンドプロンプトのアイコンをクリック、端末を起動する。

コマンドプロンプト は、Ubuntu では 端末 (ターミナル) と呼ぶ。

下記を入力する。

```Bash:network_restart.sh
sudo service networking restart
exit
```

画面右上、電源マークをクリック、Ubuntu の 再起動を選択する。

#4. ゲストOS の ネットワーク を確認する
端末を起動する。

下記を入力する。

```Bash:confirm_route.sh
route
```

default _gateway が eth0 ( [アダプタ1] の ネットワーク) となっていること
eth1 ( [アダプタ2] の ネットワーク) も表示されていることを確認する。

default _gateway が 2つ以上ある場合は先述の設定を再確認する。

#5. ubuntu にて 公開鍵 秘密鍵 を作成する
端末を起動する。

カレントディレクトリは、ホームディレクトリ ( /home/<ユーザー名> ) となっている。

ここで、下記を実行する。

```Bash:key_genarate.sh
pwd
ssh-keygen -t rsa
```

鍵の保存先をプロンプトで聞いてくるが、入力せずそのまま Enterキーを押す。

次にパスフレーズをプロンプトで聞いてくるので、パスフレーズを入力する。

パスフレーズはOSのパスワードとは別のものとし
10～30文字程度、半角大文字小文字、数字、記号を混ぜると良い。

成功すると /home/<ユーザー名>/.ssh のフォルダが作成され、鍵が作られる。

```Bash:permission_check_authorized_keys.sh
cd .ssh
pwd
ls -al
cat id_rsa.pub >> authorized_keys
chmod 600 authorized_keys
ls -al
rm id_rsa.pub
ls -al
```

上記では 公開鍵 (id_rsa.pub) を authorized_keys というファイルに追記する。
authorized_keys の権限を「-rw-------」(chmod 600相当) にする。
公開鍵 (id_rsa.pub) の追記が終わったら、削除する。

秘密鍵 (id_rsa) を何らかの方法で
ホストOS の C:\Users\<ユーザー名>\.ssh というフォルダに移動する。
Tera Term を使って ftp でも良し、cat コマンドで内容を表示し貼り付けでも良い。

移動が終わったら、元のファイルを rm id_rsa で削除する。

```Bash:permission_check_ssh_folder.sh
cd ../
pwd
ls -al
```

ここで /home/<ユーザー名>/.ssh のフォルダの権限が「drwx------」(chmod 700相当) に
なっているはずであり、なっていなければ chmod 700 <フォルダ名> する。

```Bash:permission_check_user_folder.sh
cd ../
pwd
ls -al
```

ここで /home/<ユーザー名> のフォルダの権限は「drwx------」(chmod 700相当) に
なっているか確認し、なっていなければ chmod 700  <フォルダ名> しておく。

#6. インストール一覧
以降の作業で、ホストOS (Windows7) にインストールする対象の一覧です。

|No.|インストール対象|バージョン|ダウンロードファイル名|取得元URL|
|:---|:---|:---|:---|:---|
|1|OpenSSH-Win64|v7.9.0.0p1-Beta|OpenSSH-Win64.zip|https://github.com/PowerShell/Win32-OpenSSH/releases|
|2|Visual Studio Code|May 2019 (version 1.35.1)|VSCodeSetup-x64-1.35.1.exe|https://code.visualstudio.com/updates/v1_35|

#7. OpenSSH-Win64 (インストール一覧 No.1)
ダウンロードファイルを解凍して、フォルダごと C:\Program Files に移動する。

コマンドプロンプトを右クリック、「管理者として実行」で起動する。

```DOS:install_openSSH.bat
cd C:\Program Files\OpenSSH-Win64

powershell -ExecutionPolicy Bypass -File install-sshd.ps1
```

エクスプローラ、[コンピューター] で右クリックして、[プロパティ] を選択する。

システムの画面が起動する。

[システムの詳細設定] をクリックする。

[環境変数]、[システム環境変数]、変数名 Path の末尾に
;C:\Program Files\OpenSSH-Win64 を追記する。

他のパスとの仕切りでセミコロンを入れている。

PCを再起動する。

コマンドプロンプトを右クリック、「管理者として実行」で起動する。

```DOS:automatic_ssh-agent.bat
powershell Set-Service ssh-agent -StartupType Automatic
powershell Start-Service ssh-agent
powershell Get-Service ssh-agent
```

ssh-agent が ステータス Running となっていることが確認できる。

コマンドプロンプトを右クリック、「管理者として実行」で起動する。

```DOS:automatic_ssh-agent.bat
ssh-add %USERPROFILE%\.ssh\id_rsa
```

上記により、秘密鍵 (id_rsa) を ssh-client に追加する。

パスフレーズをプロンプトで聞いてくるので、パスフレーズを入力する。

最後 Identity added と表示されれば成功となる。

#8. Visual Studio Code (インストール一覧 No.2)
ダウンロードファイルの .exe ファイルをダブルクリックする。

インストールが完了すると、英語の Visual Studio Code の画面が表示される。

Visual Studio Code 画面左部の黒いアクティビティーバーから上から5つ目あたりの
四角に穴があいたような Extentionsボタン (Ctrl + Shift + X) を押す。

Visual Studio Code 画面、左上部「Search Extensions in Marketplace」
と書かれたテキストボックスに「Remote Development」と入力する。

一番目に表示された「Remote Development」の小さな Install 緑ボタンを押す。

Visual Studio Code 画面、左下部に表示される小さな >< ボタン
Open a remote window を押す。

Visual Studio Code 画面、中央上部に表示されるリストから
Remote-SSH:Open Configuration File...を選択する。

C:\ProgramData\ssh\ssh_configを選択する。

```text:ssh_config
Host <ゲストOS の ホスト名>
    Hostname <ゲストOS の IPアドレス>
    Port 22
    User <ユーザーID>
```

上記を入力し保存する。

ゲストOS の ホスト名は
ゲストOS の 端末 にて hostname と 入力すると表示される値とする。

Visual Studio Code 画面、左部の黒いアクティビティーバーから上から6つ目あたりの
モニターのような Remote-SSH ボタンを押す。

サイドバーの CONNECTIONS に、今入力したホスト名が表示される。

ホスト名の右の +マーク のような Connect to Host in New Window ボタンを押す。

<ゲストOS の ホスト名> has fingerprint と 表示され
Continue と Cancel が選択肢として表示されるので、「Continue」を選択する。

このメッセージを見るのは、これが最後となった。

Visual Studio Code 画面を全て閉じて、Windows7を再起動しても
+マークのような Connect to Host in New Window ボタン を押すだけで
確認無しでログインできるようになりました。

まれにログインに失敗するが、その場合は retry ボタンが表示されるので
retry ボタンを押し、再接続する。

接続が完了すると、Visual Studio Code 画面、左下部の >< ボタン に
ログインしている ゲストOS の ホスト名が表示される。

インストールや設定作業は、以上で終了となる。

#9. Visual Studio Code の設定をイチからやり直したい場合
通常は以下の 9-3 のみ実行で事足りる。
Visual Studio Code 本体を再インストールならば、9-1 から順に実行する。

##9-1. Visual Studio Code 本体をアンインストールする
コントロールパネルから Visual Studio Code を アンインストールする。

##9-2. 該当する環境変数を削除する
エクスプローラ、[コンピューター] で右クリックして、[プロパティ] を選択する。

システムの画面が起動する。

[システムの詳細設定] をクリックする。

[環境変数]、[システム環境変数]、変数名 Path の中にある
;C:\Program Files\Microsoft VS Code\bin を削除する。

他のパスとの仕切りでセミコロンを入れている。

PCを再起動する。

##9-3. Visual Studio Code ユーザー設定や拡張機能を削除する
ホストOS (Windows7) にて コマンドプロンプトを右クリック、「管理者として実行」で起動する。

```DOS:remove_vscode_setting.bat
REM C:\Users\<ユーザー名>\AppData\Roaming\Code
rd /s /q %APPDATA%\Code

REM C:\Users\<ユーザー名>
rd /s /q %USERPROFILE%\.vscode
```

ゲストOS (Ubuntu 18.04.2 LTS) にて、端末を起動する。

```Bash:remove_vscode_setting.sh
# .vscode 始まりのフォルダを削除
# /home/<ユーザー名>/.vscode-server や .vscode-cpptools など
rm -rf ~/.vscode*
```

上記により、ホストOS (Windows7) ならびに ゲストOS (Ubuntu 18.04.2 LTS) の
ディレクトリを削除すると、ユーザー設定や拡張機能は削除される。

#10. openSSH を アンインストールする場合
ホストOS (Windows7) にて コマンドプロンプトを右クリック、「管理者として実行」で起動する。

以下、「Program Files」などディレクトリ名に半角スペースが含まれる場合
rd コマンドについては C:\Program Files\OpenSSH-Win64\ を
半角ダブルクォーテーション(")で囲う。

```DOS:remove_openSSH.bat
cd C:\Program Files\OpenSSH-Win64\

powershell -ExecutionPolicy Bypass -File uninstall-sshd.ps1

cd ../

rd /s /q "C:\Program Files\OpenSSH-Win64\"
```

エクスプローラ、[コンピューター] で右クリックして、[プロパティ] を選択する。

システムの画面が起動する。

[システムの詳細設定] をクリックする。

[環境変数]、[システム環境変数]、変数名 Path の中にある
;C:\Program Files\OpenSSH-Win64 を削除する。

他のパスとの仕切りでセミコロンを入れている。

PCを再起動する。

#11. 要点について
![fig.1 SSH Files and Service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271734/a28ba12f-0165-be5f-8b2f-5c270d54964c.png "fig.1 SSH Files and Service.png")

公開鍵認証では、作成された秘密鍵 (id_rsa)、公開鍵 (id_rsa.pub → authorized_key) の
ペアが重要であって、その秘密鍵と公開鍵はどこで作成しても良い。

Tera Term にも GUI で作る機能があるので、Windows7 側で作成しても良かったが
今回は、Ubuntu 側でコマンドベースで作成することにトライしてみた。

見てきたとおり、秘密鍵があれば、容易にログインできてしまう為
秘密鍵と公開鍵の取り扱いには十分に注意する。

デスクトップなどには、作業の途中で一時的ではあっても置かない方が良い。

今回、役割で重要なのが、openSSH の ssh-agent である。

openSSH を インストール時に ssh-agent は Windows サービス として登録される。

Windows サービス として登録された時点では、ssh-agent は 停止している。

ssh-agent の 起動を ホストOS (Windows7) の起動時に自動起動とする。

ssh-agent の 最初の起動 は 手動でコマンドにより行う。

この ssh-agent のおかげで、一度 パスフレーズ を登録すれば
今後 パスフレーズ を プロンプトで聞かれなくなる。

設定ファイル、ssh_config の内容には IdentityFile という項目で
秘密鍵の場所を指定することも可能だが、ssh-agent がよろしくやってくれるので
指定しない。

公開鍵を格納するディレクトリについて、権限はハマりポイント。

/home/<ユーザー名> フォルダ、ならびに、/home/<ユーザー名>/.ssh フォルダ は
権限が chmod 700 相当、自分以外のユーザーに権限を与えてはいけない。

色々なことをしているなかで、過去に /home/<ユーザー名> フォルダに
chmod 777 にしていて、そのことを忘れていて、とてもハマった。

公開鍵の権限も注意が必要。

/home/<ユーザーID>/.ssh/authorized_key は、権限が chmod 600 相当
自分に対しても実行の権限を与えてはいけない。

#終わりに
Visual Studio Code では Remote Development を使って
Dockerコンテナ を 使うこともできるようです。

Dockerコンテナ自体 を 知らない為、機会があれば習得したいです。

また新たな知見を得たら、別の記事で書きたいと思います。