LinuxサーバーへSSH公開鍵認証とFail2Banでの不正ログイン対策

— セキュリティ強化の基本を、手戻りゼロで

この記事で得られること

  • 安全に SSH公開鍵認証 を導入できる
  • パスワードログインを停止 して総当り攻撃をブロック
  • Fail2Ban でログ監視→自動遮断、通知や再犯重課も設定
  • つまずきにくい テスト手順/ロールバック手順 付き

前提・想定環境

  • OS:Ubuntu 20.04/22.04/24.04 などのDebian系、または RHEL 8/9・AlmaLinux・Rocky Linux
  • SSH はデフォルトポート 22(任意で変更手順も後述)
  • 作業ユーザーは sudo 可能(root でもOK)

⚠️ 作業は 必ず既存セッションを閉じずに 新しいターミナルからテストしながら進めてください。設定ミス時は既存セッションで戻せます。


ステップ0:新規の安全な管理ユーザーを用意(任意だが推奨)

root直ログインを避け、普段は一般ユーザー + sudo にしましょう。

Ubuntu/Debian

sudo adduser adminuser
sudo usermod -aG sudo adminuser

RHEL/AlmaLinux/Rocky

sudo adduser adminuser
sudo passwd adminuser
sudo usermod -aG wheel adminuser

ステップ1:クライアント側でSSH鍵を作る

Ed25519 推奨(高速・短鍵長・強度十分)。古いサーバーで非対応なら RSA 4096 を。

# 基本(コメントは任意、-a でKDF反復回数を強化)
ssh-keygen -t ed25519 -a 100 -C "yourname@machine"

# 互換性重視(必要時のみ)
# ssh-keygen -t rsa -b 4096 -o -a 100 -C "yourname@machine"

生成物(デフォルト)

  • 秘密鍵:~/.ssh/id_ed25519
  • 公開鍵:~/.ssh/id_ed25519.pub

秘密鍵は厳重に保管。第三者と共有しないでください。必要ならパスフレーズも設定。


ステップ2:サーバーに公開鍵を登録する

2-1. ssh-copy-id で楽に配置(推奨)

# まだパスワードログインが有効なうちに実行
ssh-copy-id -i ~/.ssh/id_ed25519.pub adminuser@your.server.ip

2-2. 手動配置(代替)

# サーバー側
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# 公開鍵の内容を authorized_keys に追記
echo "ssh-ed25519 AAAA...コメント" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

ステップ3:公開鍵認証のみでログインできるかテスト

既存セッションは閉じず、別ターミナルから接続確認

ssh -i ~/.ssh/id_ed25519 adminuser@your.server.ip

接続できたらOK。できない場合はこの時点で原因を解消(鍵の権限、ユーザー名、IP制限など)。


ステップ4:パスワードログインを停止(安全確認を挟む)

/etc/ssh/sshd_config を編集します。ディストリにより sshd_config.d/*.conf が優先される場合もあるので、同等設定が重複しないように。

# バックアップ
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo nano /etc/ssh/sshd_config

追記/確認(存在すれば値を修正)

PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
PubkeyAuthentication yes
# ルート直ログイン禁止(後述のroot鍵運用しない場合はnoに)
PermitRootLogin no
# 任意:特定ユーザーのみ許可(誤ると自分も締め出すので要注意)
# AllowUsers adminuser

設定反映

# Ubuntu/Debian
sudo systemctl restart ssh

# RHEL系
sudo systemctl restart sshd

テスト:別ターミナルで再接続(鍵で成功、パスワードでは拒否されることを確認)。

ロールバック:もしログイン不可になったら、既存セッションsshd_config.bak を戻し再起動。最悪はクラウドのコンソール接続/救出モードを使用。


ステップ5:ファイアウォールでSSHを限定(任意だが強力)

Ubuntu:UFW

sudo apt update
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH許可(デフォルト22番)
sudo ufw allow OpenSSH
# 任意:固定グローバルIPのみ許可
# sudo ufw allow from x.x.x.x to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose

RHEL系:firewalld

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
# 任意:単一IPのみ許可
# sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=x.x.x.x/32 service name=ssh accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

ステップ6:Fail2Ban の導入

インストール

  • Ubuntu/Debian sudo apt update sudo apt install -y fail2ban
  • RHEL/AlmaLinux/Rocky sudo dnf install -y epel-release sudo dnf install -y fail2ban

基本設定(jail.local)

Fail2Ban は /etc/fail2ban/jail.conf を直接いじらず、上書き用の jail.local(または jail.d/*.conf)に書きます。

sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[DEFAULT]
# 誤BANを避けたいIP(自宅/踏み台など)を空白区切り
ignoreip = 127.0.0.1/8 ::1
bantime  = 1h            # 初回のBAN時間(1時間)
findtime = 10m           # 失敗回数カウント対象期間
maxretry = 5             # この回数失敗でBAN
backend  = systemd       # Ubuntu/RHELともsystemdジャーナル監視が安定

# 再犯重課(段階的にBAN延長)
bantime.increment = true
bantime.factor    = 2
bantime.maxtime   = 1w   # 最大で1週間まで延長

destemail = root@localhost
sender    = fail2ban@$(hostname -f)
mta       = sendmail

[sshd]
enabled  = true
port     = ssh
logpath  = %(sshd_log)s
mode     = aggressive    # ブルートフォースに強いモード
action   = %(action_)s   # ローカルログのみ(メール不要ならこれ)
# メール通知も欲しい場合は下行に変更(MTAの設定が必要)
# action = %(action_mw)s
EOF

mode = aggressive は OpenSSH のログからより多くの失敗パターンを拾います。誤検知が心配なら通常モードに。

起動・有効化

sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

状態確認

sudo fail2ban-client status
sudo fail2ban-client status sshd

出力例(イメージ)

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  `- Total failed: 23
`- Actions
   |- Currently banned: 2
   `- Total banned: 4

ステップ7:再犯者にさらに厳しく(recidive)

短時間のBANをすり抜ける攻撃者に有効です。

sudo tee /etc/fail2ban/jail.d/recidive.local >/dev/null <<'EOF'
[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
bantime  = 1w
findtime = 1d
maxretry = 5
EOF

sudo systemctl restart fail2ban
sudo fail2ban-client status recidive

ステップ8:運用のポイント(通知・ログ・解除)

  • 手動で解除(誤BAN時)
# 現在BANされているIP一覧
sudo fail2ban-client status sshd
# 単一IPの解除
sudo fail2ban-client set sshd unbanip 203.0.113.45
  • メール通知
    action = %(action_mw)s にすると BAN 時に whois 情報付きメール。
    送信には sendmail/postfix 等のMTA設定が必要。
  • ログの見方
    • Ubuntu/Debian:/var/log/auth.log(または journalctl -u ssh
    • RHEL系:/var/log/secure(または journalctl -u sshd
    • Fail2Ban 自体のログ:/var/log/fail2ban.log

ステップ9:追加強化(任意)

9-1. SSHポート変更(効率的なノイズ削減)

「隠蔽」ではありますが、botスキャンの大半を避けられます。
/etc/ssh/sshd_config

Port 22222

ファイアウォール許可 → SSH再起動 → 新ポートで接続テスト成功を確認してから 旧ポート閉鎖。

# UFW 例
sudo ufw allow 22222/tcp
sudo systemctl restart ssh
ssh -p 22222 adminuser@your.server.ip
# うまくいったら
sudo ufw delete allow OpenSSH

9-2. ルート直ログインの扱い

PermitRootLogin no を基本に。どうしても必要なら prohibit-password(鍵のみ)だが、通常は root 直ログイン自体を避ける運用が安全。

9-3. ユーザー制限

管理者以外のログインを切る

AllowUsers adminuser

複数指定可(空白区切り)。設定前に対象ユーザーで鍵ログインできることを確認

9-4. 多要素認証(上級者向け)

libpam-google-authenticator などのTOTPを PAM と組み合わせ可能。ただし無人接続や自動化処理には影響が出るので要設計。


うまくいかない時のチェックリスト

  1. 鍵ファイルの権限(サーバー側) chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys
  2. ユーザー名・ホームディレクトリ が正しいか
  3. sshd_config の二重定義/etc/ssh/sshd_config.d/*.conf)で上書きされていないか
  4. ファイアウォール/クラウドFW/セキュリティグループ でポートが開いているか
  5. ログ確認
    • journalctl -u ssh / journalctl -u sshd
    • /var/log/auth.log / /var/log/secure
  6. 古いOpenSSH で Ed25519 非対応 → RSA 4096 を使う
  7. SELinux(RHEL系) が有効でポリシーに阻まれていないか
    • getenforce で確認、/var/log/audit/audit.log を参照

まとめ:最小コストで最大の効果を出す順番

  1. 公開鍵認証導入(鍵ログインテストまで)
  2. パスワードログイン停止(PermitRootLoginも見直し)
  3. Fail2Ban(sshd有効、段階的BANとrecidive)
  4. ファイアウォール(IP制限やポート変更でノイズ減)

この4点を抑えるだけで、一般的な総当り攻撃・スキャンはほぼ無害化できます。あとは定期的なOS更新(自動化推奨)と監視で堅牢性を維持しましょう。


付録:コピペ実行用スニペット(Ubuntu最短コース)

既存セッションを閉じずに、各行の意味を理解して 実行してください。

# 0) 管理ユーザー(存在するならスキップ)
sudo adduser adminuser && sudo usermod -aG sudo adminuser

# 1) クライアントで鍵作成(ローカル端末で)
# ssh-keygen -t ed25519 -a 100 -C "you@pc"

# 2) 公開鍵登録(ローカル端末で)
# ssh-copy-id -i ~/.ssh/id_ed25519.pub adminuser@your.server.ip

# 3) 鍵ログインテスト(別ターミナル)
# ssh -i ~/.ssh/id_ed25519 adminuser@your.server.ip

# 4) パスワードログイン停止(サーバー側)
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config
grep -q '^PubkeyAuthentication' /etc/ssh/sshd_config || echo 'PubkeyAuthentication yes' | sudo tee -a /etc/ssh/sshd_config
grep -q '^PermitRootLogin' /etc/ssh/sshd_config || echo 'PermitRootLogin no' | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart ssh

# 5) UFW(任意)
sudo apt update && sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable

# 6) Fail2Ban
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd
bantime.increment = true
bantime.factor    = 2
bantime.maxtime   = 1w
[sshd]
enabled  = true
port     = ssh
logpath  = %(sshd_log)s
mode     = aggressive
action   = %(action_)s
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

よくある質問(FAQ)

Q. パスワードログインを完全に切るのは怖い…
A. まず鍵ログインが成功することを 別ターミナル で確認してから切り替えれば安全です。戻し方(ロールバック)も用意しておきましょう。

Q. ポート変更は必要?
A. 必須ではありませんが、スキャン雑音が減りログが見やすくなります。Fail2Banと併用で管理の手間が減ることが多いです。

Q. 自動化やCI/CDで鍵が使い回しになる
A. ジョブ専用の鍵を発行し、最小権限のユーザー・限定IPで使い分けましょう。期限管理も忘れずに。

タイトルとURLをコピーしました