0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

本記事の位置づけ

本記事は、FreeRADIUS MFA実装における秘密鍵管理の課題を明らかにするための技術検証レポートです。
記載されている手法②(秘密鍵の集約管理)は、セキュリティベストプラクティスに反するため、本番環境での採用を推奨しません
本番環境での実装を検討される場合は、手法④(マネージドMFAサービス)または手法③(Secrets Manager統合)の採用を推奨します。

はじめに

はじめまして。株式会社NTTデータ九州 ビジネス共創部 デジタルビジネス推進室 の永田です。
Amazon Web Services(AWS) を中心にパブリッククラウドの技術習得やデリバリー業務に励んでいます。

今回のブログでは、FreeRADIUS + PAM + Google Authenticator を使用した多要素認証(MFA) の実装と検証および学んだことについて紹介します。

FreeRADIUS + PAM + Google Authenticator の認証フロー

FreeRADIUSGoogle Authenticatorを用いた多要素認証のフローは次のイメージです。

認証の流れ.png

FreeRADIUSはADサーバー(MSAD)から認証リクエストを受信し、認証処理をPAM(Pluggable Authentication Modules) に移譲します。
すなわち、FreeRADIUS自体は認証を行わず、認証の仲介役として動作します。

PAMはユーザー認証方式を一元管理できます。
PAMの設定ファイルで認証方式を指定し、それに従って認証を行います。

Google AuthenticatorはPAMモジュールの一つで、ユーザーが入力したOTPコードを検証します。
OTPコードの検証では、~/.google_authenticator ファイルに保存された秘密鍵と照合を行います。

課題

先人のブログ記事等を参考に FreeRADIUS + PAM + Google Authenticator の構成で多要素認証を実装していたところ、
radiusdプロセスをrootユーザーで実行していることに気づきました。
root 実行の構成では、RADIUS サーバーの侵害が“単なる認証サーバ破壊”に留まらず、サーバ OS 全体および他サービスへの横展開につながる危険性があるため、まず実行権限の分離とアクセス制限の徹底が不可欠です。
今回の検証では、RADIUSサーバーをrootで実行せずradiusdユーザーで実行することを試みましたが、
Google AuthenticatorやPAMの仕様上の制約により、完全な権限分離とリスク低減は実現できませんでした

Google Authenticatorの仕様

  • 秘密鍵ファイル(/.google_authenticator)は、ユーザーのホームディレクトリ(/home/user/.google_authenticator)に所有者のみ読取り可能(権限600) で作成される
  • ゆえに他ユーザーから秘密鍵を参照できない設計
  • Google Authenticator は秘密鍵の作成先を変更するオプションがない

PAM認証フロー

  • RADIUSプロセス(radiusdとして起動)が認証リクエストを受信
  • PAMモジュールが呼び出し元プロセス(radiusd)の UID で実行される
  • PAMモジュールが「/home/{USER}/.google_authenticator」の秘密鍵を参照
  • 各ユーザーのホームディレクトリに配置された秘密鍵(600 権限)が参照できない

制約を踏まえた対応

上記の制約を回避するため、各ユーザーの秘密鍵をradiusdが参照可能なディレクトリへコピーする方法で検証しました。
※秘密鍵を集約したディレクトリは“単一障害点 (Single Point of Failure)” となり、RADIUS 侵害時に MFA 全体が機能を失う構造上の問題が残ります。

構築手順

今回はAmazonLinux2023上にRADIUSサーバーを構築します。

1. パッケージのインストール

FreeRADIUS


# AmazonLinux2023のリポジトリからFreeRADIUS構築に必要なパッケージをインストールする
$ dnf install freeradius freeradius-utils

# RADIUSサーバー起動時にFreeRADIUSを自動起動する設定を有効化する
$ systemctl enable --now radiusd

# radiusdを起動させる
$ systemctl start radiusd

Google Authenticator


# Google Authenticatorをインストールする
$ dnf install google-authenticator -y

RADIUSサーバー経由の認証許可


# RADIUSサーバー経由の認証許可のためのグループを作成する
$ sudo groupadd radius-enabled

2. FreeRADIUSの設定

ここからは、root以外のユーザーでFreeRADIUSを実行するための設定をします。

FreeRADIUS認証設定


# FreeRADIUS認証設定ファイルを開く
$ sudo vi /etc/raddb/users

次の設定を追記します。


# radius-enabled以外のグループの場合、認証を拒否
DEFAULT    Group != "radius-enabled", Auth-Type := Reject,Reply-Message = "Your account has been disabled."
# PAM認証を用いる
DEFAULT    Auth-Type := PAM

/etc/raddb/sites-available/default を編集


# /etc/raddb/sites-available/default を開く
$ sudo vi /etc/raddb/sites-available/default

PAM認証モジュールを利用するようコメントアウトを外します。


# 修正前
        #  Pluggable Authentication Modules.
#        pam
# 修正後
        #  Pluggable Authentication Modules.
        pam

Google Authenticatorの設定


# 設定ファイルを開く
$ sudo vi /etc/pam.d/radiusd

radiusdユーザーで実行するよう、次のように修正します。


#%PAM-1.0
#auth       include     password-auth
#account    required    pam_nologin.so
#account    include     password-auth
#password   include     password-auth
#session    include     password-auth
# radiusdユーザーで実行し、secretに設定された秘密鍵を参照する
auth required /usr/lib64/security/pam_google_authenticator.so user=radiusd secret=/var/lib/radiusd/auth-secrets/${USER}
account required pam_permit.so
session required pam_permit.so

本検証では秘密鍵の参照を次のように設定しました。


secret=/var/lib/radiusd/auth-secrets/${USER}

${USER}にはRADIUSサーバーへ多要素認証をリクエストしたユーザーIDが入ります。
この設定により、radiusdがユーザー毎の秘密鍵を参照することが出来ます。

  • RADIUSサーバーがプロトコルを受け付けるクライアントの設定

# 設定ファイルを開く
$ sudo vi /etc/raddb/clients.conf 

ファイルを開いたら、次の設定を追記します。
※x.x.x.x/xxには、MSADのNWアドレスを設定
※zzzzzzzには、任意のシークレットを入力する


client vpc {
        ipaddr = x.x.x.x/xx
        secret = zzzzzzz
}

PAMモジュールの有効化


$ sudo ln -s /etc/raddb/mods-available/pam /etc/raddb/mods-enabled/pam

証明書の発行


# 証明書期限を変更
$ vim /etc/raddb/certs/ca.cnf

ファイルを開いたら、次のように修正する。
※今回の検証では、証明書の有効期限を365日としています。


# 以下修正
default_days=365
default_crl_days=365

証明書を発行する。


# 証明書発行
$ /etc/raddb/certs/bootstrap

RADIUSサーバーを再起動する


$ sudo systemctl enable radiusd
$ sudo systemctl restart radiusd

3. 認証ユーザー設定

認証ユーザーを追加する

認証するユーザーを追加します。
※xxxxは任意の認証ユーザー


$ useradd -g radius-enabled xxxx

Google Authenticatorの起動

追加したユーザーのGoogle Authenticator を起動します。
※いくつか質問されるので、「y」を入力する


$ sudo -u xxxx /usr/bin/google-authenticator

秘密鍵のコピー


# 認証ユーザー(xxxx)の読み取り用ディレクトリを作成する
$ sudo mkdir /var/lib/radiusd/auth-secrets/xxxx

# google_authenticatorの秘密鍵をradiusdディレクトリ配下にコピーする
$ sudo cp /home/xxxx/.google_authenticator /var/lib/radiusd/auth-secrets/xxxx

# コピーしてきたディレクトリの所有者をradiusdに変更する
$ sudo chown radiusd:radiusd /var/lib/radiusd/auth-secrets/xxxx

# コピーしてきた秘密鍵の所有者をradiusdに変更する
sudo chown radiusd:radiusd /var/lib/radiusd/auth-secrets/xxxx/.google_authenticator

これにて、RADIUSサーバーの設定は完了になります。

実行結果

多要素認証が成功していることが確認できます。

認証結果.png

検証に対する評価

今回の検証を次のように評価しました。

権限分離の不完全性

先にも述べたように、本方式では次の問題が残ります。

懸念事項 内容 影響
秘密鍵の集約 全ユーザーの秘密鍵がradiusd配下に集約 radiusdユーザー侵害時に全秘密鍵が漏洩
鍵管理の煩雑化 鍵の更新時に手動コピーが必要 運用ミスのリスク増加
監査の困難性 radiusd 配下に集約した秘密鍵ディレクトリでは、個々の鍵の更新履歴を OS 標準機能で追跡できない インシデント調査の障害

評価

radiusd 実行によりプロセスサンドボックスを成立させることで、root実行と比べてOS全体の即時掌握は予防できたが、
本方式ではradiusdがsecretsを全て保持するため、radiusd 配下のキー漏洩によるMFA破りには脆弱さが残りました。

その他多要素認証実現手法との比較

その他の手法とも比較をしました。

手法1:AWS Secrets Manager / Systems Manager Parameter Store 統合

概要
秘密鍵をSecrets Managerに保管し、認証時にAPIで取得する。

技術的な実現可能性
PAMモジュールをカスタマイズし、以下の流れを実装する。

  1. 認証リクエスト受信
  2. AWS APIで秘密鍵取得(IAMロールで権限制御)
  3. メモリ上で検証
  4. 即座に破棄

課題

  • PAMモジュールのカスタム実装が必要(高難度)
  • ネットワーク遅延
  • AWSサービス依存

評価
Secrets Managerに鍵を保管するため、radiusdユーザーを奪取されたとしても秘密鍵が漏洩することは無くなります。
※IAMロールで権限制御するため、radiusdユーザーを奪取しただけでは秘密鍵にアクセスすることが出来ない。
また、秘密鍵の二重管理も無くなり、運用コストや運用ミスを低減することが出来ます。
しかし、カスタム PAM モジュールの実装難易度はかなり高く、C言語での開発 + PAM APIの理解が必要になります。
また、AWSサービス依存になるため、別のCSP(Cloud Service Provider) へ乗り換えする際に再度手法を検討し直す必要があります。

手法2:認証基盤ツールでの比較

具体的な選択肢

  • Microsoft Entra MFA
  • Okta

コスト比較

方式 初期費用 月額運用費(100ユーザーー想定)
自前RADIUS EC2 t3.small: ~$15
Microsoft Entra ID P1 $600 ($6/user)
Okta Workforce Identity $200-400 ($2-4/user)

※金額は目安になります。

評価

手法2の場合、秘密鍵の管理自体不要になるため、今回の方式で残存する脆弱性に対しても対応できます。
手法1と比較した場合、手法2は開発コストが比較的小さく、AWSサービス依存性も無くなります。
しかし、手法2ではライセンスのランニングコストが発生します。
※ユーザー数が多くなると、ランニングコストの差が大きくなります

まとめ

本記事では、FreeRADIUS + PAM + Google Authenticator を使用した多要素認証を実装し、rootユーザーではなくradiusdユーザーで実行する手順をまとめました。
その他手法と比較すると、以下表にまとめられます。

手法 影響範囲 導入コスト 運用コスト
①FreeRADIUS + PAM + Google Authenticator(実行ユーザー:root) 影響:大(システム全体)
②FreeRADIUS + PAM + Google Authenticator(実行ユーザー:radiusd) 影響:中(radiusdユーザー権限範囲、全秘密鍵漏洩) 小~中
③AWS Secrets Manager / Systems Manager Parameter Store 統合 影響:小~中(radiusdユーザー権限範囲、IAMロール)  中(AWSサービス利用料が追加)
④認証基盤ツール統合(Microsoft Entra MFA、Oktaなど)  影響:小(radiusdユーザー権限範囲) 小 

手軽に多要素認証を実装したい場合は①②を検討できますが、②はRADIUSプロセスが侵害された場合のOS影響範囲を限定できる点において優れています。
しかし、認証ユーザーにsudo権限を与えている場合、①と同様の影響範囲になるため、最小権限の原則を遵守する必要があります。
また、発見的統制の観点でradiusdユーザーが奪取されたことを検知できるよう監視機能等を追加することも有効です。

③は開発難易度が高く、IAMロールに過剰に権限を与えた場合など、別のレイヤーの権限コントロールも十分に検討する必要があるため、特別な理由がある場合を除いて、採用しづらい方式ではないでしょうか。

④は他の方式と比較してランニングコストはかかりますが、①~④の中では最も影響範囲が狭く、鍵の漏洩の心配もありません。
ただし、ユーザー数の増加に比例してランニングコストが増えるため、ユーザー数が多い場合には事前にランニングコストを試算することをお勧めします。

今回はFreeRADIUS + PAM + Google Authenticator構成の多要素認証を構築し、RADIUSプロセスが侵害された場合のOS影響範囲を限定できました。
しかし、今回検証した方式には脆弱性が残っており、本番システムへ適用できる方式ではないことが分かりました。
引き続き、セキュアに多要素認証を実装する方式を検討していきます。

執筆日・免責事項

この記事は2025年11月時点の情報に基づいて作成しています。
記載されているサービスの仕様や画面は変更される可能性があります。
実際の利用にあたっては、最新の公式ドキュメントをご確認ください。

注意

本記事で紹介した方式・手順は、検証目的で行ったものです。
本記事の内容に基づいて実施した結果生じた、いかなる損害についても一切の責任を負いません。
本番システムへ採用する場合は、必ずセキュリティ専門家のレビューを受けることを推奨します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?