Quick start: 5分で完了するSSH 2FAの有効化
ステージング環境や本番環境のセキュリティを今すぐ強化したいけれど、長々とした理論を読む時間がないという方へ。Ubuntu/Debian環境で迅速に設定するための4ステップを紹介します。
ステップ 1: PAM Google Authenticatorライブラリのインストール
sudo apt update
sudo apt install -y libpam-google-authenticator
(CentOS Stream、RHEL、AlmaLinuxの場合は、EPELリポジトリを有効化してインストールします: sudo dnf install -y epel-release && sudo dnf install -y google-authenticator)
ステップ 2: シークレットキーの生成とリカバリーコードの保存
普段SSHログインに使用している一般ユーザーで初期設定コマンドを実行します(rootでの実行は避けてください):
google-authenticator
ターミナルに確認プロンプトが順次表示されるので、以下のように回答します:
Do you want authentication tokens to be time-based (y/n): y- スマートフォンのGoogle Authenticator、2FAS、Bitwardenなどのアプリを開き、画面に表示されたQRコードをスキャンします。
- 表示された5つのemergency scratch codes(8桁の緊急リカバリーコード)を、1Password、Bitwarden、社内Vaultなどに直ちに保存してください。スマートフォンを紛失した場合、これが唯一の復旧手段となります。
Do you want me to update your "~/.google_authenticator" file? (y/n): yDo you want to disallow multiple uses of the same authentication token? (y/n): y(リプレイ攻撃を防止します)。By default, a new token is generated every 30 seconds... Increase window? (y/n): n(サーバーのクロックドリフトが頻発する場合は y を選択)。Do you want to enable rate-limiting? (y/n): y(30秒間に最大3回までのログイン試行に制限します)。
ステップ 3: PAM(Pluggable Authentication Module)の設定
SSHのPAM設定ファイルを開きます:
sudo nano /etc/pam.d/sshd
ファイルの末尾に以下のディレクティブを追加します:
auth required pam_google_authenticator.so nullok
nullokフラグを付与することで、まだOTP設定を完了していないユーザーも通常のSSHログインが継続できます。この記述がない場合、チームメンバーが即座にサーバーから締め出されてしまうため注意してください。
ステップ 4: SSHデーモンの設定更新とサービスの再起動
SSHサーバーの設定ファイルを開きます:
sudo nano /etc/ssh/sshd_config
以下の2つのパラメータを確認して有効化します(行頭に # がある場合は削除してコメントアウトを解除):
KbdInteractiveAuthentication yes
UsePAM yes
注意: Ubuntu 20.04以前などの古いディストリビューションでは、このディレクティブは ChallengeResponseAuthentication yes という名称になっています。
サービスを再起動する前に、設定のシンタックスチェックを実施します:
sudo sshd -t
sudo systemctl restart sshd
最重要ポイント: 現在接続中のSSHセッションは絶対に閉じないでください!別のターミナルタブを開いて新規にSSH接続を試み、Verification code を要求されるか確認します。正常にログインできることを確認してから、元のセッションを閉じるようにしてください。
詳細解説: 内部の動作メカニズム
PAMとSSHはどのように連携しているか?
OpenSSH自体が直接OTPの計算処理を行うわけではありません。代わりに、ユーザー認証の処理全体をPAMシステムに委任しています。処理フローは以下のとおりです:
- クライアントがサーバーに対してSSH接続リクエストを送信。
sshdが設定を検証し、KbdInteractiveAuthenticationフラグを検知すると/etc/pam.d/sshdに定義されたPAMモジュールへ認証処理を委譲。- PAMが
pam_google_authenticator.soライブラリを呼び出す。 - 該当ライブラリがユーザーのホームディレクトリ配下にある
~/.google_authenticatorからシークレットキーを読み込み、TOTPアルゴリズム(RFC 6238)を適用。 - サーバーが現在のタイムスタンプをもとにOTPを算出し、ユーザーが入力した6桁の数値と照合。一致すれば接続セッションが承認される。
なぜSSH鍵認証だけでは不十分なのか?
エンジニアの間ではよく、「Ed25519やRSA 4096-bitのSSH鍵を使っていれば総当たり攻撃は不可能だし、わざわざ面倒な2FAを導入する必要はないのでは?」という声が聞かれます。
しかし、問題の本質は暗号化アルゴリズムの強度ではなく、ローカルの作業環境に潜むリスクにあります。作業用PCがマルウェアに感染して鍵ファイルを盗まれたり、パブリックリポジトリに誤って秘密鍵をコミットしてしまったり、暗号化せずにGoogle Drive等へバックアップしてしまったりすれば、サーバーは一瞬で危険に晒されます。そこで2FAが第2の物理的な防壁として機能します。攻撃者が秘密鍵を手に入れたとしても、手元のスマートフォンにある30秒間有効なワンタイムパスワードがなければ侵入することはできません。
高度な設定: SSH鍵認証「かつ」2FAを必須にする
デフォルトでは、有効なSSH鍵が提示されるとOpenSSHはOTPを要求せずにそのままログインを許可してしまいます。セキュリティポリシーを厳格化し、「有効なSSH鍵認証」と「正しい6桁のOTP入力」の両方を必須化するには、多段階認証チェーンを構成します。
/etc/ssh/sshd_config を編集します:
sudo nano /etc/ssh/sshd_config
ファイルの末尾に以下の順序で認証方式を定義します:
AuthenticationMethods publickey,keyboard-interactive
この設定により、クライアントはまず公開鍵認証をパスし、その後にOTP入力ステップを通過することが強制されます。
続いて、Linuxユーザーのパスワード入力をスキップするよう /etc/pam.d/sshd を調整します:
sudo nano /etc/pam.d/sshd
@include common-auth(RHEL/AlmaLinuxの場合は auth substack password-auth)の行頭に # を追加してコメントアウトします:
# @include common-auth
auth required pam_google_authenticator.so
これにより運用体験が格段にスムーズになります。SSHコマンドを実行 → サーバーが自動的に秘密鍵を検証 → ターミナルに Verification code: が表示される → 6桁のOTPを入力するだけでシェルに直接アクセスでき、Linuxアカウントのパスワードを都度入力する煩わしさがなくなります。
本番運用の修羅場から得た実践Tips
30名以上のエンジニアチームに2FAを展開した経験から、現場で極めて重要となる4つのプラクティスをまとめました:
1. 時刻同期(NTP)の維持は絶対条件
TOTPは30秒の固定サイクルに基づいて計算されます。サーバーのハードウェアクロックが標準時(UTC)から30秒以上ドリフトすると、アプリ上で正確に入力していてもすべてのOTPが拒絶されてしまいます。作業着手前に必ず時刻同期サービスの状態を確認してください:
timedatectl status
NTP service: active かつ System clock synchronized: yes になっていることを確認してから設定を進めましょう。
2. ロールアウト初期は最低1週間 nullok を維持する
導入初日に焦って nullok フラグを削除してはいけません。auth required pam_google_authenticator.so nullok の状態を約7日間維持することをお勧めします。この猶予期間を設けることで、日常業務を止めることなくチームメンバー各自が都合の良いタイミングでOTPの初期設定を完了できます。/home/ 配下の全ユーザーが設定ファイルを生成したことを確認した段階で nullok を外し、完全にロックダウンします。
3. オフィスネットワークやVPN向けの2FA免除設定
1日に数十回もOTP入力を求められると、エンジニアの生産性が低下し、回避策を探し始める原因になります。固定グローバルIPや社内VPN(WireGuard、Tailscaleなど)を運用している場合は、それらのIPレンジをホワイトリスト化できます。/etc/ssh/sshd_config の末尾に以下のブロックを追加します:
Match Address 192.168.1.0/24,10.8.0.0/24
AuthenticationMethods publickey
Match Address *
AuthenticationMethods publickey,keyboard-interactive
オフィス勤務時やVPN接続時はSSH鍵のみで即座にログインでき、カフェや未知のネットワークからの接続時には即座にOTP認証が要求されるセキュアかつ柔軟な構成が実現します。
4. 緊急スクラッチコードの確実な管理運用
初期セットアップ実行時に、システムは使い切りのバックアップコードを5つ発行します。これを必ず社内の共有シークレット管理ツールに保存するよう周知徹底してください。スマートフォンが水没したり、2FAの移行を行わずに機種変更してしまったりした場合でも、この数行のバックアップコードがあれば、クラウド事業者のWebコンソールからレスキューモードでディスクをマウントするような事態を回避できます。

