WSLからEC2にSSHしようとして「UNPROTECTED PRIVATE KEY FILE!」と言われた時

# はじめに

「WSLはWSL内だけで完結させるといいよ」というのが主旨です。

Vscodeでon the WSLの開発をしていると、警告画面で「プロジェクトディレクトリはWSL内に置いてください！」みたいなことを促されたりします。これはアクセス速度の問題ですが、SSHに関してもアクセス権限の問題で、WSL内で完結するのが良さそうです。

ただし、管理者権限やroot権限が上司にいただけない立場で仕事している場合の話です。

# 現象

WSL から AWS の EC2 インスタンスへSSH 接続するとき、Permission error になります。

```bash:wsl
The authenticity of host 'ec2-instance-name.region-name.compute.amazonaws.com (public-ip)' can't be established.
ECDSA key fingerprint is SHA256:???????????????????????????.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'ec2-instance-name.region-name.compute.amazonaws.com (public-ip)'  (ECDSA) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0555 for '????????.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "???????.pem": bad permissions
ubuntu@ec2-instance-name.region-name.compute.amazonaws.com: Permission denied (publickey).
```

この時、Windows 側から同じことをしてみると、

```posh:pwsh
he authenticity of host 'ec2-instance-name.region-name.compute.amazonaws.com (public-ip)' can't be established.
ECDSA key fingerprint is SHA256:???????????????????????????.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'ec2-instance-name.region-name.compute.amazonaws.com (public-ip)'  (ECDSA) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for '????????.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "???????.pem": bad permissions
ubuntu@ec2-instance-name.region-name.compute.amazonaws.com: Permission denied (publickey).
```

8行目が、Powershellだと、`Permissions for `で WSL だと`Permissions 0555 for `になっています。

# 状況

まずは大きく、

```
WARNING: UNPROTECTED PRIVATE KEY FILE!
```

と記載されていますので、「警告！保護されていない秘密鍵ファイル」というアラートが出ていることは分かります。


```
Permissions 0555 for '????????.pem' are too open.
```

次にこの部分ですが、カタカナを使わずに言うと、「許可が0555なのは、開放的すぎる」と言ってます。
何の許可かというと、ファイルのアクセスです。

この、`0555`という数字は`stat`コマンドなどで確認できます。

```bash:wsl
stat ????.pem -c '%a'
```

ここで、AWS のコンソールを確認すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134703/6accd7c1-577b-e3b3-cf71-b534e8a92952.png)

```bash:wsl
chmod 400 ???.pem
```

と書いてあります。

しかし、これを行っても、依然として同じエラーメッセージが出て、SSH接続はできません。

# 原因追及

なぜなのか確認してみましょう。`chmod 400 ???.pem`をした直後に`stat ???.pem -c '%a'`で確認すると、`555`になっていることが分かります。

恐らく、私と同じ状況にある人は、`???.pem`ファイルの置いてあるディレクトリが、WSLの`/mnt/`の下位ディレクトリに保管されているのではないでしょうか？

どういうことなのでしょう？これは、`???.pem`ファイルの保存ディレクトリがWindowsの管轄領域にあり、アクセス権限はWindowsでコントロールされているので、WSL側で自由に変更できないように制限がかけられているということです。

WSL側でファイルパーミッションを書き換えた後にWindows側が自動修復するのか、そもそも書き換える直前にWindows側でコマンドを変更されるのかは分かりませんが、`chmod`コマンドをひたすら試しても意味のないことが分かります。

# 解決方法

解決方法は３つあります。

１つは、WSL側が管理しているディレクトリに`???.pem`ファイルを移動する方法です。
そして、もう１つは、諦めてWindows側でSSH接続する方法です。
最後の方法はroot権限でSSH接続する方法です。

~~先に伝えておくと、Windows側の方法を試しても、WSL側でSSH接続はできません。~~

## WSL側で完結させる方法

まず、最初の方法は簡単で、単純に`cp`コマンドで移動させてから、`chmod`でファイルパーミッションを変更するだけです。

例えば、`???.pem`ファイルが置いてあるディレクトリに移動したとして、

```bash:wsl
cp ./???.pem ~/???.pem
```

とすると、WSLのホームディレクトリに秘密鍵ファイルがコピーされます。このまま、移動先の秘密鍵のファイルパーミッションを変更します。

```bash:wsl
chmod 400 ~/???.pem
```

一応ファイルパーミッションを変更できているのか確認しましょう。

```bash:wsl
stat ~/???.pem -c `%a`
```

とすると、`400`と出ました。完璧です。これでSSH接続できますね。

## Windows側で解決する方法

Windows側ではGUIでやることもできますが、
Powershellでの方法を紹介します。

簡単に言うと、システム権限をシステムから剝奪します。

```posh:pwsh
Copy-Item './???.pem'
Set-Location '~/Desktop'
New-Variable -Name Key -Value './???.pem'
Icacls $Key /c /t /Inheritance:d
Icacls $Key /c /t /Grant $( $env:UserName + ':F' )
Icacls $Key /c /t /Remove Administrator 'Authenticated Users' BUILTIN\Administrators BUILTIN Everyone System Users
Icacls $Key
Remove-Variable -Name Key
```


:::note info
上記のPowershellスクリプトの実行には管理者権限が必要です。
:::

:::note warn
秘密鍵ファイルがUSBメモリや外付けHDDなどのリムーバブルメディアに保管されていると上手くいきません。
:::

この時、`Icacls $Key`の部分で、ファイルパーミッションがどう設定されたのか確認できます。

```
.\???.pem PCNAME\USERNAME:(F)
```

のようになっていれば成功です。
ここで、すぐにWindows側でSSH接続を試すと接続できます。

しかし、このファイルは、WSL側から、`stat ./???.pem -c '%a'`で確認すると、`777`となっています。

~~このことから、Windows側に置いている秘密鍵ファイルを使って、WSL側からSSH接続をすることは非常に難しいと結論づけることが出来ます。~~

ここで、WSLにて、`sudo su`をしてから、`chmod 400 ./???.pem`すると、`stat ./???.pem -c '%a'`の結果は`555`になります。
その root 権限のまま SSH接続を試すと、接続することが出来ます。

ここで、「ん？」となるのではないでしょうか？そうです。実はWindows側であれこれする前から`555`なので、root 権限であれば始めからSSH接続できたのです。

# 公式の記述

このことは、公式にも書かれてます。

https://docs.microsoft.com/ja-jp/windows/wsl/file-permissions

# ほかの方法

c ドライブなどのmount方法を変更することで、chmodの効力が変わるようですが、デフォルト設定を変更するのは避けたいところ。

https://yanor.net/wiki/?Windows/WSL/Windows%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AEchmod%E3%81%A8chown

https://yomon.hatenablog.com/entry/2020/04/wsl777_perm

https://sig9.hatenablog.com/entry/2020/02/19/000000

# まとめ

WSL側の領域に秘密鍵ファイルを保管するのが最も早そうです。

日常生活では、`777`というゾロ目は少しだけハッピーな気分にさせてくれます。
この状況では`777`という数字は見たくないですね。

みなさんの手元に`400`が出ることを願っています！