hgot07 Hotspot Blog

主に無線LANや認証連携などの技術についてまとめるブログです。ネコは見る専。

FreeRADIUSでLet's Encryptの証明書を使う

WPA2/WPA3 Enterpriseの無線LANで、ID/パスワード認証を使うときは、サーバ認証を行うことが必須または強く推奨されています。

具体的には、EAP-TTLSを使う場合はサーバ認証が必須で、PEAPでもMSCHAPv2のセキュリティが弱いのでサーバ認証が強く推奨されています。詳しくは以前の記事をご覧ください。

hgot07.hatenablog.com

※ タイトルにある組み合わせ、それなりに長いこと運用していますが、もし動かなくなったらごめんなさい。

 

サーバ認証で使うべき証明書

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 に設定します

今度は無事に動きました (゚∀゚)

[2024/4/8修正] ……だったのですが、その後にeduroamでも色々と知見が共有されるようになって、中間CA証明書はサーバ証明書と組み合わせるべきという話になりました。具体的には、以下のようにします。

 

private_key_password = "" つまり空にする。

private_key_file = には、privkey.pem を指定する。

certificate_file = には、cert.pem と中間CA証明書(ISRG Root X1で署名されたR3)を連結したものを指定する。

ca_file = には、ISRG Root X1 だけを指定する。

 

中間CA証明書が複数になるケースも考えたら、サーバ証明書と紐づく中間CA証明書を一緒にクライアントに送るのは理にかなっています。

 

めでたし めでたし

 

余談

EAP-TLSでは、サーバ認証とクライアント認証で、異なるPKIを使うことができます。というか、クライアント認証にパブリックCAを用いるのは、セキュリティ的に問題があります。mods-enabled/eap 内に(ちょっと不親切な)コメントがあります。

従って、選択肢は二つ。

運用コスト次第ですが、後者も妥協点として悪くないようです (とある識者の技術指導 より)。

 

certbot 1.6以上には --preferred-chain "ISRG Root X1" なるオプションがあるそうで、これでもいけるかな?