課題:Fail2Banだけではサーバーの存在を隠しきれない
VPSをクラウド上に公開して24時間も経てば、SSHログ(/var/log/auth.log)が数千もの不正ログイン試行で埋め尽くされていることに気づくでしょう。ボットネットは24時間365日ポートスキャンを行っており、ポート22を2222に変更したとしても、Nmapのようなツールを使えば数秒で稼働中のサービスを特定されてしまいます。
6ヶ月間プロダクションサーバー群を運用してきた経験から、Port Knockingは非常に実用的な追加セキュリティ層であると感じています。Fail2Banのように攻撃を受けてからブロックするのではなく、Port KnockingはSSHポートを常にClosed(閉じている)状態に保ちます. サーバーはまるで窓のないレンガの壁のようになります。秘密の順序でパケットを送信(ノック)したときだけ、あなたのIPアドレス専用にSSHの扉が一時的に開かれます。
Port Knockingの仕組み
knockdサービスはバックグラウンドで動作し、ネットワークログを監視します。あらかじめ定義されたポート(例:7001, 8005, 9002)にパケットを送信すると、それがトリガーとなってiptablesスクリプトが実行されます。このコマンドにより、あなたのIPアドレスがホワイトリストに追加され、一定時間だけポート22へのアクセスが許可されます。
興味深いのは、「ノック」に使用するポートをファイアウォールで開けておく必要がない点です。knockdは、ファイアウォールがパケットを拒否する前に、ネットワークインターフェース(libpcap)から直接パケットをキャプチャします。外部から見ると、サーバーはあたかも稼働中のサービスが何一つない「ブラックホール」のように見えます。
Ubuntu/Debianでのknockdのインストールと設定
ステップ1:パッケージのインストール
knockdのインストールは、以下のコマンドで簡単に行えます。
sudo apt update && sudo apt install knockd -y
ステップ2:ポートノックのシーケンス設定
主要な設定はすべて /etc/knockd.conf ファイルにあります。推測されないように、デフォルトのポート番号を変更しましょう。
sudo nano /etc/knockd.conf
ファイルの内容を以下の実用例に合わせて修正します:
[options]
UseSyslog
[openSSH]
sequence = 7542,8231,9145
seq_timeout = 5
command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 9145,8231,7542
seq_timeout = 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
技術的な注意点:
- sequence:1024〜65535の範囲でランダムな3〜4個のポートを選択します。
- seq_timeout:5秒以内に「ノック」を完了させる必要があります。
- command:
-I(Insert) パラメータを使用してルールをiptablesの先頭に追加し、最優先で適用されるようにします。
ステップ3:デーモンの有効化
/etc/default/knockd ファイルを開き、サービスが自動で起動するように設定します。
sudo nano /etc/default/knockd
START_KNOCKD=1 に変更します。ip link show コマンドでネットワークインターフェース(通常は eth0 や ens3)を確認し、更新します:
KNOCKD_OPTS="-i eth0"
その後、サービスを再起動します:
sudo systemctl enable --now knockd
ステップ4:デフォルトでSSHをブロックするファイアウォール設定
ここでサーバーの「扉」を閉じます。警告: 最初のノックのテストに成功するまで、現在のSSH接続は切断しないでください。
# 確立済みの接続を許可(即座にセッションが切れないようにするため)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# ポート22への新規接続をすべて拒否(REJECT)
sudo iptables -A INPUT -p tcp --dport 22 -j REJECT
特定のオフィスサブネットなどに対してアクセス範囲を制限するためにIP範囲を計算する必要がある場合は、IP Subnet Calculator ツールを使用すると、数秒で正確なCIDR範囲を取得できます。
クライアント端末からポートを開く方法
ポート22がブロックされたら、通常のSSHコマンドを実行する前にノックシーケンスを実行する必要があります。
knockコマンドを使用する場合
LinuxやmacOSを使用している場合は、knockd クライアントをインストールして実行します:
knock your-server-ip 7542 8231 9145
Netcat (nc) を使用する場合
追加ツールをインストールしたくない場合は、シンプルなbashループでも有効化できます:
for x in 7542 8231 9145; do nc -z your-server-ip $x; done
ノックが完了すると、通常通り ssh user@server が可能になります。作業が終わったら、逆順のシーケンスをノックしてポートを閉じます。
自分自身を締め出さないための実践的なアドバイス
Port Knockingの導入は非常に有効ですが、以下の3つの重要な点に注意してください:
- ネットワーク遅延: ネットワークが不安定な場合、パケットが正しい順序で届かないことがあります。接続できない場合は、2〜3回ノックを試してみてください。
- サーバーの再起動: 手動で設定したiptablesルールは再起動すると消失します。
iptables-persistentを使用してルールを保存するか、起動スクリプトに追加してください。 - 常にバックアップ手段を用意する: 万が一ファイアウォールの設定を間違えた場合に備え、常にVPSプロバイダーのWebコンソール(VNC)へのアクセス権を保持しておいてください。
おわりに
Port KnockingはSSHキーの代わりになるものではありませんが、自動攻撃によるノイズを完全に排除してくれます。攻撃者がポート22が開いているのを確認できなければ、彼らはあなたのサーバーを諦め、より簡単な標的を探しに行くでしょう。これは、すべてのLinux管理者が検討すべき、非常に効果的な「隠密」セキュリティ手法です。もしネットワークの疎通確認で問題が発生した場合は、接続できない場合のトラブルシューティングガイドも参考にしてください。

