LinuxのSSHに二要素認証(TOTP)を設定する方法|Google AuthenticatorとPAMで不正ログインを防ぐ実践手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtipsセキュリティ > LinuxのSSHに二要素認証(TOTP)を設定する方法|Google AuthenticatorとPAMで不正ログインを防ぐ実践手順
「SSHにbrute force攻撃が来ているのは分かっているが、パスワードを変えるだけで本当に大丈夫なのか」
インターネットに公開したLinuxサーバーのSSHポートには、公開した翌日から世界中のスキャナーが探りを入れてきます。\`/var/log/secure\`や\`journalctl -u sshd\`を確認すると、1時間に数百件もの不正ログイン試行が記録されている — そんな状況は珍しくありません。

パスワードを複雑にするだけでは根本的な対策になりません。認証情報が流出した瞬間に終わりだからです。

この記事では、TOTPベースの二要素認証(2FA)をLinuxサーバーのSSHに設定する完全な手順を解説します。RHEL9系(Rocky Linux 9/AlmaLinux 9含む)とUbuntu 24.04 LTSの両方で動作確認済みです。パスワードが漏えいしても、スマートフォンの認証コードがなければログインできない構成を30分で構築できます。

この記事のポイント

・TOTPは30秒ごとに変わる6桁コードで、パスワード漏えいだけでは不正ログインを防げる構成にできる
・libpam-google-authenticatorとPAMの設定変更だけでSSHに組み込める
・公開鍵認証との組み合わせはAuthenticationMethodsで2段階を明示するのが確実
・ロックアウト対策としてスクラッチコードを設定直後にオフライン保管すること


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

SSHへの不正ログインがなぜ後を絶たないのか

「22番ポートを開けたら翌日には攻撃が来ている」というのは、インターネットに公開したLinuxサーバーを運用していれば誰でも経験することです。実際に`journalctl`で確認すると、こんなログが延々と流れています。

# journalctl -u sshd --since "2026-09-22" | grep "Failed password" Sep 22 03:12:41 web01 sshd[3289]: Failed password for root from 103.114.x.x port 51823 ssh2 Sep 22 03:12:44 web01 sshd[3292]: Failed password for root from 103.114.x.x port 51824 ssh2 Sep 22 03:12:47 web01 sshd[3295]: Failed password for admin from 185.220.x.x port 44218 ssh2 Sep 22 03:15:02 web01 sshd[3311]: Failed password for ubuntu from 45.33.x.x port 60012 ssh2 (以下省略: 1時間に200件超)

fail2banによる自動ブロックやポート番号の変更も有効な対策ですが、これらは「攻撃を受けにくくする」施策です。認証情報が流出した場合には効果がありません

二要素認証(2FA)が根本的に異なるのは、「知識(パスワード)+所持(スマートフォン)の2要素が揃わないとログインできない」点です。攻撃者がパスワードを知っていても、あなたのスマートフォンを持っていなければ侵入できません。

TOTPの仕組みと今回の設定ゴール

TOTP(Time-based One-Time Password)は、サーバーとスマートフォンで共有したシークレットキーと現在時刻を組み合わせて、30秒ごとに変わる6桁のコードを生成します。RFC 6238で定義された標準規格であり、Google Authenticator・Authy・1Passwordなど多くのアプリが対応しています。

今回の設定完了後、SSHログインフローはこうなります。
・SSHクライアントが接続要求を送る
・サーバーがパスワードを要求(または公開鍵認証)
・サーバーがTOTPコード(Verification Code)を要求
・30秒以内に正しい6桁を入力するとログイン成功

動作確認環境:Rocky Linux 9.4 / Ubuntu 24.04 LTS

libpam-google-authenticatorのインストール

1. Rocky Linux 9 / RHEL 9 / AlmaLinux 9の場合

Rocky Linux 9系では`libpam-google-authenticator`はEPELリポジトリに収録されています。EPELが未導入であればまず有効化します。

# EPELリポジトリを有効化(既に有効な場合は不要) dnf install epel-release -y # google-authenticatorとQRコード表示用ツールをインストール dnf install google-authenticator qrencode -y # インストール確認 rpm -q google-authenticator google-authenticator-1.10-2.el9.x86_64

`qrencode`はターミナル上にQRコードを表示するためのパッケージです。スマートフォンカメラでそのままスキャンできるので一緒に入れておきましょう。

2. Ubuntu 24.04 LTSの場合

Ubuntuはaptで直接インストールできます。

apt install libpam-google-authenticator -y # インストール確認 dpkg -l libpam-google-authenticator ii libpam-google-authenticator 20210105-2 amd64 Two-step verification

google-authenticatorコマンドでシークレットキーを初期化する

インストール後、TOTPを有効にしたいユーザーとして(rootではなく対象ユーザーで)`google-authenticator`コマンドを実行します。

# 対象ユーザーでログインした状態で実行する google-authenticator

1. 対話式設問への回答と実機の出力例

実行すると以下のような対話式設問が続きます。

Do you want authentication tokens to be time-based (y/n) y Warning: pasting the following URL into your browser exposes the OTP secret to Google: https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/... (ここにターミナル上でQRコードが表示される) Your new secret key is: ABCDE23456FGHIJ7 Enter code from app (-1 to skip): 836492 Code confirmed Your emergency scratch codes are: 42815709 91637402 58024167 76310582 30947861 Do you want me to update your "/home/sysadm/.google_authenticator" file? (y/n) y Do you want to disallow multiple uses of the same authentication token? (y/n) y By default, a new token is generated every 30 seconds by the mobile app. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. Do you want to do so? (y/n) y If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. Do you want to enable rate-limiting? (y/n) y

各設問の意味を整理します。
time-based y/n:時刻ベースのTOTPを使うかどうか。「y」で固定です
disallow multiple uses:同じコードを1回しか使えなくする(リプレイ攻撃防止)。「y」推奨
time-skew補正:前後1ステップ(前後30秒)の時刻ズレを許容するか。「y」推奨
rate-limiting:30秒間に3回までの制限を設ける。「y」推奨

2. QRコードをスマートフォンアプリで読み取る

ターミナルに表示されたQRコードを、Google Authenticator(iOS/Android)やAuthyなどのTOTPアプリで読み取ります。アプリに追加されると、30秒ごとに変わる6桁のコードが表示されるようになります。

読み取り後、アプリに表示されているコードをコマンドの「Enter code from app」の設問に入力して正しいことを確認してください。

3. スクラッチコードを必ずオフラインで保管する

表示された5つのスクラッチコード(8桁)は、スマートフォンを紛失・初期化した場合に一度だけ使える緊急ログイン用コードです。これを失うとロックアウトから自力で復旧できなくなります。紙に印刷してオフライン保管するか、専用パスワードマネージャーに保存してください。

PAMとsshd_configを変更してSSHにTOTPを組み込む

変更作業中は必ず現在のSSHセッションを維持したまま別セッションでテストしてください。設定ミスでロックアウトされた場合にコンソール(VNC/ILO/iDRAC)以外での復旧が不可能になります。

1. /etc/pam.d/sshdを編集する

`/etc/pam.d/sshd`の末尾に以下の1行を追加します。

# /etc/pam.d/sshd の末尾に追加(既存行は変更しない) auth required pam_google_authenticator.so

Rocky Linux 9.4での実際のファイル末尾(抜粋)は以下のようになります。

# /etc/pam.d/sshd(末尾抜粋・Rocky Linux 9.4) auth substack password-auth auth include postlogin # ...(省略)... # 末尾に追加した行 auth required pam_google_authenticator.so

2. /etc/ssh/sshd_configを変更する

`/etc/ssh/sshd_config`を開き、キーボードインタラクティブ認証を有効にします。ディストリビューションによって設定キー名が異なります。

# RHEL9系 / Rocky Linux 9 / Ubuntu 22.04以降 → KbdInteractiveAuthentication を使用 KbdInteractiveAuthentication yes # 古いOS(CentOS 7等)は下記のキー名を使用 # ChallengeResponseAuthentication yes # UsePAMはyesであることを確認(大半のディストリビューションでデフォルトyes) UsePAM yes

3. sshdの再起動と設定反映確認

変更後は必ず構文チェックをしてからsshdを再起動します。

# 構文チェック(エラーがなければ何も出力されない) sshd -t && echo "構文OK" 構文OK # sshdを再起動 systemctl restart sshd # 状態確認 systemctl status sshd | grep -E "Active:|Loaded:" Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled) Active: active (running) since Tue 2026-09-23 14:30:12 JST; 3s ago

動作確認と公開鍵認証との組み合わせ設定

1. Verification Codeが要求されることを確認する

別ターミナルから対象ユーザーでSSH接続します。パスワード入力後に「Verification code:」が表示されれば設定成功です。

ssh sysadm@192.168.x.x sysadm@192.168.x.x's password: Verification code:

TOTPアプリに表示されている6桁のコードを入力してログインできることを確認します。

2. 公開鍵認証とTOTPを組み合わせる設定

公開鍵認証を利用している場合、デフォルトでは公開鍵認証が成功した時点でTOTPなしでログインできてしまいます。公開鍵認証にもTOTPを必須にするには、`/etc/ssh/sshd_config`に次の行を追加します。

# 公開鍵認証が成功した後にもTOTPコードを要求する AuthenticationMethods publickey,keyboard-interactive

この設定後のSSH接続フローは次のようになります。

# 公開鍵認証で接続(鍵のパスフレーズなしの場合) ssh -i ~/.ssh/id_ed25519 sysadm@192.168.x.x # 公開鍵認証成功後、TOTPが要求される Authenticated with partial success. Verification code:

`Authenticated with partial success.`と表示されたら、公開鍵認証は通ったがTOTPが未入力という状態です。ここでアプリのコードを入力します。

トラブルシュート

【問題1】設定後もVerification Codeが要求されずにログインできてしまう

原因:`/etc/pam.d/sshd`への追記ミス、またはsshd_configの`KbdInteractiveAuthentication`が`no`のまま。

# PAM設定確認 grep pam_google /etc/pam.d/sshd auth required pam_google_authenticator.so # この行があればOK # sshd設定確認 sshd -T | grep -iE "kbdinteractive|challengeresponse|usepam" kbdinteractiveauthentication yes usepam yes

【問題2】正しいコードを入力しても「Verification code incorrect」になる

原因の多くはサーバーとスマートフォンの時刻ズレです。TOTPは現在時刻に基づいてコードを生成するため、双方の時刻が数十秒以上ずれると認証が失敗します。ntpd 時刻同期設定を参考にサーバーのNTP同期状態を確認してください。

# サーバーのNTP同期状態確認 timedatectl Local time: Tue 2026-09-23 14:35:22 JST Universal time: Tue 2026-09-23 05:35:22 UTC RTC time: Tue 2026-09-23 05:35:22 Time zone: Asia/Tokyo (JST, +0900) System clock synchronized: yes ← yes でなければ要確認 NTP service: active

時刻同期が有効で正常なのに認証が通らない場合は、`~/.google_authenticator`に`WINDOW_SIZE 3`を追記して許容範囲を広げてみてください(前後90秒まで許容)。ただしセキュリティは下がるため恒久対応はNTP修正を優先してください。

【問題3】スクラッチコードも尽きてロックアウトされた

コンソール(KVM/VNC/ILO/iDRAC)でサーバーに直接ログインし、`~/.google_authenticator`ファイルを削除すればTOTPが無効化されます。SSHでログインできるようになったら、`google-authenticator`コマンドで再設定してください。

# コンソールでログイン後にTOTP設定を削除してSSHを一時無効化 rm ~/.google_authenticator # SSHで再ログインできることを確認後、再設定する google-authenticator

本記事のまとめ

手順 コマンド・設定
インストール(RHEL9系) dnf install epel-release google-authenticator qrencode
インストール(Ubuntu) apt install libpam-google-authenticator
TOTPシークレット初期化 google-authenticator(対象ユーザーで実行)
PAM設定追加 /etc/pam.d/sshd末尾にauth required pam_google_authenticator.so
SSHD設定変更 KbdInteractiveAuthentication yes(sshd_configに追加)
構文確認と再起動 sshd -t && systemctl restart sshd
公開鍵+TOTP設定 AuthenticationMethods publickey,keyboard-interactive
パスワードだけに頼ったSSHは、認証情報が流出した瞬間に突破されます。TOTPの設定作業自体は30分程度で完了します。スクラッチコードの保管だけ忘れずに、今日中に設定してしまいましょう。

「こういったセキュリティ設定を迷わず正確に判断できるエンジニアになりたい」という方には、Linuxサーバー管理の実践スキルを2日間で体系的に習得できるセミナーをご用意しています。

SSH二要素認証を設定したら、次はサーバー全体のセキュリティ設計を体系的に固めませんか?

TOTPの設定は「攻撃者を門前払いする入口の鍵」です。しかし現場では、ファイアウォール設計・SELinux・監査ログ・侵入後の検知まで多層防御が求められます。
ネット上の断片的な情報をつなぎ合わせるだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。