はじめに
こんにちは。 KMC OB の nojima です。 最近は東京で社会人をやってます。
この記事はKMCアドベントカレンダー2013の13日目の記事です。 昨日の記事はnon117さんの ssh_config でした。
今日は authorized_keys
について書きたいと思います。
認証
最近は乗っ取ったPCを使って Bitcoin をひたすら採掘するのが流行っているそうです。 怖い世の中ですね。
ところで、SSH でサーバにアクセスできるようにしていると、結構頻繁に不審なユーザ(というかボット)からのログイン試行があります。 当然、このようなログインは絶対に成功させてはいけません。 逆に言うと、サーバに SSH ログインするためには、自分がそのサーバの正当なユーザであることを証明しなければなりません。 自分が自分であることを証明するための仕組みを認証と呼びます。
最もありふれた認証方法は、パスワード認証です。 ユーザは事前にサーバに秘密のパスワードを保存しておき、ログイン時にも同じパスワードをサーバに対して送信することで認証を行うという、なんの変哲もない認証です。 シンプルで便利な方法なのですが、パスワード認証にはいくつか問題があります。
- 事前にサーバにパスワードを安全に登録する手段がない場合がある。
- 強いパスワードを作ったり、覚えたりするのが大変。(特にサーバ管理者が)他人に強制するのはもっと大変。
- サーバにパスワードがバレる。(サーバがクラックされているとパスワードが流出する)
これらの問題は、パスワードではなく、鍵対を使って認証することで解決できます。 鍵対というのは、公開鍵と秘密鍵のペアで、…… と書こうと思っていたら既に possum さんが記事に書いてありました。 possum さんに記事では、通信の暗号化に公開鍵と秘密鍵を使うという話でしたが、認証にも鍵対を使うことができます。
- 任意のメッセージ M に対して、秘密鍵で暗号化すると、よくわからないメッセージ M’ になる。
- M’ を公開鍵で復号化すると元のメッセージ M に戻る。
- M から M’ を求めるのは困難。(暗号化通信の文脈では M’ から M を求めるのが困難であることを利用していましたが、認証では公開鍵と秘密鍵の役割をひっくり返して使います)
これを、
- サーバが提示したランダムなメッセージ M に対して
- ユーザ A があるメッセージ M’ を提示して
- サーバが M’ を事前に登録された公開鍵で復号化すると M になった場合、
- ユーザ A は登録された公開鍵に対応する秘密鍵を持っているに違いない。
- すなわち A は正当なユーザである!!
というふうに使います。 これにより、前述したパスワード認証の問題が解決されています。
- サーバに事前に登録しておくのは公開鍵だけなので、盗聴されても大丈夫。
- 秘密鍵はファイルなので中身を覚えなくて良い&非常に強い。ただしこれが流出するとまずいので、流出に備えてパスフレーズで保護するのが一般的です。流出させてしまったらパスフレーズが破られる前に鍵を revoke しましょう。
- サーバにはパスワードも秘密鍵の内容も送信しないので、サーバがクラックされていても秘密のcredentialが流出しない。
ということで、前置きが長くなりましたがこの公開鍵を保存しておくためのファイルが今回紹介する authorized_keys
です。
また、単に公開鍵を保存しておくだけでなく、実行するコマンドを制限したり、環境変数を設定したりすることもできます。
authorized_keys
の基本的な使い方
まずは、公開鍵と秘密鍵のペアを用意しないことには始まりません。
Linux であれば ssh-keygen -t rsa
を実行すると $HOME/.ssh/id_rsa
に秘密鍵が、$HOME/.ssh/id_rsa.pub
に公開鍵が生成されます。
この際にパスフレーズの指定が求められるので適当にパスフレーズを設定しましょう。
Windows では、例えば PuTTYgen を使って生成します。
PuTTYgen の使い方は適当にググってください。
「Public key for passing into OpenSSH authorized_keys2 file」と書いてあるところが公開鍵です。
公開鍵は次のような文字列です。(見やすくするために改行を入れていますが、実際は一行です。)
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDiOfpFMlcQuHHJR1SE1MOyrf2ifW5C8WgC7yvkNPQ
yeqjP5j5KSkNHm0mB4jieDLY8pV5Cu2pnUTwaN+nxMZragHgPTZMFO9ebk5BpM08or32bhp0+CpOGe8
Q9xt2lh8hrQr3cPgJojJ/w1TY5mo6RAiVHIw+tsqw2cRFxCgAOoV/Cpn0QtCpm7uusCvWxc3E3UzzEu
pnUoxSEqSg5ZHyEtJt/HfARt4aNozyLN3HHBJ9n5+BeIA6H36ZJBOf3lKtm7r2zO6TWT5W+xNoOPEZj
Cb4cpYMoR9/RY5kHt5ni3XgIk86DRPH0CiGQfJgBAoUel5bqj62MmpsMLKHRP8cz ubuntu@www-2
これを、何らかの手段でログインしたいサーバの $HOME/.ssh/authorized_keys
に書けば、鍵認証の準備完了です。
(パスワード認証などでログインできる場合は ssh-copy-id
を使うのが便利です。)
使いたい公開鍵が複数ある場合は、1行にひとつずつ公開鍵を書いていけばOKです。
ログインするときは、以下のように秘密鍵の場所を指定すると鍵認証でログインを試みてくれます。
$ ssh -i ~/.ssh/id_rsa example.com
実は ~/.ssh/id_rsa
はデフォルトで見てくれるので、~/.ssh/id_rsa
を使う場合に限っては -i ...
を省略して以下のように書くこともできます。
$ ssh example.com
Windows だと PuTTY の設定画面でそれっぽく設定すると鍵認証でログインできます。
コマンドの制限
サーバAからサーバBに定期的にファイルをバックアップすることを考えます。 具体的には、cron で定期的に rsync します。 このとき問題になるのが認証です。
- cron から実行されるのでユーザがパスワードを打つことはできない。
- 鍵認証を使えばパスワードは打たなくてよくなるが、悪意のあるユーザに秘密鍵を見られると、バックアップ用アカウントでサーバBにログインされてしまう。
これは嫌なので、「サーバBにはログインできるが、バックアップ以外のことができない」ような仕組みが欲しくなります。
実は、authorized_keys
を使えば、公開鍵ごとに実行できるコマンドを制限することができます。
(正確には、SSHクライアントから渡されたコマンドを無視して authorized_keys
に書かれたコマンドが実行されるという動作になる)
サーバAでは以下のようなスクリプトを cron で実行しているとします。
#!/bin/sh
rsync \
--archive \
--compress \
--delete \
--exclude=".ssh/" \
--exclude=".vim_backup/" \
--exclude=".gem/" \
--exclude=".rbenv/" \
--rsh="ssh -i /home/nojima/.ssh/backup_rsa" \
/home/nojima \
example.com:/path/to/backup
rsync は SSH した先で転送元から送られてきたデータを受け取るためのプロセスを起動します。
上のスクリプトを実行した場合は rsync --server -logDtprze.iLsf --delete . /path/to/backup
というコマンドを実行するので、authorized_keys
を使って実行可能なコマンドをこのコマンドだけに制限すれば、秘密鍵が流出してもバックアップ以外の悪さはできなくなります。
(rsync が転送先でどんなコマンドを実行しているのかは rsync に -vvv
オプションをつければ知ることができます。)
コマンドを制限するには、以下のように、公開鍵(ssh-rsa AAAAB...
の部分)の前に command="hogehoge"
という形でコマンドを書けばよいです。
command="rsync --server -logDtprze.iLsf --delete . /path/to/backup" ssh-rsa AAAAB...
公開鍵ごとに command が指定できるという機能は、他にも応用ができます。
例えば、Git レポジトリ管理ツールである Gitolite では公開鍵とユーザを結びつけるために authorized_keys
の command を利用しています。
- どのユーザも
git clone [email protected]:repo.git
のように git ユーザでレポジトリにアクセスする。 - Gitolite は認証に使用された公開鍵からユーザを判定する。
Gitolite に公開鍵を登録すると、git ユーザの authorized_keys
に以下のようなエントリが追加されます。
command="[path]/gl-auth-command tanaka",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t...
command="[path]/gl-auth-command suzuki",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXtCT...
このようにコマンドの中にユーザを表す引数が含まれているため、git ユーザとしてアクセスされても本当は誰がアクセスしてきたのか知ることができます。
おわりに
他にも authorized_keys
を使えばいろいろできますが、眠たくなってきたので(現在1時15分)これで今回の僕の話はおしまいです。
より詳しいことは man sshd
を参照ください。
明日は wacky さんが -D
オプションと tsocks について書いてくれます。
お楽しみに。
参考
man sshd
- how gitolite uses ssh