Google Authenticatorを使ったLinux SSHの二要素認証(2FA/MFA)設定ガイド

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

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): 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... 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システムに委任しています。処理フローは以下のとおりです:

  1. クライアントがサーバーに対してSSH接続リクエストを送信。
  2. sshd が設定を検証し、KbdInteractiveAuthentication フラグを検知すると /etc/pam.d/sshd に定義されたPAMモジュールへ認証処理を委譲。
  3. PAMが pam_google_authenticator.so ライブラリを呼び出す。
  4. 該当ライブラリがユーザーのホームディレクトリ配下にある ~/.google_authenticator からシークレットキーを読み込み、TOTPアルゴリズム(RFC 6238)を適用。
  5. サーバーが現在のタイムスタンプをもとに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コンソールからレスキューモードでディスクをマウントするような事態を回避できます。

Share: