ポートノッキングで SSH の authorized_keys を更新する

はじめに

こんにちは、 yosida95 です。

先日、 3 年間共に闘ってきた iMac が逝去しました。 その結果 MacBook Air と共に闘うことを強いられたのですが、この MacBook Air も 3 年前に購入したもので、 C2D の超低電圧版を積んだ大変歴史を感じる非実用的なマシンです。

そこで、実用的なマシンを手に入れるために MacBook Air を購入しました。 マシンを新しく購入して真っ先にやることは SSH 用の RSA 鍵ペアの生成だと思います。 私もその例に漏れずに SSH 用に RSA 鍵ペアを生成しました。

いざ開発を始めようとリモートのサーバーにログインを試みると、認証に失敗して接続を拒まれました。 当たり前の話です。 そこで何をするかというと、リモートサーバーの authorized_keys に新しく生成した RSA 鍵ペアの公開鍵の方を追記するわけです。 しかし、 authorized_keys を追記するにはリモートサーバーにログインする必要があります。 このためにすでに認可された鍵を持っているマシンから接続するのは面倒臭いです。

そこで、リモートサーバーにログインせずに authorized_keys を更新する方法を考えるわけです。 今回は、リモートサーバーに対してポートノッキングをすることで authorized_keys を更新できるようにします。

ポートノッキング

ポートノッキングとは、サーバーの特定のポートに対して特定のパターンでパケットを飛ばすことで事前に設定したコマンドを実行する仕組みのことを言います。

例えば、 sshd が 22 番ポートを listen しており、この 22 番ポートをポートスキャンから隠蔽したりブルートフォースから守ったりしたいという状況において、通常時は 22 番ポートに来たパケットは捨てるが、ポートノッキングをトリガーに一定時間だけ 22 番ポートを開けるという使い方をするわけです。

前述の例の場合では、 iptables の ipt_recent モジュールなどを使えば簡単に実現できますが、今回は authorized_keys を更新するという操作を実行するために、 L7 でポートノッキングを待ち受けるデーモンを動かすことにします。

今回、ポートノッキングを受け取るために recvknocking という Go ライブラリを書きました。

authorized_keys の更新

authorized_keys を更新する方法をお話する前に、私の SSH 公開鍵の管理方法についてお話します。

私の公開鍵の管理方法は、 ssh-keys という Git リポジトリ (オリジナルは GitLab でホスティング) にすべての SSH 公開鍵を保存し、クライアントマシンの公開鍵などの、全てのリモートサーバーで認可されてほしい鍵を authorized_keys に追記するルールを同じリポジトリにある Makefile に記述するというものです。

そのため、 authorized_keys を更新するには、リモートサーバーにある ssh-keys を GitLab から git pull してきて、そのあと make すればよいという事になります。

これを行うデーモンプログラムを gitpull として実装しました (リポジトリの名前や README 的には、ポートノッキングを受けて git pull を実行するだけのはずですが、実際には git pullmake したうえで、挙句その結果をメールで送信するということまでしています)。 これも Go 製で、先ほどの recvknocking を使って実装しています。

まとめ

#!/usr/bin/zsh
port=NNNN

for host in akari kyoko yui chinatsu sakurako yuno; do
    for i in `seq 1 3`; do
        nc "${host}.yosida95.com" $port
    done
done

とかすると authorized_keys が更新され、古い非実用的なマシンからわざわざリモートサーバーにログインせずとも新しい実用的なマシンの鍵が認可されるようになりました。

最後に

OpenSSH 6.2 からは、接続してきたクライアントの公開鍵が認可されているか否かを調べるために、 sshd が AuthorizedKeysCommand に設定したコマンドを叩いてくれる仕組みが導入されました。 この仕組を使うことで、データベースに公開鍵を問い合わせるといったことも可能になり、コードを書かずとも、ポートノッキングをせずとも、 authorized_keys を更新できます。 大変素晴らしいですね。

ちなみに、 Ubuntu 12.04 の apt リポジトリにある OpenSSH は 5.9p1 、 Sceitntific Linux 6.2 の yum リポジトリにある OpenSSH は 5.3p1 、 Mac OS X 10.9 にバンドルされている OpenSSH は 6.2p2 です。

以上です。 ありがとうございました。