ぼくのかんがえたさいきょうの SSH 公開鍵認証


# はじめに

SSH はシステム開発時にサーバにアクセスするための方法として一般的なものです。
しかしその標準的な認証方法である、 SSH 公開鍵認証について、あまり知られていないようなのでまとめました。

公開鍵認証は、パスワード認証よりも手軽で、安全な認証方式です。
本稿では SSH 公開鍵認証とはどのようなものか、 SSH 公開鍵認証の使い方、運用の流れとポイントについて説明します。
また、管理者向けに本稿で提案した運用方法の安全性について考察します。

ユーザとして SSH 公開鍵認証を利用する際に特に重要な点は、 SSH 公開鍵認証には公開鍵と秘密鍵の2つを使用し、公開鍵は誰に渡しても良いが、秘密鍵は誰にも渡してはいけない、他のコンピュータにコピーしてもいけないということです。

管理者の観点からは、本稿で提案するような運用は管理が煩雑になると思われる向きも多いようです。
しかし、ユーザにあらかじめ公開鍵を提出させ git レポジトリなどで管理をし、 Ansible などの構成管理ツールを使用することで、簡単に運用する事が可能です。

# SSH 公開鍵認証とは

まず SSH 公開鍵認証の仕組みについて説明します。

## 暗号とは

SSH 公開鍵認証は、暗号の仕組みを利用しています。
暗号の基本的な使い方は、暗号通信です。
暗号通信を行うには、届けたいデータを第三者が見ても内容がわからない形に変換して相手に送り、
相手は変換されたデータから元のデータを復元出来なければなりません。

一般的によく知られた暗号の方式では、この変換と復元に一つの秘密のデータを利用します。
この秘密のデータは鍵(key)などと呼ばれます。
また、変換前のデータを平文(plaintext)、内容がわからない形に変換することを暗号化(Encryption)、変換されたデータを暗号文(ciphertext)、暗号文を平文に復元することを復号化(Decryption)と呼びます。

![symmetric-encryption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/a66985e7-e617-05da-9eec-4c028edbcbfd.png)

一般的によく知られた暗号の方式では、図の青色の要素、つまり暗号文と暗号化、復号化の手順から、図中の赤色の要素、つまり鍵や平文を推測することは困難です。
これは暗号の方式を知られたり、暗号文を盗み見られても、その内容が知られてしまう事はないということです。
これが暗号通信ということです。

この暗号の方式では、鍵を持っている人であれば誰でも復号することが出来ます。
そのため鍵は秘密にしなければならず、この鍵は秘密鍵などと呼ばれます。
こういった、暗号化に使う鍵と復号化に使う鍵が同じで、鍵を秘密にしなければならないという特徴から、この暗号の方式は共通鍵暗号、秘密鍵暗号、対称鍵暗号などと呼ばれます。

一方で、共通鍵暗号は暗号通信を行うことが出来るのですが、秘密鍵を安全に流通させる仕組みが必要だという問題があります。

## 公開鍵暗号とは

SSH 公開鍵認証は公開鍵暗号という仕組みを利用しています。

公開鍵暗号では、暗号化に使用する鍵と、復号化に使用する鍵が別であり、ペアになっています
仮に、暗号化に使用する鍵を暗号鍵(Encryption key)、復号化に使用する鍵を復号鍵(Decryption key)と呼びましょう。

![publickey-encryption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/b9556627-6e20-74ca-e4ae-f7f6254c3378.png)

よく知られた公開鍵暗号の方式である RSA 暗号では、図の青色の要素、つまり暗号文と暗号鍵、暗号化、復号化の手順から、図中の赤色の要素、つまり復号鍵や平文を推測することは困難です。
そのため、暗号鍵を広く公開することが可能で、共通鍵暗号のように暗号鍵の流通に頭を悩ませることなく暗号通信が可能になります。

しかし復号鍵があると誰にでも復号されてしまう点は変わりありません。
復号鍵は秘密にしなければなりません。
公開することの出来る鍵があるという特徴から、この仕組みは公開鍵暗号と呼ばれ、暗号鍵は公開鍵、復号鍵は秘密鍵と呼ばれます。

## 電子署名とは

公開鍵暗号は、暗号通信のほかに、電子署名という使い方があります。
電子署名は、あるデータが特定の人によって作られたものであることを証明することです。

ある人が署名鍵(Sign Key)を用いて平文(plaintext)から署名文(Signature)を作成します。
検証鍵(Verification Key)を用いると、ある平文に対する署名文が、正当なものか検証(Verifiction)し、結果(Result)を得ることが出来ます。

![publickey-singing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/f73e3919-4e07-f611-21f0-3e29236e0af9.png)

ここで、図の青色の要素、つまり平文、暗号文、検証鍵、暗号化、復号化の手順から、図中の赤色の要素、つまり署名鍵鍵を推測することは困難であり、また、別の平文から作成した署名文を推測することが困難である場合に、検証鍵を広く公開して電子署名を実現することが可能になります[^signature-algo]。
これにより、ある署名鍵の持ち主が、対応する検証鍵を提示した人物と同じ人物だと証明することが可能になります。

[^signature-algo]: 暗号通信の場合と比べ条件が追加されています。これは暗号通信の場合平文が秘密であることが前提なのに対し、電子署名の場合平文も公開しなければならないからです。

しかし、署名鍵があると誰でも署名文を作成出来てしまいます。
そのため署名鍵は秘密にしなければなりません。
電子署名の場合は、検証鍵が公開鍵と呼ばれ、署名鍵が秘密鍵と呼ばれます。

先ほど登場した RSA 暗号は、暗号通信にも電子署名にも使うことが可能で、一つのキーペアの公開鍵を暗号鍵にも検証鍵にも、秘密鍵を署名鍵にも復号鍵にも使うことが可能です。
他の公開鍵暗号の方式には、暗号通信にしか使えないもの、電子署名にしか使えないものもあります。

## SSH 公開鍵認証のしくみ

SSH 公開鍵認証は電子署名の仕組みを使って認証を行います。
クライアントは認証の途中でサーバと共有されるデータ[^ssh-auth-detail]について署名を生成し、サーバに送信します。
サーバは検証結果が正しかった場合に、クライアントにアクセスを許可します。

[^ssh-auth-detail]: 具体的にはセッション識別子と SSH 公開鍵認証リクエストメッセージを使用します(参考 : [RFC4252](https://tools.ietf.org/html/rfc4252)9ページ目)。

![ssh-pubkey-auth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/a6b9701a-c465-d396-f807-dc5b3709707d.png)

ここからわかるように、 SSH 公開鍵認証では、クライアントがあるキーペアの署名鍵、つまり秘密鍵を持っているか否かで認証を行っています。
つまり公開鍵認証における秘密鍵はパスワード認証におけるパスワードと同じものです。

# SSH 公開鍵認証の使い方

次に SSH 公開鍵認証の使い方を説明します。
OpenSSH クライアントの説明を行います。
サーバや他の製品については割愛します。

## SSH キーペアの作成

SSH 公開鍵認証を利用するには、まずキーペアが必要です。

### OpenSSH の場合の手順

OpenSSH クライアントにて SSH キーペアを作成するには以下のコマンドを実行します[^keyalgo]。

[^keyalgo]: ここでは RSA 方式の公開鍵を生成します。これは、2019年7月現在、 AWS の鍵登録システムが RSA にしか対応していないためです。 AWS を利用しない場合には、より効率的な ECDSA などの方式を利用する選択肢もあります。その際のコマンドは ``ssh-keygen -b 521 -t ecdsa`` などです。詳しくはマニュアル、 [ssh-keygent(1)](https://man.openbsd.org/ssh-keygen) を読みましょう。

~~~
ssh-keygen -b 4096 -t rsa
~~~

実行するとまず以下のような出力があり、キーペアを書き出すファイルを名の入力を要求されます。括弧内のファイルパス(この例では /home/username/.ssh/id_rsa)は実行環境によって異なります。

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

特別な場合でない限り、ここはそのままエンターキーを押して構いません。
続いて、以下のような出力があり、鍵ファイルを暗号化するパスフレーズの入力を要求されます。

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

特別な場合でない限り、ここにはパスフレーズを入力しましょう。
パスフレーズは覚えやすいことが大切ですが、あまりにも短かいものや、単純すぎるものは避けましょう。

そうすると ``~/.ssh`` 以下に ``id_rsa`` と ``id_rsa.pub`` の2つのファイルが作成されます。
前者が秘密鍵、後者の ``.pub`` がついている方が公開鍵です。
それぞれ以下のような内容になります。

~~~ ~/.ssh/id_rsa.pub
ssh-rsa XXXX(長いので中略)XXXX== kaznak@qiita.com
~~~

~~~ ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: XXX-XXX-XXX,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(長いので中略)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END RSA PRIVATE KEY-----
~~~

サーバ管理者が居る場合は、作成した公開鍵を安全な方法で渡しておきましょう。
秘密鍵を送ってはいけません。

### PuTTY の場合の手順

OpenSSH クライアントにて SSH キーペアを作成する場合、 PuTTY Key Generator を利用します。
以下のようなアイコンのアプリケーションを起動します。

<img width="83" alt="puttyKeygen-icon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/d25b5391-fe16-5e12-9fce-f857750c25ca.png">

起動した画面を以下のように設定します。
下から二番目の ``Type of key to generate:`` のラジオボタンで、 RSA を選択し、一番下の ``Number of bits in a generated key:`` の欄に 4096 を入力します。

<img width="359" alt="putty-before-gen.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/e7c500ea-0207-5287-94c6-a83cd0797959.png">

設定したら、中段の ``Generate`` ボタンを押します。
すると、プログレスバーが表示されたあとに鍵の内容が表示されるので、
上段の ``Key passphrase:`` 、 ``Comfirm passphrase:`` の欄に、同じパスフレーズを入力します。
パスフレーズは覚えやすいことが大切ですが、あまりにも短かいものや、単純すぎるものは避けましょう。

<img width="359" alt="putty-before-save.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/8d0f188d-ea00-1660-d926-5abe145dc418.png">

入力が終わったら、 ``Save public key`` 、 ``Save private key`` を押して、それぞれ公開鍵と秘密鍵をファイルに保存します。
秘密鍵は自分以外見ることが出来ないフォルダに保存しましょう。

公開鍵ファイルの内容は以下のような形です。

~~~
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-20190731"
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(長いので中略)
XXXXXXXX
---- END SSH2 PUBLIC KEY ----
~~~

秘密鍵ファイルの内容は以下のような形です。

~~~
PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: rsa-key-XXXXXXXX
Public-Lines: XX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(長いので中略)
XXXXXXXX
Private-Lines: XX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(長いので中略)
XXXXXXXXXXXXXXXXXXXXXXXX
Private-MAC: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
~~~

サーバ管理者が居る場合は、作成した公開鍵を安全な方法で渡しておきましょう。
秘密鍵を送ってはいけません。

## 公開鍵の設置

筆者は、通常は後述する運用方法のように、サーバの管理者が公開鍵を設置する事を勧めています。
しかし自分自身で設置する必要があることもあるでしょう。
以下ではサーバへの公開鍵の設置の仕方を説明します。

### PuTTY で作成した公開鍵の OpenSSH 公開鍵への変換方法

PuTTY を利用しているユーザは、公開鍵を設置する前に出力された公開鍵を OpenSSH の形式に変換する必要があります。

PuTTY で作成した公開鍵ファイルが ``puttykey.pub`` という名前のファイルに格納されているとします。
同ファイルを OpenSSH のコマンドが使用できる環境に移して、以下のコマンドを実行します。

~~~
ssh-keygen -i -f puttykey.pub  > opensshkey.pub
~~~

``opensshkey.pub`` に OpenSSH 形式の公開鍵が保存されます。
以下では ``ssh-keygen`` で作成した場合と同じ手順で利用できます。

### OpenSSH サーバ側での作業

公開鍵は全て一行の文字列です。
公開鍵が格納されたファイルをサーバに送信し、その内容をサーバのファイル、 ``~/.ssh/authorized_keys`` に追記します。
これでそのユーザは、対応する秘密鍵でログイン出来るようになります。

サーバに送信する必要があるのは公開鍵だけです。
秘密鍵はサーバに送信してはいけません。
秘密鍵は誰にも渡してはいけません。

サーバのディレクトリ ``~/.ssh`` とファイル ``~/.ssh/authorized_keys`` は、自分自身だけが読めるようになっていなければなりません。
以下のコマンドをサーバで実行して、パーミッションを変更します。

~~~
chmod -R go-rw ~/.ssh
chmod -R u+rw ~/.ssh
~~~

``authorized_keys`` には複数の公開鍵を保存できます[^multiple-key]。
その場合、一行に一つのキーを登録します。

[^multiple-key]: これにより、後述する1デバイス1キーペアの運用が可能です。

Linux ディストリビューションによっては、手元のコンピュータの authorized_keys が既に設定ずみの場合に利用できる、 ``ssh-copy-id`` コマンドを提供しています。

## SSH ログインの方法

それでは登録した公開鍵を利用してログインしましょう。

### OpenSSH の場合の手順

OpenSSH クライアントの場合の手順は以下のとおりです。
Linux や MacOS X の場合は通常こちらです。

秘密鍵が ``~/.ssh/id_rsa``(本稿の手順通り進めていればこのファイルのはずです)、ユーザ名が ``username`` 、ホスト名が ``ssh-server`` の場合、手元のコンピュータで以下のコマンドを実行します。

~~~
ssh -i ~/.ssh/id_rsa -l username ssh-server
~~~

これにより ``ssh-server`` にログイン出来ます。
このコマンドは以下のような形に省略することも可能です。

~~~
ssh username@ssh-server
~~~

### PuTTY の場合の手順

PuTTY クライアントの場合の手順は以下のとおりです。
以下のようなアイコンのアプリケーションを起動します。

<img width="86" alt="putty-icon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/cd2ac1e4-287a-b279-2ee5-db50be5caf80.png">


起動したら、左側のカテゴリツリーから、 ``Connection`` - ``SSH`` - ``Auth`` を選択し、以下の画像のように設定します。
右側の設定値入力欄の一番下の ``Private key file for authentication:`` で、秘密鍵を選択します。
ここでは秘密鍵ファイル、 ``secretkey.ppk`` を選択しています。

<img width="338" alt="putty-set-seckey.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/5e916b30-7ebb-e1ae-2755-688588d4b1ab.png">


秘密鍵を選択したら、左側のカテゴリツリーから、 ``Session`` を選択し、以下の画像のように設定します。
右側の設定値入力欄の一番上の ``Host Name (or IP address)`` の欄に、アクセス先のホスト名を入力します。
ここでは、 ``ssh-server`` を入力しています。

<img width="338" alt="putty-hostsetting.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/050b8e5c-7e1c-7ba5-a83c-929e94567d40.png">

入力したら、一番下の ``Open`` ボタンを押します。
すると以下のような画面が現れるので、 ``login as:`` に続いてユーザ名を入力します。
ここでは ``username`` を入力しています。

<img width="495" alt="putty-loginname.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121700/eee3309d-97a4-acbc-9735-6b5c9f0065a6.png">

これにより ``ssh-server`` にログイン出来ます。

# SSH 公開鍵認証の運用

SSH 公開鍵認証の利点は、キーペアをいくつでも作り、複数のサーバで認証に利用することが出来るという点です。
運用の際も、その利点を活かして以下のような流れになります。

+ キーペア作成(ユーザ側、一度だけ)
   1. ユーザは SSH 公開鍵認証を利用するコンピュータ上でそれぞれ個別にキーペアを作成する
	  - 秘密鍵のコピーは行いません
   2. ユーザは作成したキーペアの公開鍵を全てサーバ管理者に提出する
+ ユーザ権限設定(サーバ管理者、サーバ毎に実施)
  1. サーバ管理者はユーザアカウントを開設し、ユーザから提出されている全ての公開鍵にてアクセス権を付与する
     - このとき、メールアドレス等、全てのサーバで共通のユーザ名でユーザアカウントを開設するようにします

この流れの重要な点は、キーペア作成とユーザ権限設定を独立に実施することが可能だという点です。
権限を設定する際にいちいちユーザとサーバ管理者のやり取りをする必要はありません。
ユーザはホスト名さえ知っていれば直ちにアクセスすることが可能で、ホスト名は必要な人々(開発チームなど)全体に公開しておくことが可能です。

## 運用のポイント: ユーザサイド

ユーザとして SSH 公開鍵認証を利用する際に最も大切なことは、一度ログイン用のキーペアを作成したら、秘密鍵はそのコンピュータから他のコンピュータにコピーしたりせず、また誰にも見せないという事を守ることです。
これにより公開鍵認証は単に管理が簡単であるだけではなく、セキュリティの向上にも役立ちます。

他にもいくつか利用の際のポイントがあります。

### 1 コンピュータ 1 キーペアでの運用

いくつものコンピュータを持っていて、そのどれからもログイン出来るようにしたいという人も居るでしょう。
その場合に秘密鍵を別のコンピュータに移動させる事はしてはいけません。
その場合は、全てのコンピュータで別々にキーペアを作成します。
出来た公開鍵を全てサーバ管理者に送っておけば、あとはどのサーバにもログインすることが出来ます。

もしコンピュータを紛失したり、盗まれたりして、秘密鍵の安全性が懸念される状況になった場合は、対応する公開鍵をサーバから削除します。
こうすることでコンピュータ単位でのアクセス制御を行うことができます。

### ssh-agent によるパスフレーズ入力の省略

特にノートパソコンなど、紛失の可能性があるコンピュータで SSH 公開鍵認証を利用する場合、パスフレーズで秘密鍵を保護するのは良いことです。
パスフレーズをかけていても秘密鍵が知られてしまうリスクはありますが、大抵の場合それには時間がかかります。
1 コンピュータ 1 キーペアでの運用をしていれば、秘密鍵が知られてしまうまでの間に公開鍵を無効化することができる可能性があります。

しかし、サーバへのアクセスのたびに公開鍵のパスフレーズを要求されるのはうっとおしくなることもあるでしょう。
そのような場合、 ``ssh-agent`` を利用する選択肢があります。

``ssh-agent`` は、登録した秘密鍵を一時的に復号した形で保持してくれるエージェントです。
``ssh-agent`` を利用するには、まず以下のようなコマンドで起動します。

~~~
exec ssh-agnet $SHELL
~~~

起動したら、仮に利用したい秘密鍵が ``~/.ssh/id_rsa`` の場合、
以下のコマンドで登録します[^ssh-agent-exec]。

[^ssh-agent-exec]: ``ssh-agent`` にはいくつかの起動方法があります。上述の起動方法をお勧めするのは、シェルから抜けると必ず ``ssh-agent`` が終了するからです。 ``ssh-agent`` は動作中は平文の秘密鍵を保持し続けるので、必要がなくなったら終了させるのが望ましいです。

~~~
ssh-add ~/.ssh/id_rsa
~~~

すると、以下のような出力があり、パスフレーズを要求されるので入力します。
ファイルパス(この例では /home/username/.ssh/id_rsa)は実行環境によって異なります。

~~~
Enter passphrase for /home/username/.ssh/id_rsa:
~~~

以降はシェルを抜けるまで ``~/.ssh/id_rsa`` をパスフレーズの入力なしで利用可能です[^mac-ssh-agent]。

[^mac-ssh-agent]: この方法では ``ssh-agent`` を起動するたびに秘密鍵の登録が必要です。しかし Mac の場合、鍵の登録時に ``ssh-add -K ~/.ssh/id_rsa`` とすることで、キーチェーンストアを利用して鍵を登録することができます。このようにするとシェルを抜けても秘密鍵の入力は必要ありません。

### 踏み台を使いたい場合

踏み台などと呼ばれる特定のサーバを経由しないと、 SSH でのログインが出来ないという運用をしているケースもあります。

そのような場合、後述する３つの方法がありますが、 SSH ポートフォワーディングの利用をお勧めします。
踏み台サーバに手元のコンピュータのキーペアを送信することは禁止です。
秘密鍵を別のコンピュータに移動させる事はしてはいけません。

#### SSH ポートフォワーディング(推奨)

SSH にはポートフォワーディングという仕組みがあり、サーバ側で有効にされている場合に利用可能です。
この仕組みを使うと、手元のコンピュータへの接続すると、別のコンピュータに転送して接続してくれます。

たとえば、ユーザ名がどちらのサーバでも共通で ``username`` 、踏み台サーバのホスト名が ``bastion``、最終的にログインしたいサーバのホスト名が ``ssh-server`` の場合、手元のコンピュータで以下のコマンドを実行します。

~~~
ssh -L10022:ssh-server:22 username@bastion
~~~

これにより、手元のコンピュータの TCP 10022 番ポートへの接続が、 ``ssh-server`` の 22 番ポートへと転送されるようになります。
そこで、以下のコマンドを実行すると、 ``ssh-server`` へ接続することが出来ます。

~~~
ssh -p 10022 username@localhost
~~~

毎回こういった手順を踏むのが面倒な場合、 ``~/.ssh/config`` に以下の設定を記述しましょう。

~~~
Host ssh-server
  ProxyCommand ssh -CW %h:%p username@bastion
~~~

すると踏み台サーバを経ずにアクセス出来る場合と同様に、以下のコマンドでログインが可能です。

~~~
ssh username@ssh-server
~~~

#### 認証エージェントフォワーディングの利用

SSH 認証エージェントフォワーディングという仕組みがあり、サーバ側で有効にされている場合に、 [``ssh-agent``](https://man.openbsd.org/ssh-agent) コマンドなどを通じて利用可能です。
これを利用すると、ログインした先のサーバで手元のコンピュータに格納されている SSH 公開鍵を利用してのログインが可能になります。

この方式の注意点として、手元のコンピュータに格納されたキーペアを利用されてしまう恐れがあることが挙げられます。
認証エージェントフォワーディングを行う場合、踏み台サーバに UNIX ドメインソケットが作成されます。
この UNIX ドメインソケットにアクセス出来ると、エージェントを利用して、手元のコンピュータに格納されたキーペアを利用した認証が可能になってしまいます。

#### 踏み台に新しいキーペアを作成

サーバに新しいキーペアを作成する方法は、サーバの上でここまで説明したキーペアの作成と、鍵の設定を行う方法です。

この方式の注意点として、踏み台サーバが攻略され、それに気づくのが遅れた場合、ターゲットのサーバに対するアクセスを許してしまうことが挙げられます。

一方で、自動デプロイのため git レポジトリへのアクセスを行う場合など、どうしても必要な場合もあります。
その場合は、 git レポジトリにアクセスするためだけの鍵を作成し、レポジトリの側では十分に権限を制限して利用するなど、細心の注意を払って権限を管理して利用する事をお勧めします。

### ssh_config の活用

上述のポートフォワーディングの節でも見ましたが、 [ssh_config(5)](https://man.openbsd.org/ssh_config) を上手く設定することで、接続時の手間を減らすことができます。

## 運用のポイント: 管理者サイド

ここまで述べたような運用方法は、一見管理が煩雑になりそうに思えます。
しかし、以下の工夫でむしろより簡単にユーザ権限の管理を行うことが可能です。

1. ユーザごとのユーザアカウントの発行し、アカウントを共用しません。
   - 権限はグループによって管理し、 [``sudo(8)``](https://www.sudo.ws/man/1.8.27/sudo.man.html) を利用するようにします。
   - これによってセキュリティインシデント発生時の対応を大幅に簡略化出来ます。
2. メールアドレスなどを利用して、全てのサーバで同じユーザ名を使用します。
   - クレデンシャル情報の管理コストを削減できます。
3. 公開鍵レポジトリ[^github-key]の運用し、ユーザ毎の公開鍵を git レポジトリなどで管理します。
   - ユーザ名毎にファイルを作成し公開鍵を格納するのが単純で楽でしょう。
   - ユーザからの公開鍵の提示をプルリクエストの形で受け付けても良いでしょう。
   - コミットには署名をつけるようにしましょう。
4. Ansible などの構成管理ツールを利用してのユーザアカウントの設定を行います。
   - ユーザの作成と前述の公開鍵レポジトリからの鍵の取得と設定を自動化します。

これにより、管理者もユーザも複数のユーザ名、ホスト名、パスフレーズの対応を管理する必要はなくなります。
管理者からユーザに伝えるアクセス情報はホスト名と、もしあれば踏み台サーバのホスト名(あるいは ``~/.ssh/config`` のスニペット)だけになり、これらはあらかじめ公開しておくことが可能な情報です。ユーザは自身の ``~/.ssh/config`` とキーペアのみ管理すればよくなります。

[^github-key]: github を利用している場合は github から登録済みの公開鍵を取得することも出来ます。ただし、デプロイ用の鍵と混同しないように気をつけましょう。

## 特殊な場合の対応

ここまでで運用の基本方針を述べました。
しかしいくつか特殊なケースがあり、上述の方法では運用が困難なケースがあります。
その場合、用途別のキーペアを作成して対応します。
以下では例を挙げて対応策を説明します。

### git レポジトリなどでデプロイ用のキーペアが必要なケース

多くの git レポジトリが SSH 公開鍵認証に対応しています。
開発のためにアクセスするさいには基本方針のままでよいのですが、自動でデプロイを行うようなケースでキーペアが必要になることがあります。

その場合はデプロイ用のキーペアを作成して利用します。
また、利用する git レポジトリの機能を利用して当該キーペアの権限を限定しておきましょう。

### クラウド上の仮想マシンの初期ユーザ鍵が必要なケース

AWS EC2 等のクラウド仮想マシンを利用する場合、初期ユーザとしてアクセスするためのキーペアが必要となるケースがあります。
この場合、以下の流れで運用します。

1. 初期ユーザ用のキーペアを作成、当該キーペアで仮想マシン立ち上げ
2. 初期ユーザにログインし、直ちに個別ユーザを作成、 root 昇格権限を付与
3. 初期ユーザのログインを無効化、パスワードロック、公開鍵の無効化を実施

初期ユーザ用のキーペアは仮想マシン立ち上げ時にのみ利用し、立ち上がったら直ちに必要な設定を済ませて、キーペアを破棄するようにします。
[Terraform](https://www.terraform.io/)/[Ansible](https://www.ansible.com/) などの構成管理ツールを使用することで、この一連の流れをスムーズに実施することが可能です[^terraform]。

[^terraform]: Terraform には [TLS Provider](https://www.terraform.io/docs/providers/tls/index.html) というモジュールがあり、 Terraform のみでキーペアを作成可能です。 Ansible では [user, authorized_key, lineinfile](https://docs.ansible.com/ansible/latest/modules/modules_by_category.html) などのモジュールを利用することでこのフローを実装可能です。

# 運用方法についての考察(管理者むけ)

以下では本稿で提案した運用方法を他の運用方法、パスワード認証の場合と比較し、安全性の観点から考察します。

## パスワード認証の運用フローとの比較

まず、本運用方式を他の運用方式と比較してみましょう。
他の運用方法の代表的な方法としてパスワード認証の運用を取り上げます。
パスワード認証の場合は以下のような流れで運用する必要がありました。

+ ユーザ権限設定(サーバ管理者とユーザ、サーバ毎に実施)
  1. サーバ管理者はユーザアカウントを開設し、パスワードをユーザに通知する
     - このとき、メールアドレス等、全てのサーバで共通のユーザ名でユーザアカウントを開設すると楽です
  2. ユーザは受けとったパスワードをログイン操作を行う必要なコンピュータ全てにパスワードをコピーする

以下では比較のため、パスワードや秘密鍵のような、アクセスに必要な情報をクレデンシャルと呼びます。

### クレデンシャルの強度について
パスワードの問題の一つとして、安全性を高めるには長いパスワードが必要であるが、長いパスワードは覚えることが困難であるという問題があります。
これの問題に対して多くのユーザがパスワードマネージャを利用しています。

公開鍵認証は ssh-keygen のデフォルトの状態でも、ほとんどのパスワードより安全なクレデンシャルを利用することが出来ます。
なおかつ、クレデンシャル情報はファイルに格納されるので覚える必要がありません。

### クレデンシャルの配布について
また、本稿では暗号について説明をしました。
このパスワード認証のアプローチは、対称鍵暗号の問題である、秘密鍵をどのように配布するかという問題に直面します。
つまり、パスワードをどのように配布すれば安全であるかという問題です。

公開鍵認証の運用の一つとして、管理者側で作成したキーペアを配布するアプローチがありますが、
秘密鍵を配布してしまっているため、パスワード認証と同等と言えます。

本稿で提案する公開鍵認証の運用方法を採用する場合は、そういった問題は発生しません。

### オペレーションの流れについて
よくある対処法として、初回のログイン時に直ちにパスワードを変更することを求めるというものがあります。
そのような対処方法の場合、ユーザ権限が発行されたら直ちにログインを促し、パスワードを変更してもらう必要があります。
したがって、安全にパスワード認証を運用するためには、管理者とユーザの間で同期的なオペレーションが必要になります。

公開鍵認証では、鍵配布に関する問題を解決しているので、こういったオペレーションは不必要となります。

### クレデンシャルの管理について
また、パスワードの認証方式の場合、サーバ毎にパスワードは異なるので、ホスト名、(必要であればユーザ名、)パスワードの組を管理しなければなりません
この管理は非常に煩雑です。

公開鍵認証の場合、使用する鍵ファイルを指定されたディレクトリに配置しておけばよく、管理が大幅に簡素化されます。

## より一般的な考察

以下ではより一般的な観点から考察します。
評価軸として、3つの軸での比較が考えられます。

1. クレデンシャル、認証方式の強度
2. オペレーションの安全性と容易さ
3. アクセス元、アクセス先とクレデンシャルの対応

1 は認証技術自体の性質に由来するものです。
公開鍵認証は現在の認証技術のなかで十分な強度を持っているといえます。

2 はオペレーションの性質に由来するもので、現実的なセキュリティ施策を実施する上では必要です。
たとえば、かつてはパスワードの定期的な変更が望ましいとされて居ました。
しかし近年ではこれは煩雑すぎるためかえって安全性を下げると考えられています[^password-change]。
公開鍵認証方式は、ここまで見たようにより容易なオペレーションで高い安全性を得ることが出来ます。

[^password-change]: [総務省 : 国民のための情報セキュリティサイト](http://www.soumu.go.jp/main_sosiki/joho_tsusin/security/basic/privacy/01-2.html)

3 は1つのクレデンシャルがアクセス元、アクセス先にどのように対応しているかという観点の議論です。
オペレーションに関する議論と近いのですが、以下で特に詳細に考察します。

### アクセス元、アクセス先とクレデンシャルの対応

アクセス元、アクセス先とクレデンシャルの対応は大まかに以下の4つに分類出来ます。

1. 1 vs 1 : アクセス元、アクセス先の対応毎に1クレデンシャル
   - 公開鍵認証で実装可能
2. n vs 1 : アクセス先毎に1クレデンシャル
   - 現行の一般的なパスワード認証
   - 公開鍵認証でもキーペアを配布する運用方式ではこちらに該当
3. 1 vs n : アクセス元毎に1クレデンシャル
   - 本稿で提案した公開鍵認証の1デバイス1キーペア方式
4. n vs n : 全てのアクセス元、アクセス先で同一のクレデンシャルを使用
   - パスワード使い回し方式

アクセス元、アクセス先というふうに、個別に考える必要があるのは、攻撃者に攻略されたノードの情報を攻撃に利用され得るからです。

まずアクセス先が攻略されたケースについて考察します。
アクセス先が攻略されるケースとしてはサイバー攻撃などが一般的でしょう。
一般的なパスワード認証は、公開鍵認証と比較してアクセス先の情報、例えばパスワードハッシュから、クレデンシャル、つまりパスワードを得ることが容易です。
あるアクセス先が攻略されたとき、もし複数のアクセス先で同じクレデンシャルを利用できると、芋づる式に複数のアクセス先の攻略を許してしまいます。
そのため、 1 か 2 の方式をとるべきなのですが、一般的なパスワード認証の性質として、アクセス元ごとにパスワードを分けることは出来ません。
そのため 2 が現実的なアプローチになります。

これに対して、公開鍵認証ではアクセス先の情報、つまり公開鍵から、クレデンシャル、つまり秘密鍵を得ることが極めて困難です。
そのため、パスワード認証と比較して芋づる式の攻略を考慮する必要性は低いと言えます。
この観点からは、公開鍵認証では全ての方式をとることが出来ます。


次にアクセス元が攻略されたケースについて考察します。
アクセス元が攻略されるケースとしては、アクセス元はノートパソコンなどのケースも多いので、紛失や盗難などでしょう。
アクセス元が攻略された場合、公開鍵認証ではクレデンシャルを取得され、芋づる式に複数のアクセス先の攻略を許してしまう可能性があります。
パスワード認証については、パスワード認証は本来、パスワードはユーザが記憶しておくべきものです。
しかし昨今では管理の煩雑さから多くの場合でパスワードマネージャが利用されています。
パスワードマネージャによってはサービス化され二段階認証などで安全性を高めているものがありますが、そうでない場合、パスワードマネージャが攻略されれば状況は同じです[^bad-mfa]。
そのため、アクセス元が攻略された場合、パスワード認証も、クレデンシャルを取得され、芋づる式に複数のアクセス先の攻略を許してしまう可能性があります。

[^bad-mfa]: 二段階認証を導入していても、間違った利用方法により効果がなくなっている使い方もあります。例えば、ログインに使用するデバイスと同じデバイスにて、仮想 MFA デバイスソフトウェアにより二段階認証コードを生成しているケースなどです。

ここでもしアクセス元ごとに別々のクレデンシャルを利用していれば、攻略された可能性のあるアクセス元のクレデンシャルを無効化することで対応が可能です。
一般的なパスワード認証の性質として、アクセス元ごとにパスワードを分けることは出来ないので、パスワードマネージャが利用されている場合、パスワード認証はアクセス元の攻略に対して脆弱です。
一方で公開鍵認証は、 1 もしくは 3 の方式をとることができます。

1 の方式はアクセス先が攻略された場合に安全性を高めることが出来ました。
公開鍵暗号は、公開鍵から秘密鍵を推測される可能性はほぼ無視することが出来るので、アクセス先が攻略されたケースについては無視することができます。
また、1 の運用方式を厳密に実行しようとすると、本稿で提案した運用方法のようにあらかじめ公開鍵の提供を受け、保存しておくという事ができません[^no-pubkey-repo]。
そのため、アクセス権を付与する前に毎回あたらしい公開鍵の提供を受ける必要があり、さらにその公開鍵を安全に受け渡す方法が必要になり、オペレーションが煩雑になります。
本稿ではオペレーションの簡単さと安全性のバランスから、 3 の方式を推奨しています。

[^no-pubkey-repo]: 公開鍵レポジトリにアクセスされると、全ての公開鍵を知られてしまうからです。

# おわりに

本稿では SSH 公開鍵認証の仕組みと利用方法、運用方法について論じました。
こういった形での運用は一見煩雑に見えるかも知れません。
しかしユーザ、管理者双方が基本的な運用のルールを守り、構成管理ツールを使用することで、ストレスなく安全な運用が可能です。
まずは出来ることから初めてみてはいかがでしょうか。

# 参考文献

+ [共通鍵暗号](https://ja.wikipedia.org/wiki/共通鍵暗号)
+ [公開鍵暗号](https://ja.wikipedia.org/wiki/公開鍵暗号)
+ [Secure Shell](https://ja.wikipedia.org/wiki/Secure_Shell)
+ [RFC4252](https://tools.ietf.org/html/rfc4252)
+ [OpenSSH](https://www.openssh.com/)
+ [ssh-keygent(1)](https://man.openbsd.org/ssh-keygen)
+ [ssh(1)](https://man.openbsd.org/ssh)
+ [ssh_config(5)](https://man.openbsd.org/ssh_config)
+ [sshd(8)](https://man.openbsd.org/sshd)
+ [ssh-agent(1)](https://man.openbsd.org/ssh-agent)