macからWindowsに公開鍵認証(RSA方式)でsshログインする話

タイトル通りのことをやろうとして約1日かかってしまったので備忘録として残します。SSH接続カンタンに見えてムズカシイ...

## 環境
<dl>
<dd>・macOS Montrey 12.2.1</dd>
<dd>・Windows 11 home 21H2</dd>
<dd>・OpenSSH (Windows)</dd>
<dd>・iTerm (mac)</dd>
<dd>・PowerShell (Windows)</dd>
</dl>

## ルーター側の設定
まずはルーターの設定です。使用するルーターによって設定画面が異なりますが、「ポート開放」あるいは「ポートフォワーディング」なる設定をする必要があります。
自分の例(Buffaloルーター)ですが、「セキュリティー」->「ポート変換」に移動して、
 
<dt>
<dd>・新規追加：任意の名前</dd>
<dd>・Internet側IPアドレス：エアステーション側のInternet側IPアドレス</dd>
<dd>・「プロトコル」->「TCP/UDP」：SSH(TCPポート:22)</dd>
<dd>・LAN側IPアドレス：Windowsに割り当てられたローカルIP</dd>
<dd>・LAN側ポートには何も記入しない</dd>
</dt>

を設定します。WindowsのローカルIPは
```powershell:powershell
ipconfig
```
で出力される`IPv4アドレス`という箇所で確認できます。

## OpenSSHクライアントのインストール
ここからWindowsの設定をしていきます。
~~Windowsをサーバー化するには「OpenSSHクライアント」のインストールが必要です。~~
Windowsをサーバー化するうえで、今回は「OpenSSHクライアント」を利用します。インストール済みかどうかは「設定」->「アプリ」->「オプション機能」で確認できます。
![設定 2022_03_09 6_28_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/2df8bee3-50f1-1da7-79d0-3ea103658b07.png)
ここにOpenSSHクライアントがなければ、オプション機能の一番上にある「オプション機能を追加する」の「機能を表示」ボタンをクリックすればインストールが可能な機能が表示されます。ここでOpenSSHを探してインストールしましょう。
![設定 2022_03_09 6_32_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/4202ee94-b611-2382-4d7a-4967761df712.png)

## OpenSSHの設定
まずは「Windowsツール」->「サービス」に移動。
![スクリーンショット 2022-03-09 065044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/20fb66f6-843c-701e-392e-fc30309e1eea.png)
![スクリーンショット 2022-03-09 065239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/d370cc26-128b-cd1a-5591-47b933199ce4.png)
「OpenSSH SSH Server」を開いて
![スクリーンショット 2022-03-09 065500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/5f48f637-ada7-5289-9cca-adbfdddf1199.png)
<dl>
<dd>・「サービスの種類」を「自動(遅延開始)」に変更</dd>
<dd>・「サービスの状態」の「開始」をクリック</dd>
</dl>

![スクリーンショット 2022-03-09 070154.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/e126123b-a3db-461d-e7bc-f2ce7ac44c67.png)

## サーバー側のSSH設定
まずはサーバー側(Windows)でSSHの設定を行っていきます。
PowerShellを管理者として起動します。
[参考 - 【Windows】PowerShellを管理者権限で起動するコマンド](https://bizlog.tech/powershell-admin-mode/)
```powershell: powershell
Start-Process PowerShell.exe -Verb runas
```

### 1. `.ssh`ディレクトリの作成
SSH接続には`.ssh`というディレクトリが必要ですので、ない場合は事前に作成しておきます。
`.ssh`ディレクトリは、自身のホームディレクトリ`C:\Users\<ユーザー名>`の直下に置くのが一般的かと思いますので、今回は以下の場所にあることを想定して進めていきます。
```
C:\Users\<ユーザー名>\.ssh
```
なお、`.ssh`がない場合は以下の2種類のコマンドを実行して作成します。
```powershell:powershell
New-Item "C:\Users\<ユーザー名>\.ssh" # .sshディレクトリ作成
icacls "C:\Users\<ユーザー名>\.ssh" /remove Everyone # 閲覧権限からEveryoneを削除(これをしないとSSH接続できない)
```

同様に、クライアント側(mac)にも`.ssh`ディレクトリを作成しておきます。クライアント側の`.ssh`の場所はどこでも大丈夫です。

### 2. サーバー側の`sshd_config`ファイルの書き換え
まずは`sshd_config`ファイルのあるディレクトリに移動します。
```powershell:powershell
Set-Location "C:\ProgramData\ssh"
```
そしてテキストエディタ(メモ帳など)で内容を編集します。書き換えるファイル名は`ssh_config`ではなく **`sshd_config`** なのでお間違えの無いよう。
```powershell:powershell
notepad ".\sshd_config"
```
ファイルが開けたら、その中の **`PubkeyAuthentication yes`** と **`Match User`** および **`AuthorizedKeysFile`** それぞれの行頭の`#`を削除します(コメントでない状態とします)。
`AuthorizedKeysFile`の箇所にはSSH接続時に使用する公開鍵のパスを記載します。デフォルトで`.ssh/authorized_keys`となっており、このままでも問題ありません（この設定の場合、後述する`authorized_keys`ファイルは`.ssh`ディレクトリ直下に置くことになります）。
![スクリーンショット 2022-03-12 152357.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/ca258f04-5f7f-de95-d005-fbd7196a28e5.png)
なお、最後の２行に
```
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
```
という記述がありますが、administratorsというGroupを使うことはないので、私は不具合のないようコメントアウトしました。

以上でサーバー側でのSSH設定は完了です。

## クライアント側(mac)でのSSH設定

### 1. macで公開鍵と秘密鍵を生成
macのコマンドプロンプトを開いて、`.ssh`ディレクトリをアクセス制限をかけつつ作成します。
```zsh:zsh
cd <.sshを格納したいディレクトリ>
mkdir .ssh
chmod 700 .ssh 　　　# .sshにはファイル所有者しかアクセスできないようにする
```
.sshに移動して公開鍵と秘密鍵を作成します。
```zsh:zsh
cd .ssh
ssh-keygen -t ed25519 # Ed25519というアルゴリズムで生成
```
最初に「どのディレクトリに作成するか」を聞かれます。何も入力せずにEnterを押せば質問文右の（）内のパスに鍵が作成され、任意のディレクトリ(絶対パス)を入力すればそこに作成されます。`id_ed25519`ファイルが秘密鍵、`id_ed25519.pub`ファイルが公開鍵です。

続いてパスフレーズの入力が求められます。パスフレーズを設定したくない場合はそのままEnter、入力すればパスフレーズが設定されます。以上で鍵の作成が完了します。

### 2. 公開鍵の中身をサーバーに登録

作成出来たら、以下コマンドにて公開鍵`id_rsa.pub`の中身をWindowsに登録します。
以下コマンド実行後，公開鍵の内容が自動的にWindows上に`authorized_keys`として登録されます．

```sh
ssh-copy-id -i <公開鍵のパス> <Windowsのユーザー名>@<WindowsのローカルIP>
# 例）ssh-copy-id -i ~/.ssh/id_ed25519.pub hoge@192.168.123.45
```

## 接続してみる
以上でSSH接続を行うための準備が完了です！試しに接続してみましょう。
クライアント側(mac)のコンソール上で.sshのあるディレクトリまで`cd`コマンドで移動したら、以下のコマンドを実行します。
```zsh:zsh
ssh -i .ssh/id_ed25519 <Windowsのユーザー名>@<WindowsのローカルIP>
```
これで無事接続出来たら
```
<Windowsのユーザー名>@<Windowsの名前>
```
上記のような表示に切り替わるはずです。
ただし、サーバーのある場所をローカルIPで指定しているこの方法では、同じLANに接続していないとSSH接続できません。ので、次はWANから接続する方法を説明します。

<!--
## WAN(外部の環境)からSSH接続する方法（非推奨）
外部から任意のLAN内の機器にアクセスするには、その機器がもつ「グローバルIP」あるいは「グローバルIPに紐づいたホスト名(ドメイン)」を知る必要があります。

### ドメインの取得
「No‐IP」というサイトでドメインを取得します。
https://www.noip.com
私は無料版で利用しています。

ドメインが取得出来たら、「Dynamic Update Client for Windows」をサーバー側のWindowsにインストールします。このアプリは自動的にグローバルIPを取得し、指定したホスト名(ドメイン)に紐づけてくれるのですごく便利です。
ただし、無料版はおよそ1ヶ月毎にドメインの更新をする必要があるようなので、めんどくさければ有料版に切り替えるのもおすすめ。

### /etc/hostsの設定
こちらはクライアント側(mac)の操作になります。
まず、No-IPのダッシュボードから「Dynamic DNS」->「Personal Hostnames」にアクセスし、ドメインの右に表示されている「IP/URL」をコピー。
![Screen Shot 2022-04-12 at 16.56.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483756/08b55fd9-a7c1-e01e-9774-2b9e8f73f642.png)

その後、ターミナルから
```
$ sudo vim /etc/hosts
```
としてhostsファイルを編集します。

:::note warn
/etc/hosts は管理者権限(sudo)で開かないと編集できないため注意
:::

そこに先ほど取得したIPとドメインを入力します。
```
[IP] [ホスト名]
```
これで /etc/hosts の設定は完了です。


### ルーターの設定
続いてルーターで「ダイナミックDNS」を設定します。私の場合(Buffaloルーター)は「Internet」->「DDNS」に移動して、
<dt>
<dd>・ダイナミックDNS機能：No-IP</dd>
<dd>・Emailアドレスおよびパスワード：No-IPアカウントのもの</dd>
<dd>・ホスト名：取得したドメイン</dd>
</dt>
を入力して設定。
この際、IPアドレスの更新周期を設定できるようであれば長期間に設定しておくのがおすすめです。

以上で、外出先からでもWindowsに接続できるようになります！ -->

## SSH接続をより安全なものにする
ここまでくるとSSH接続ができる状態になっていると思いますが、セキュリティ面ではまだ不安が残っていることも事実です。
ここでは
- SSH接続は公開鍵認証のみ受け付ける(パスワードでのログインを許可しない)</dd>
- root(管理者)としてログインできないようにする</dd>
</dt>
といった設定を行います。

### `sshd_config`の設定
サーバー側(Windows)の`sshd_config`ファイルを修正するだけで安全な接続ができるようになります。
`sshd_config`は管理者権限でのみ変更が可能なので、まずはPowerShellを管理者として実行します。
実行出来たら`sshd_config`ファイルのあるディレクトリに移動
```powershell:powershell
Set-Location "C:\ProgramData\ssh"
```
メモ帳などのエディタで`sshd_config`を編集します。
```powershell:powershell
notepad sshd_config
```
ファイルが開いたら、以下の文を追加します。
```config
PubkeyAuthentication yes    # 公開鍵認証の許可 
PasswordAuthentication no   # パスワード認証を許可しない
PermitRootLogin no          # rootとしてのログインを禁止
```
保存したらsshdを再起動します。
```powershell:powershell
net stop sshd
net start sshd
```
これでより安全にSSH接続が行えるようになります！