WPA2/WPA3 Enterpriseの無線LANで、ID/パスワード認証を使うときは、サーバ認証を行うことが必須または強く推奨されています。
具体的には、EAP-TTLSを使う場合はサーバ認証が必須で、PEAPでもMSCHAPv2のセキュリティが弱いのでサーバ認証が強く推奨されています。詳しくは以前の記事をご覧ください。
※ タイトルにある組み合わせ、それなりに長いこと運用していますが、もし動かなくなったらごめんなさい。
サーバ認証で使うべき証明書
EAP-TTLSやPEAPでは、基地局に端末を接続しようとする際に、まずサーバ認証を行って、これから接続しようとする基地局が正規のものかを確認します。基地局そのものの真贋を確認するのは無理なので、実際は、基地局が正しい認証サーバ (AAAサーバ)につながっているかどうかを確認します。ここで、公開鍵基盤 (PKI, 必ずしも一般公開とは限らない) の電子証明書が使われます。利用者認証が行われるのは、サーバ認証に成功した後です。
利用者認証、というか正確には端末認証を実施するEAP-TLSでは、ID/パスワードの代わりにクライアント証明書が使われます。これは、サーバ認証とは異なるものです。
「サーバ認証用の証明書を取得してRADIUSサーバに導入しろと言われても、どうすればいいの?」
「証明書は買わないといけないの?」
FreeRADIUSの場合、インストールすると自動的に /etc/raddb/certs の下にデモ用の証明書が作成されます。サーバ認証関係の設定は /etc/raddb/mods-available/eap というファイルに書かれています。初期状態ではデモ証明書が使われます。RADIUS proxyとして動作させるだけならこのままでもよいのですが、認証を行う RADIUS IdP として使うなら、デモ証明書を使い続けてはいけません (そもそも60日で期限切れになる)。
certs ディレクトリの中にある設定ファイル ca.cnf と server.cnf を自分のサーバに合うように修正して、証明書を作り直せば、プライベートなPKIとして運用することが可能です。
Enterpriseな無線LANで、できるだけセキュリティを高めたいなら、プライベートCAで発行した証明書を使うのがよいでしょう。ただし、個々の端末にCA証明書をインストールする手間があります。企業などで MDM (Mobile Device Management) を使うならよいのですが、利用者個人が無線LANの接続設定を行う企業やキャンパスの無線LANでは、採用しにくいかもしれません。端末にCA証明書を導入する操作は、セキュリティリスクもあるので、個人に任せるのは少し不安です。
グローバルなパブリックCAを使うのはどうでしょう?
端末には著名なCA証明書がプリインストールされているので、CA証明書を追加でインストールする手間 (とリスク) がなくなります。ただし、同じCAを使う第三者のRADIUSサーバを正規のものと認識しては危険なので、ドメイン名を確実に確認する必要があります。つまり、サーバ証明書の発行の際に、ドメイン名と所有者が紐づけられているところに、信頼が生じるという仕組みです。
Let's Encryptの証明書でも大丈夫か
Let's Encryptでもドメイン名のチェックはできているので、Let's Encryptで取得したサーバ証明書をRADIUSで使っても、大丈夫でしょう。Androidで無線LANの設定をするときに、CA証明書で「システム証明書を使用」を選び、ドメインを入力するだけという、お手軽設定になります。
FreeRADIUSの設定方法
Let's Encryptのサーバ証明書の取得は、ウェブサーバ向けの設定ガイドが多数存在するので、そちらをご覧ください。certbotが少しずつ変化しているので、できるだけ新しい記事を探すとよいです。
FreeRADIUSですが、現在の最新版 3.2.0 と、一つ前の 3.0.25 で確認しています。3.0.x 系には、TLS接続が不安定になる致命的な不具合があります。3.2.0 以上を使うべきです。
サーバ証明書の設定は mods-enabled/eap の、tls-config tls-common セクションにあります。
private_key_password = は、たぶん空でよいはず (Let's Encrypt次第)。
private_key_file = には、privkey.pem を指定します。
certificate_file = には、cert.pem を指定します。
ca_file = には、chain.pem を指定……、アレ?
We've got a problem!
Thu Jul 7 13:55:35 2022 : Auth: (31) Login incorrect (eap_peap: (TLS) Alert read:fatal:certificate expired): ...
ど、どうして……
当エントリを起こそうと思い立った理由がこれです。
chain.pem には、CA証明書と中間CA証明書のチェーンが含まれているのが普通です。執筆時点で、chain.pem には2つの証明書が含まれていて、先頭から、中間CA証明書 (CN= R3)、ルートCA証明書らしきもの (CN= ISRG Root X1) です。後者が曲者で、2021年9月に破棄された古い証明書 (CN= DST Root CA X3) で署名されていました。
Apache HTTP Serverに仕込んで、ブラウザで証明書の情報を見ると、ISRG Root X1 が新しく自己署名証明書になっているのが分かります。
というわけで、chain.pem の先頭にある R3 の証明書だけ残して、後半を新しい方に差し替え、これを ca_file に設定します。
今度は無事に動きました (゚∀゚)
めでたし めでたし
余談
EAP-TLSでは、サーバ認証とクライアント認証で、異なるPKIを使うことができます。というか、クライアント認証にパブリックCAを用いるのは、セキュリティ的に問題があります。mods-enabled/eap 内に(ちょっと不親切な)コメントがあります。
従って、選択肢は二つ。
- サーバ認証とクライアント認証、両方にプライベートCAを用いる。
- サーバ認証にパブリックCA、クライアント認証にプライベートCAを用いる。
運用コスト次第ですが、後者も妥協点として悪くないようです (とある識者の技術指導 より)。
certbot 1.6以上には --preferred-chain "ISRG Root X1" なるオプションがあるそうで、これでもいけるかな?