公開鍵認証方式でのssh接続・設定・トラブルシューティング法

技術者向けというより利用者向けの記事になります。ターゲットとして今までパスワード認証だったけど、これからセキュリティを考慮して公開鍵認証に切り替えるよ、でも切り替えに必要な作業は個人で行ってねと言われて途方に暮れている人向けです。
急ぎの方は、

* [秘密鍵と公開鍵の生成](#秘密鍵と公開鍵の生成)
* [秘密鍵の登録](#秘密鍵の登録)
* [公開鍵の登録](#公開鍵の登録)
* [動作確認](#動作確認)

を読んで、実行してもらえれば大丈夫です。

# 公開鍵認証方式
sshの認証方式としてはよく使われるパスワード認証の他に公開鍵認証というものがあります。
公開鍵方式では「公開鍵」と「秘密鍵」の2種類の鍵を使って認証を行います。この2つの鍵は基本的にファイル（実体としてはただのテキスト）として扱われます。sshの場合はパスワードの代わりに秘密鍵を用いる感覚（場合によってはもっとお手軽な感覚）で使うことができます。もちろん、パスワードと同じように秘密鍵は厳重に管理する必要があります。
パスワード認証に比べたメリットとして、弱いパスワード（例えば誕生日や電話番号単体）のようなものが存在しないという点があげられます。つまり、利用者のセキュリティ意識が薄弱であったとしても一定程度のセキュリティを確保することができます。
逆にデメリットとして、秘密鍵はファイルとして残すことが前提となっているので、秘密鍵が漏洩するリスクがパスワードが漏洩するリスクに比べて高いという点があります。しかし、このデメリットは利用者の工夫によって打ち消すことができます。
その方法が、秘密鍵自体にパスワードを設定するというものです。つまり、秘密鍵を使用するためにはパスワードを入力する必要があるように設定します。これはいわば従来のパスワード認証と公開鍵認証の良いとこ取りをしたような形になりますので、ここではこの方式の設定方法を紹介していきます。

## よくある誤解
ログイン先ごとに秘密鍵を作らなければいけないと考えている人がいるかもしれませんが、実際はそんなことはありません。言うならば、秘密鍵は鍵で、公開鍵は錠前（鍵穴）です。そして、秘密鍵も公開鍵もファイルなのでコピーすることが出来ます。つまり、錠前（公開鍵）をいくらでも複製することができます。実際の作業では、いろいろな接続先に同じ公開鍵を登録（配置）していくことが、錠前の複製に対応しています。これによって、一つの秘密鍵を使って、公開鍵を登録したすべてのリモートホストに接続することが出来るようになります。
秘密鍵はこれら公開鍵を登録した場所にログインすることができる言わばマスターキーです。ならば秘密鍵を厳重に保管する必要性は理解できると思いますし、秘密鍵にパスワードを設定する意義も理解できるかと思います。

# OpenSSHの公開鍵と秘密鍵
秘密鍵はログインする側のPCに置いておき、公開鍵はログインされる側のPCに置いておく形になります。ただし、秘密鍵と公開鍵は2つで1組なので、公開鍵認証を使用する際には、どちらかのPCで秘密鍵と公開鍵を一緒に生成し、もう片方のPCに一方の鍵を移すという作業をすることになります。
一般的なLinux環境ではOpenSSHがインストールされているので、この場合について解説していきます。
まず、公開鍵は ```~/.ssh/authorized_keys``` に書き込まれています。公開鍵は複数登録することができるので、 authorized_keys と複数形になっています。このファイルに1行に1つの公開鍵の情報が書き込まれています。現在登録されている公開鍵を確認するには、

```bash
cat ~/.ssh/authorized_keys
```

といったコマンドを利用しましょう。多くの端末では1行に1つの公開鍵の情報を表示しきれないので複数行にわたって表示されることに注意します。このコマンドを実行した結果、たとえば

```
cat: /home/username/.ssh/authorized_keys: そのようなファイルやディレクトリはありません
```

などと表示されれば、まだ公開鍵は登録されていないことになりますし、既に登録されていれば、

```
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgfXNBxYReEuP+Ki4A0DXx15kMDa83qkHy+o+EmUImrURQeiblCznrXpgH2HlYbwz3AzebUGyt7jOW0W+cZDzAaIPvqU47lIxHZgLPStvI5vEASjGwego5BknzTJE0z/XXO6iE5B9OoJAzKYihH1xsBbO/9W7ssNzXN31FSdrKuGj9PslSpamwfV517Za4vw3vvYJEGjSOosNx+JZlZblvnQVtM3Wd9ZstrSu0EbPriPCMi7ufszPtUl5MVDodHzVrbwh8vfzo34jzzJY2WdEQfwvU3bwkh+7jKH+YMv+o7lcT19/f4j0Q4hWQ8LLdiBz/qKBuPoll1QG2PfwOFg3 stonedot
```

と公開鍵の内容が表示されます。もちろん、人によってこのファイルの中身は異なっています。

対して秘密鍵は```~/.ssh/id_rsa```といったファイルに保存されています。このファイル名はどのような秘密鍵を使用するかによって、名前が変化するのですが、今回使用するRSA暗号を使用する場合はこのようなファイル名になります。現在使用している秘密鍵を確認するためには、

```bash
cat ~/.ssh/id_rsa
```

を実行してみます。

```
cat: /home/username/.ssh/id_rsa: そのようなファイルやディレクトリはありません
```

のような内容が表示されれば、あなたはまだ秘密鍵を持っていないことになります。対して、

```
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAw4H1zQcWEXhLj/iouANA18deZDA2vN6pB8vqPhJlCJq1EUHo
m5Qs5616YB9h5WG8M9wM3m1Bsre4zltFvnGQ8wGiD76lOO5SMR2YCz0rbyObxAEo
xsHoKOQZJ80yRNM/11zuohOQfTqCQMymIoR9cbAWzv/Vu7LDc1zd9RUnayrho/T7
JUqWpsH1ede2WuL8N772CRBo0jqLDcfiWZWW5b50FbTN1nfWbLa0rtBGz64jwjIu
7n7Mz7VJeTFQ6HR81a28IfL386N+I88yWNlnREH8L1N28JIfu4yh/mDL/qO5XE9f
f3+I9EOIVkPCy3Ygc/6igbj6JZdUBtj38DhYNwIDAQABAoIBAQCjKsuiGc/pNKSb
u8PUD6MGc3Xr1/FXH92ijCUrON7pl3SWupMPhVMU6EvB/W8OqcsQ3Q5AdJ7oMT0j
vDkxAEchCLPgwBPUt9IQ+8nxV1PwpZ9SrkUB3MONnREBjtftaQFXFFB1JC7q1PHw
ctwU4s5vG69tg0c2J7PHjDISYV1Mqj4VbVWwBjYGviCcqmkVJPkZaXKndh5enQUn
YxiZrIkCxaK5W44uAJ+syoBw/F0sZQcMjBMKGrZYUbrwp+pWzhNamIqwqFfrmGgJ
fH8w2chZWagV63Iovcs0YkhFiPvmlcKN2mGKh4mnU6DNiPUJjfAAtDJs13XM0Ofs
3BT2zDpBAoGBAPYiDhaeYU0KHgd3k8qh1DKrcXYQiT3w1kBs95ad5AQyRAsKleh3
4iUhdQDyVLN8Fr4fpou4Qf6S5mfsOb/7P43PxnuskAzJzN5e9UkCVU4PNgMuKjTU
+jZbjNnWOqUrQFZHdhqA9fYMPV1Pio4KTnvQeDvYqM7Wwhvkio5+aOyFAoGBAMtY
XHzSRDWE4cBtYGNk0cNNdf6ZkW/nXeiUt+ICI1A0egwwT1mMfvAZOODgZ+OQY5jG
cGF4TE4XoGYNKN1t5cS1fokXzSSCFzv5QCqAcq6EOuHna8tuJ/mdfisx/aGauoy9
K7j4gQRnAdL0QXNF6jqRdSmV4iOTGR6IggAQyfyLAoGBAMvjwAnqny2jUObcnngA
AHkM3ktwPVArPkBWQ+7n0mfLf+Qpm67cCGC7y2HCXHnmNCzAqUUamMiaxfSWkew/
5BDEamYut5FwZZ5byRL2tNWZ8iNGTb5AIxl+UzpspV4Hax9NyT8BTz7IOtkeN+ec
EBGuyrrAqm3VJyzV8BVEEATFAoGBAK6UXENmGt2ACnm07g4nntf4hxdhLTZQA5YN
KJpHj53qj+YrC9UsBEeKwASBZXBApOGjbRShvZFGQ5WaMr14/s2VrN9yqdNwRRZe
djKHOO6P5CXTE/8BwhxSlOHs935pY0Q1nXYfFFV9QlmlDxQysFg8TcS4RACa5/QI
6uO3hlLlAoGAZmLxYl3ydUazmRArAswtsdmm7sorq7nsW11sv39Eb2iMMJrDVuKM
lplpDSeq/MIIvlbHlLV+m8nKul5cGFRtLKyDLNzTAvnS4wKvZa44Fx26iWogs0f3
2LUKr/CTDLG6qnta4+kz/aQqcEUbHS8HeS6kYQZ8//jQIcn59XIBwbE=
-----END RSA PRIVATE KEY-----
```

のような内容が表示された場合はあなたは既に秘密鍵を持っていることになります。
**ここでは例示のためにあえて表示されるであろう内容を表示しています（この鍵は実際には使っていません）。この内容はパスワードと同じものと言えるので決して他の人に漏らさないでください。**
多くの場合、この秘密鍵に対応する公開鍵は ```~/.ssh/id_rsa.pub``` に保存されています。

```bash
cat ~/.ssh/id_rsa.pub
```

で存在するか確認しておきましょう

# 秘密鍵と公開鍵の生成
秘密鍵を持っていない人は、ここで秘密鍵と公開鍵を一緒に生成しましょう。もし、既に秘密鍵を持っていて公開鍵だけ分からないという状況であるならば、[秘密鍵から公開鍵を生成する方法](#秘密鍵から公開鍵を生成する方法)を参照してください。
後の説明を簡単にするために、以下の作業は**手元（接続元、ローカルホスト）**の端末で行ってください。
鍵の作り方自体はとても簡単で、以下のコマンドを実行します。

```bash
ssh-keygen
```

すると、


```
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):
```

と、どこに秘密鍵を保存するのか聞かれるのですが、デフォルトのままで問題ないのでそのままEnterキーを押します。そうすると、

```
Enter passphrase (empty for no passphrase):
```

と、秘密鍵に設定するパスワードを聞かれるので、パスワードを入力しましょう（sshで接続するときに必要になるので忘れないように！）。
よくあるように、パスワードの再入力を求められます。

```
Enter same passphrase again:
```

もしパスワードに問題がある場合は、

```
Saving key "/home/username/.ssh/id_rsa" failed: passphrase is too short (minimum five characters)
```

のように改善すべき点が表示されるので頑張って良いパスワードを考えなおしましょう。

```
Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:c3Lg0ZpoVvVS22SF5YLKzOi3UK+4eO/6awdPM4eWdsg username@host
The key's randomart image is:
+---[RSA 2048]----+
|          . . o+o|
|         o o *.. |
|        + o + o .|
|       + X o   . |
|      + S O. +   |
|     o . *..E o  |
|        o .*.=   |
|       ..+.oo    |
|      ..+BBo     |
+----[SHA256]-----+
```

のような表示がされれば成功です。保存場所を変更していなければ ```~/.ssh/id_rsa```に秘密鍵、```~/.ssh/id_rsa.pub``` に公開鍵が保存されます。

# 秘密鍵の登録
秘密鍵を登録する手順、注意する点、トラブルシューティング法を説明します。

## 秘密鍵の配置
秘密鍵の配置場所はRSA鍵の場合 ```~/.ssh/id_rsa``` になっています。実は ssh-keygen を実行して鍵の生成に成功している場合は既にこの場所に鍵が配置されているはずです。今までに何回か出てきた ```cat ~/.ssh/id_rsa``` コマンド等で確認してみてください。 

## 秘密鍵のパーミッションの問題
```ssh-keygen``` で自動生成した場合はこのセクションの内容は無視しても動くはずです。もし、何かしら問題が発生した場合はこのセクションの内容を読んでみてください。

```~/.ssh/id_rsa``` ファイルがグループやユーザーにアクセスできる状態になっている場合、sshで接続しようとすると以下のようなエラーメッセージが表示されます。

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0640 for '/home/username/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/home/username/.ssh/id_rsa": bad permissions
```

このような場合は以下のコマンドを実行すれば解決します。

```bash
chmod go-rwx ~/.ssh/id_rsa
```

これによって、 ```id_rsa``` は自分しか閲覧できなくなります（ただし、通常環境ではrootユーザーだと閲覧できてしまいます。これが秘密鍵にパスワードを設定するべき理由の一つです）。


# 公開鍵の登録
公開鍵を登録する手順、注意する点、トラブルシューティング法を説明します。

## 公開鍵の配置
公開鍵は接続先（ログイン先）――リモートホストと呼ばれたりします――の端末の ```~/.ssh/authorized_keys``` ファイルに ```id_rsa.pub``` の中身を追記することで実現できます。一番分かりやすい方法はコピーアンドペーストです。
ここでの説明は手元（接続元、ローカルホスト）での作業と、接続先（リモートホスト）での作業があるため、接続元でのプロンプトを```local:~$```、接続先でのプロンプトを```remote:~$```と表示することで区別することにします。
```id_rsa.pub```が手元（接続元）の端末にあるはずなので、```cat``` コマンドでこれを表示します。

```bash
local:~$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgfXNBxYReEuP+Ki4A0DXx15kMDa83qkHy+o+EmUImrURQeiblCznrXpgH2HlYbwz3AzebUGyt7jOW0W+cZDzAaIPvqU47lIxHZgLPStvI5vEASjGwego5BknzTJE0z/XXO6iE5B9OoJAzKYihH1xsBbO/9W7ssNzXN31FSdrKuGj9PslSpamwfV517Za4vw3vvYJEGjSOosNx+JZlZblvnQVtM3Wd9ZstrSu0EbPriPCMi7ufszPtUl5MVDodHzVrbwh8vfzo34jzzJY2WdEQfwvU3bwkh+7jKH+YMv+o7lcT19/f4j0Q4hWQ8LLdiBz/qKBuPoll1QG2PfwOFg3 stonedot
```

ここで表示された、ssh-rsa で始まる行をすべてコピーします。適当な場所に貼り付けて途中で改行が入っていたら改行を取り除いて、再度コピーしなおしてください。

次に接続先のPCにsshでログインして、```id_rsa.pub``` の内容を ```rsa_pub_key``` に貼り付けます。

```bash
local:~$ ssh username@servername
username@servername password: 
remote:~$ mkdir ~/.ssh
remote:~$ chmod go-rwx ~/.ssh
remote:~$ echo "ここにコピーしていた内容を貼り付け" > ~/.ssh/rsa_pub_key
```

以上のコマンドで、ローカルにある ```id_rsa.pub``` と同じファイルを接続先に作ることができます（ファイル名は```rsa_pub_key```に変更しています）。usernameの部分を接続先PCのユーザー名に、servernameを接続先サーバーのドメイン名（ホスト名）やIPアドレスに、「ここにコピーしていた内容を貼り付け」の部分をコピーしておいた内容に置き換えるように注意してください。

ファイルのコピー操作はscpコマンドを使っても行うことが出来ます。上記の ```~/.ssh``` ディレクトリの作成とパーミッションの設定後、「[コピーアンドペーストがうまく行かない場合](#コピーアンドペーストがうまく行かない場合)」の内容を行うことで同様の事を行うことが出来ます。ただし、自分がどのホストの端末に居るのか注意して操作するようにして下さい。

最後に現在の ```~/.ssh/rsa_pub_key``` の内容を ```authorized_keys``` に追記して完了です。以下のコマンドを**接続先環境**で実行してください。">>"が追記を意味しています。間違って複数回実行しても大丈夫なように、```uniq```コマンドを使用しています。これは重複行を取り除く効果があります。

```bash
cat ~/.ssh/rsa_pub_key >> ~/.ssh/authorized_keys
uniq ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.uniq
mv ~/.ssh/authorized_keys.uniq ~/.ssh/authorized_keys
chmod go-rwx ~/.ssh/authorized_keys
```

### コピーアンドペーストがうまく行かない場合
scpを使ってコピーする方法もあります（既に慣れていればこちらのほうが分かりやすいかもしれません）。scpコマンドではリモート環境への接続にsshを使っているので、接続時のパスワードや接続情報は完全にsshと同じです。コピーコマンドと同じように、最初にコピー元のファイルを指定し、次にコピー先の場所を指定します。

以下のコマンドを**手元のPC（ローカル環境）**で実行すると ```~/.ssh/rsa_pub_key``` にファイルがコピーされます。

```bash
scp ~/.ssh/id_rsa.pub username@servername:~/.ssh/rsa_pub_key
```

usernameを接続先のユーザー名、servernameを接続先のドメイン名（ホスト名）やIPアドレスに変更するのを忘れないでください。

## 公開鍵の各種パーミッションの問題
各ディレクトリ、ファイルに適切なパーミッションを設定していない場合、公開暗号認証でのログインができなくなってしまいます。これらを一気に解消するコマンドは以下のとおりです。これを公開鍵を設置する**ログイン先の環境**で実行してください。

```bash
chmod go-w ~
chmod go-w ~/.ssh
chmod go-w ~/.ssh/authorized_keys
```

もし、各コマンドが使用される意味を知りたい場合は以下のサブセクションを確認してください。

### ホームディレクトリのパーミッション
ホームディレクトリが、グループや他のユーザーに対して書き込みを許している場合sshでのログインができなくなります。
具体的には、

```bash
ls -la ~ | grep " \.$"
```

で表示される内容が、

```
drwxrwxr-x    5 username users    4096 10月  3 21:50 2016 .
```

の様に最初の部分(drwxrwxr-xの部分)で6文字目以降でwが表示されている場合が該当します。この場合は以下のコマンドを実行します。

```bash
chmod go-w ~
```

再度権限を確認するために以下のコマンドを実行し、

```bash
ls -la ~ | grep " \.$"
```

以下のように6文字目以降にwが現れていなければ成功です。

```
drwxr-xr-x    5 username users    4096 10月  3 21:50 2016 .
```

### .ssh ディレクトリのパーミッション
```~/.ssh/``` にグループや他のユーザーに対して書き込み権限を与えている場合、公開暗号認証でのログインができなくなります。

```bash
ls -la ~ | grep "\.ssh"
```

上記のコマンドを実行した際に、

```
drwxrwxr-x    5 username users    4096  9月 28 17:25 2016 .ssh
```

のようになっている場合が問題です。これを解消するコマンドは以下のとおりです。

```bash
chmod go-w ~/.ssh
```

### authorized_keys のパーミッション
```~/.ssh/authorized_keys``` にグループや他のユーザーに対して書き込み権限を与えている場合、公開暗号認証でのログインができなくなります。

```bash
ls -la ~/.ssh | grep "authorized_keys"
```

上記のコマンドを実行した際に、

```
drwxrwxr-x    5 username users    4096  9月 28 17:25 2016 authorized_keys
```

のようになっている場合が問題です。これを解消するコマンドは以下のとおりです。

```bash
chmod go-w ~/.ssh/authorized_keys
```

# 動作確認
通常通りsshでリモートホストに接続してしましょう。秘密鍵のパスワードを入力してログインできれば成功です。もし、以下のようなプロンプトが表示され、リモートホストのログインパスワードでなければログイン出来ない場合はうまく設定されていない可能性もあります。

```
username@servername's password: 
```

ただし、ディストリビューションによってはローカルホストの ```id_rsa``` を使用するために再起動が必要な場合があるようです（Ubuntu 16.04でこの現象を確認）。上記のような表示が出て公開鍵で認証できない場合は、一度手元のPCを再起動させてみましょう。

もしそれでも解決しない場合は、[公開鍵のパーミッション](#公開鍵の各種パーミッションの問題)や[秘密鍵のパーミッション](#秘密鍵のパーミッションの問題)に問題があるかもしませんので、当記事の該当部分を参照してみてください。

# 付録
## 公開鍵の方式とbit長
公開鍵認証に用いる鍵にはbit長というものがあり、RSA鍵の場合デフォルトでは2048bitが使用されています。鍵長は長ければ長いほどセキュリティが高まりますが、一般に2048bitでも十分な鍵長と考えられています。もし望むのであれば ```-b 4096``` のようなオプションを追加することでより長い鍵長を指定することができます。
現在使っている鍵長や暗号方式は以下のコマンドで確認できます。

```bash
ssh-keygen -l
```

2048bit未満の鍵長が使われている場合は、新しい鍵を作り直すことを考えたほうが良いでしょう。

他にもDSA方式やECDSA方式を使うこともできます。DSA方式はssh-keygenが1024bitにしか対応していないため避けたほうが良いでしょう。ECDSA方式はセキュリティ的に問題はないため、意識高い事をアピールしたい人は使ってみてもいいでしょう。

* [GitHubユーザーのSSH鍵6万個を調べてみた - hnwの日記](http://d.hatena.ne.jp/hnw/20140705)

## 秘密鍵から公開鍵を生成する方法
もしかしたら、あなたが秘密鍵を持っているけどそれに対応する公開鍵を知らないということがあるかもしれません。そのような場合でも大丈夫です。以下のコマンドを使えば、秘密鍵に対応する公開鍵を生成することができます。

```bash
ssh-keygen -y -f rsa_filename
```

```rsa_filename``` を秘密鍵があるパスに書き換えてください。特に何もしていなければ ```~/.ssh/id_rsa``` です。これだけだと、標準出力に公開鍵の内容が表示されるだけなので、

```bash
ssh-keygen -y -f rsa_filename > ~/.ssh/id_rsa.pub
```

のようにリダイレクトを使ってファイルに保存しておくと後々便利でしょう。ただし、既存ファイルの上書きに注意してください。

## puttyで生成した秘密鍵の利用
やり方あったはずだったけど忘れてしまった。あとで調べて書く。