サーバーを「公開してはいけない」という勘違い:SSH要塞化の真実
いいか、よく聞け。クラウドにインスタンスを立てた瞬間、君のサーバーは世界中から「餌食」としてスキャンされている。22番ポートを開放し、デフォルトのままパスワード認証で運用しているなら、それは玄関の鍵を開けたまま大金庫を庭に放置しているのと同じだ。
「そんな単純な攻撃、今どき通用しないだろ?」と高を括るエンジニアほど、インシデント発生時に真っ先に血の気が引くことになる。今回は、SSHの要塞化という「セキュリティのABC」を、泥臭い実戦レベルで叩き込む。
—
なぜ「パスワード認証」が命取りになるのか
攻撃者が使うツール(nmapやmasscanなど)を使えば、インターネット上の全IPアドレスのポートスキャンなんて数分で終わる。その後、MedusaやHydraといったツールで、辞書攻撃(ブルートフォース)を仕掛けるのが彼らの常套手段だ。
攻撃者が狙う「盲点」
1. rootログインの試行: 多くのディストリビューションでデフォルトのユーザー名であるrootは、攻撃者の最初の標的だ。
2. パスワードの限界: どれほど複雑なパスワードを設定しても、GPUクラスタを用いた現代の総当たり攻撃の前では、いずれ突破される。
3. ログの汚染: パスワード認証を許可していると、攻撃の試行ログで /var/log/auth.log が埋め尽くされ、本当に検知すべき異常が埋もれてしまう。
これらを物理的に無効化し、「鍵がなければ門前払い」にするのが、我々が守るべき鉄則だ。
—
実践:sshd_config の鉄壁設定
設定を変更する前に、必ず「現在ログイン中のセッション」とは別に、もう一つ接続確認用のセッションを維持しておくこと。設定ミスで自分が締め出される「ロックアウト」は、現場で最も恥ずべきミスのひとつだ。
/etc/ssh/sshd_config を開き、以下の設定を適用しろ。
# ---------------------------------------------------------
# SSHD セキュア構成テンプレート
# ---------------------------------------------------------
# rootでのログインを許可しない(必須)
PermitRootLogin no
# パスワード認証を完全に無効化(ブルートフォースを物理的に無効化)
PasswordAuthentication no
# 公開鍵認証を強制
PubkeyAuthentication yes
# 空パスワードの許可を禁止
PermitEmptyPasswords no
# チャレンジレスポンス認証を無効化(不要な攻撃対象を減らす)
ChallengeResponseAuthentication no
# X11転送の無効化(踏み台リスクの排除)
X11Forwarding no
# 必要があれば、特定のユーザーのみにログインを制限
# AllowUsers username
設定を書き換えたら、必ず sudo sshd -t で構文チェックを行え。問題なければ sudo systemctl restart sshd で反映させる。これで、パスワード認証という脆弱性は消滅する。
—
自動化時代の「鍵管理」:Python での鍵生成プロセス
手動で鍵を作るのもいいが、エンジニアなら冪等性を担保した運用を目指すべきだ。以下は、新規サーバー構築時に公開鍵を自動配置するためのPythonの断片コードだ。手作業による「鍵の取り違え」を防ぐための設計思想だ。
import os
import subprocess
def setup_ssh_directory(user_home):
"""
SSHディレクトリの権限を厳格に設定する
"""
ssh_dir = os.path.join(user_home, ".ssh")
# 権限は 700 (所有者のみ読み書き実行可)
os.makedirs(ssh_dir, mode=0o700, exist_ok=True)
# authorized_keys の作成と権限設定
auth_keys = os.path.join(ssh_dir, "authorized_keys")
if not os.path.exists(auth_keys):
with open(auth_keys, "w") as f:
f.write("ssh-rsa AAAAB3Nza... (ここに公開鍵を記述) ...user@host")
# 権限は 600 (所有者のみ読み書き可)
os.chmod(auth_keys, 0o600)
print("SSHディレクトリの要塞化が完了しました。")
# 実行時には、必ず適切な所有権を付与すること
# subprocess.run(["chown", "-R", "user:user", ssh_dir])
—
現場の知見:さらに一歩先へ
SSHを要塞化しても、依然としてポートを公開している事実は変わらない。より高いレベルのエンジニアを目指すなら、以下の対策も検討せよ。
- ポート番号の変更:
22番ポート以外に変更するだけで、Botによる単純な攻撃の9割を回避できる。ただし、これはセキュリティではなく「隠蔽」であることに注意しろ。 - Fail2Banの導入: 認証失敗を繰り返すIPを、ファイアウォール(
iptablesやnftables)レベルで自動ブロックさせる。これはもはや現代運用の標準装備だ。 - 踏み台サーバー(Bastion Host)の構築: インターネットから直接アプリサーバーにSSHさせず、認可されたセキュアな踏み台を経由させる構成を組む。
最後に:セキュリティは「設定」ではなく「規律」だ
一度設定して終わりではない。PermitRootLogin no を設定しても、将来的に誰かが「一時的に便利だから」といって設定を戻してしまうことは往々にしてある。
構成管理ツール(AnsibleやTerraform)を用いて、「正しい状態を強制的に維持する」ことこそが、最高峰のエンジニアが取るべきアプローチだ。
君の守るべきサーバーは、君が寝ている間も攻撃されている。だが、正しい設計さえしていれば、その攻撃はただの「無意味なノイズ」に過ぎない。さあ、今すぐ設定ファイルを確認しろ。そこに妥協の余地はないはずだ。
コメント