SSH接続のための認証方式について

# SSH接続のための認証方式について

VPSやAWSのEC2インスタンスには誰でもSSHログインできるわけではありません。
SSHを使ってサーバーに接続する場合、パスワード認証や鍵認証という方法でログインすることができます。

それぞれ、たとえを使って説明してみます。

## パスワード認証
あなたのローカルマシンを自宅とします。
サーバー機はあなたの会社です。
会社には警備員がいて、あなたが会社に入ろうとすると「合言葉は？」と聞かれます。
そこで、あなたは合言葉を答えて会社に入ります。
パスワードを知らない人は会社に入ることができません。
ところが、入り口でパスワードを答えている時、泥棒がすぐ横でパスワードを聞いていました。
なので、泥棒は警備員にパスワードを聞かれましたが、簡単に会社に侵入することができました。

これがパスワード認証です。
途中までは堅牢そうに見えましたが、簡単にパスワードを盗まれて会社への侵入を許してしまいました。
これでは危険なので、**鍵認証**という方式でログインさせることにしましょう。

## 鍵認証
鍵認証の場合は、こうです。
あなたは家で鍵と鍵穴シリンダーを作りました。
あなたは鍵穴シリンダーを会社の警備員に渡し、ドアに取り付けてもらいました。
なので、今後はあなたは会社に鍵を持っていき、その鍵を使って会社に入ることができます。
入り口で、あなたが鍵を使っって会社に入っていくのを見た泥棒は、鍵がないため会社に入ることはできませんでした。

そこで、泥棒は鍵を盗むことにしました。
どうにかしてあなたの鍵を盗むことに成功した泥棒は、その鍵を使って会社に侵入することに成功します。

途中までは堅牢そうに見えましたが、鍵を盗まれてしまうと会社への侵入を許してしまいます。
これでは危険なので、鍵は特定の所有者しか使えないように権限機能をつけることにしました。
さらに、家での鍵の保管庫も鍵自体もあなたしか見えません。
これだけの条件を備えた鍵でなければ、会社の鍵穴は受け付けません。

これで安全に会社に入ることができます。泥棒には、保管庫も、その保管庫の中にある鍵自体も見えません。
鍵を使おうにも、鍵の持ち主とDNA鑑定の結果、別人と判断されて鍵を使うこともできないのです。

これが鍵認証です。

## 鍵認証のやり方

それでは、実際にEC2に鍵認証でSSHログインしてみましょう。
ローカルマシンで`~/.ssh`に移動して`ssh-keygen`というコマンドで鍵と鍵穴シリンダーを作成します。

```
[your_local_pc]$ cd ~/.ssh
[your_local_pc]$ ssh-keygen -m pem ~/.ssh/testapp-ec2-user -C ""
```
すると、`testapp-ec2-user`と`testapp-ec2-user.pub`という2つのファイルが作成されます。
`testapp-ec2-user`が鍵で`testapp-ec2-user.pub`が鍵穴シリンダーです。
この鍵は絶対に削除してはいけませんし、どこ行ったかわからなくなるような場所に移動させるのもやめましょう。`find`コマンドで探すことはできますが、鍵の保管場所を決めてそこに保存するか、作成された時のまま`.ssh`の直下においておくのが安心です。

鍵穴のシリンダーは、後でEC2インスタンスを作成する際に登録することになります。

なお、AWSではなくて、普通のVPSのサーバーの場合とかだと、最初に作成されるルートユーザーで鍵穴シリンダーをサーバーに送って、サーバー側でドアに取り付ける、という作業を自分ですることになります。

### AWSじゃない場合

先程は`ec2-user`というユーザー名を鍵名に付けましたが、今回は(何でも良いのですが)`root`としましょう。
ローカルから以下のコマンドでサーバーに鍵穴シリンダーを持っていく。
鍵のパスなどは、自分の環境によって適宜読み変えてください。
```
$ scp ~/.ssh/testapp-root root@178.0.0.1:~/ -i ~/.ssh/testapp-root
```
これで`178.0.0.1`というIPアドレスを持つサーバーの`root`というユーザーのhomeディレクトリに`testapp-root`という鍵穴シリンダーを置いてこれました。
これだと鍵穴を持っていっただけなので、ドアに取り付ける作業が必要です。
シリンダーの取り付けは、会社の中から工事します。
```
$ ssh root@178.0.0.1
[root@178.0.0.1]$ mkdir ~/.ssh
[root@178.0.0.1]$ touch ~/.ssh/authorized_keys
[root@178.0.0.1]$ cat testapp-root >> ~/.ssh/authorized_keys
```
これでドアに鍵穴を取り付ける作業が完了です。
今度は鍵自身の権限です。
鍵の保管庫は本人にしか見えないし、鍵自身も本人にしか見えません。
さらに鍵を使えるのも本人のみです。
以上の条件をローカルの鍵に設定します。
```
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/testapp-root
```
これで`.ssh`ディレクトリはログイン中のユーザーのみがRead, Write, Executeできる権限を付与され、`testapp-root`鍵はログイン中のユーザーのみがRead, Writeできる権限を付与されたことになります。

ここまでやって初めて、安全にサーバーにSSH接続できるようになりました。

### AWSの場合

AWSの場合に戻りましょう。
EC2作成時に鍵穴シリンダーを登録できるので、ローカルで作成した鍵と鍵穴シリンダーの、鍵穴シリンダーの方を登録します。
`cat`コマンドでtestapp-ec2-user.pub`の中身を出力してそれをコピーし、キーペアの登録画面でペーストします。

鍵の権限については、VPSの場合と同じです。

```
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/testapp-ec2-user
```

## 踏み台サーバーへの鍵の持ち込みについて

さて、自宅から会社に入る仕組みはできました。
会社には社員しか入ることができません。
ところが、会社は世間一般にサービスを提供しているので、一般のお客さんも入れる入り口を用意しなければいけません。
お客さんは、その一般のお客様専用入り口から会社に入ってきて、応接室に通されます。
そこでサービスを受けるのです。

ところが実は、個人情報やその他の重要機密データは会社の社内のデータルームに置いています。
いくらお客様専用の入り口と応接室を用意しても、同じ建物の中にどこの馬の骨とも知らない一般人を招き入れるのは危険かもしれません。
そこで、データルームは会社敷地内の別の建物に移すことにしました。

すると、データルームの建物は外から丸見えなので、今度はデータルームに直接データを盗みに来る輩が現れました。
これは危険です。
そこで、データルームは、会社の地下に移設することにしました。
これだと、会社に入って、さらに地下室の鍵を使ってデータルームに入ることになります。
一件落着、と思ったのですが、地下室の鍵を社内に置いておいたので、鍵を盗まれてしまい、データルームへの侵入を許してしまいました。

鍵を会社に置いておくのはセキュリティ上の問題があるようです。
そこで、今度はデータルームのドアに、各社員が会社に入る時の鍵穴シリンダーをコピーして取り付け、各社員は自分の鍵を会社に持ち込んでデータルームにも同じ鍵で入れるようにしました。
ちょっと無理がある設定ですが、各社員の自宅と会社の間には専用の通路が用意されていて、普段は自宅に取り付けられた会社のドアを鍵を開け、鍵自体は家に置いておく、という設定にしましょう。
なので、普段は鍵は各社員の自宅に保管されていますが、データルームに入るために、その鍵を会社まで持ち込むこともできるのです。

たとえ話が長くなってしまいましたが、これが踏み台サーバーを使った鍵の持ち込み認証です。

まず、会社の建物は地上にあり、データルームは会社の建物からアクセスできる地下にあります。
これはパブリックなサブネットにあるサーバーからプライベートなサブネットにあるサーバーにアクセスできるようにすることを表しています。

パブリックなサブネットにあるサーバーにはローカルPCからsshでログインしましょう。

```
[your_local_pc]$ ssh -i ~/.ssh/testapp-ec2-user ec2-user@178.0.0.1
[ec2-user@178.0.0.1$
```

ここからプライペートサブネットにあるサーバーにSSH接続するのですが、先程の会社の例えのように、会社内に鍵を置くのは危険です。
つまり、パブリックサブネット内のサーバー内に、プライベートサブネット内のサーバーにSSHログインするための鍵を置くのは危険です。

今、ローカルPCからパブリックサブネット内にあるサーバーにSSHログインしていますが、鍵は持ち込んでいません。
一旦家に帰って（ログアウト）今度は会社に鍵を持ち込んだ状態で出社しましょう。
鍵を会社に持ち込むためには、その鍵を持ち出しして良いという許可が必要になります。
```
[your_local_pc]$ ssh-add ~/.ssh/testapp-ec2-user
```
では、今度こそ鍵を持ち込んで出社し直します。
```
[your_local_pc]$ ssh -i ~/.ssh/testapp-ec2-user ec2-user@178.0.0.1 -A
[ec2-user@178.0.0.1]$
```
`-A`というオプションをつけるだけです。
これで鍵を持ったまま会社（サーバー）に入ることができました。
ちゃんと鍵を持ってきているか確認してみましょう。
```
[ec2-user@178.0.0.1]$ ssh-add -l
3072 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxx testapp-ec2-user (RSA)
```
こんなふうに表示されたら鍵の持ち込みに成功しています。

では、この鍵を使ってデータルームのある地下室（プライベートサブネット内のサーバー）に入ります。
```
[ec2-user@178.0.0.1]$ ssh -A ec2-user@178.0.0.2 -i ~/.ssh/testapp-ec2-user
[ec2-user@178.0.0.2]$
```
初めてログインする時は確認ダイアログだ出ますので、`yes`と答えておきましょう。

### ホスト名をわかりやすい名前に変更する

さて、これで無事に`[ec2-user@178.0.0.1]`から`[ec2-user@178.0.0.2]`にログインできました。
あれ？どちらも`ec2-user`だしホスト名もIPアドレスで、これだとちょっとわかりにくくて今いるところがどこなのか間違えてしまいそうです。
それぞれ、わかりやすい名前に変更しましょう。
まずは、今はプライベートサブネットのEC2にいるので、そのホスト名を`testapp-db`に変更しましょう。
```
[ec2-user@178.0.0.2]$ sudo hostnamectl set-hostname testapp-db.localdomain
```
さらにこのホスト名を`/etc/hosts`に登録します。

```
[ec2-user@178.0.0.2]$ sudo vi /etc/hosts
```
```
127.0.0.1   testapp-db localhost localhost.localdomain localhost4 localhost4.localdomain4
```
先頭に`testapp-db `を追加します。
そしてログアウトして踏み台サーバーであるプライベートサブネットのEC2に戻ります。
```
[ec2-user@178.0.0.2]$ exit
[ec2-user@178.0.0.1]$
```
このサーバーのホスト名も変更します。
手順は同じです。
```
[ec2-user@178.0.0.1]$ sudo hostnamectl set-hostname testapp-app.localdomain
[ec2-user@178.0.0.1]$ sudo vi /etc/hosts
```
踏み台サーバーの方は`testapp-app`にしました。
```
127.0.0.1   testapp-app localhost localhost.localdomain localhost4 localhost4.localdomain4
```
`/etc/hosts`を編集したらこのサーバーからもログアウトして、AWSコンソールから両方のEC2を再起動します。
再起動が完了したらログインし直してみましょう。
```
[your_local_pc]$ ssh -A ec2-user@178.0.0.1 -i ~/.ssh/testapp-ec2-user
[ec2-user@testapp-app]$ ssh -A ec2-user@178.0.0.2
[ec2-user@testapp-db]$
```

はい、これでどこにいるのかわかりやすくなりました。

ここまでのおさらいです。

1. 自宅で鍵と鍵穴シリンダーを作る（`ssh-keygen`で秘密鍵と公開鍵を作成）
1. 鍵穴シリンダーをサーバーに登録（AWSの場合は`キーペア`の登録、VPSなどの場合は`scp`で送って`authorized_keys`に登録）
1. 鍵の権限と鍵の保管庫の権限を設定（秘密鍵は600、その鍵のある`.ssh`ディレクトリは700の権限を設定）
1. 出社時にデータルームの鍵も持っていく（`ssh-add`で持ち出し可能にして`ssh -A`オプションで鍵を持ち込んで踏み台サーバーにログイン）
1. 持ち込んだ鍵でデータルームに入室（踏み台サーバーから`ssh -A`でプライベートサーバーにログイン）
1. それぞれのサーバーにわかりやすいホスト名をつける

以上が鍵認証を使ったSSH接続の基本です。