hgot07 Hotspot Blog

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

RADIUSサーバをRadSecでつないでみよう! (FreeRADIUS編)

RADIUSをいじっている人もそうそういないと思いますが(?)、そのせいで新しい情報があまり出回っていないので、ちょっと書いてみます。(自分のための備忘録ですよ、そうですよ)

RADIUSプロトコルでは、通常1812/udp (認証), 1813/udp (アカウンティング)が使われるのですが、RadSecというトランスポートもあります。FreeRADIUSでRadSecを使ってみようという話です。

ポイント

  • 素のRADIUSではUDPを使うため、証明書を使うEAP-TLSなどでパケットが大きくなると、Fragmentationで不安定になることがある。
  • 普通のRADIUSでは送信元・送信先ともIPアドレスの変更に対応しにくい。
  • RadSecはRADIUSの通信を安全・安定にしようとするトランスポートで、RADIUS over TLS (RFC 6614) の実装。
  • RadSecでは標準で2083/tcpが使われ、証明書で接続相手を認証するのが一般的。IPアドレスの変更にも柔軟に対応できる。
  • Dynamic Peer Discovery (RFC 7585)と組み合わせると、IDプロバイダ(IdP)のサーバと直接接続して認証連携もできる。(FreeRADIUS 3.0.21では未対応。当記事では書かない)

 

RadSecに対応したRADIUSサーバ

RadSecに対応したRADIUSサーバには、FreeRADIUSやRadiatorなどがあり、プロキシのみの機能ならばradsecproxyがあります。

執筆時点(2020/6/29)のFreeRADIUSのバージョンは3.0.21ですが、今回はこれを使って二拠点間でRadSec接続を実現してみます。

 

FreeRADIUSのデモ用証明書を作り直す

世の中のSIerには、どういうわけかLinuxディストリビューションに付属のパッケージを使いたがるところが少なくないようです。しかし、パッケージだからといって安定しているとは限りません。特にFreeRADIUSの場合、古いバージョンでは幾つか致命的なダメ仕様やバグを抱えているものがあるので、最低でも3.0.19以降を使うべきです

さて、なーんも考えないでFreeRADIUSをソースからビルド、インストールすると、デモ用の証明書群が自動的に作成されます。標準的には /etc/raddb/certs の中に置かれるのですが、インストール先が別の所にある場合は、適宜読み替えてください。

この証明書群、RADIUS proxyの場合はこのままでもよいのですが、IdPになるサーバの場合は、まともなサーバ証明書を入れるべきです。デモ用はCA証明書でさえ60日間しか有効ではないので、とりあえず、全部作り直しましょう

certsディレクトリの中にあるREADMEは、本当に有用なことが書かれているので、ぜひ読みましょう。まずcertsの中にcdして、設定ファイル *.cnf の中身を自サイトに合わせて書き換えましょう。続いて、READMEのとおり以下のコマンドを打ち込み、期限切れになっている証明書をすべて削除の上で、新しく作り直しましょう。

# rm -f *.pem *.der *.csr *.crt *.key *.p12 serial* index.txt*
# make

おっと、まだ説明していませんでした。

無線LANサービスプロバイダ(SP)側で、基地局を収容しているRADIUS proxyとして動作するホストをHost1とします。

SPから認証要求を受け取って認証処理を行う、IdP側のホストをHost0とします。Host0は、中間proxyの場合もあるでしょう。

今回、Host0が証明書発行の主体となり、Host1に対してRadSec用のクライアント証明書を発行することにします。両ホストで、正しく本番用の証明書が作られている必要があります。

 

RadSec接続用のクライアント証明書を作成する

RadSecの接続に必要なクライアント証明書を作成する手順は以下のとおりです。

Host1 (SP側)でクライアント証明書のCSRを作る

Host1のFreeRADIUSの証明書ディレクトリ (標準では/etc/raddb/certsにある) の中で、次のようにしてクライアント証明書を発行依頼するためのCertificate Signing Request (CSR)を作成します。出来上がったCSRファイル (client1.csr) をHost0に持っていきます (Host0の管理者に渡します)。

# cp client.cnf client1.cnf
(client1.cnfを適宜編集)
# openssl req -new -out client1.csr -keyout client1.key -config ./client1.cnf

Host0 (IdP側)でクライアント証明書を発行する

Host0の管理者は、FreeRADIUSの証明書ディレクトリ (標準では/etc/raddb/certsにある) の中で、受け取ったCSRを元に、次のようにしてクライアント証明書を作成します。Host1用の client-for1.cnf ファイルを先に作成しておきます。出来上がった証明書ファイル (client1.crt) と、自己のCA証明書 (ca.pem) を、Host1に送ります。-keyに書くパスワードは、もちろんHost0のCA証明書のものです (Host1の方を知っているはずないので)。また、Host1のCA証明書と紛れないように、別名のファイル (ca0.pem) にコピーしてから渡すとよいでしょう。

# cp client.cnf client-for1.cnf
(client-for1.cnfを適宜編集)
# openssl ca -batch -keyfile ca.key -cert ca.pem -in client1.csr \
-key whatever -out client1.crt -extensions xpclient_ext \
-extfile xpextensions -config ./client-for1.cnf
# cp ca.pem ca0.pem

Host1 (SP側)でクライアント証明書を変換する

FreeRADIUSでは .crt のままでも使えますが、ついでなのでPEM形式も作っておきましょう。

Host1で、受け取ったクライアント証明書 (client1.crt) を元に、次のようにしてPEM形式のクライアント証明書を作成します。パスワードは二つとも自分の client1.cnf の中に書いたものです。

# openssl pkcs12 -export -in client1.crt -inkey client1.key \
-out client1.p12 -passin pass:whatever1 -passout pass:whatever1
# openssl pkcs12 -in client1.p12 -out client1.pem \
-passin pass:whatever1 -passout pass:whatever1

 

FreeRADIUSの設定

Host1側の設定

現在、FreeRADIUSのRadSecサポートは未熟な感じで、設定ファイルも十分に整理されていない印象です。認証要求を送り出す側であるHost1でRadSecに関係するファイルは、proxy.confとsites-available/tlsの二つです。とりあえずバックアップを作成しておくのが良いでしょう。

sites-enabledの中から、sites-available/tlsシンボリックリンクを張ることで、このファイルの内容が有効になります。

# (cd sites-available; cp -p tls tls.orig)
# cd sites-enabled
# ln -s ../sites-available/tls

ファイルtlsを編集します。

home_server tls {...} というセクションを見つけて、その部分を丸っとコピーします。例えば、サーバ名をHost0に変更しておきます。冒頭はこんな感じです。

home_server Host0 {
ipaddr = <Host0のIPアドレス>
port = 2083
type = auth
secret = radsec # 通常は"radsec"のまま使う
proto = tcp
status_check = none

続いてtls {...}というセクションがあるので、この中にある証明書関係の変数を以下のように変更します。

private_key_password = whatever1  # 自分のclient1.cnfに書いたもの。
private_key_file = ${certdir}/client1.key # Host1で作成したもの。

certificate_file = ${certdir}/client1.pem
# Host0から受け取って変換したもの。.crtのままでもよい。

ca_file = ${cadir}/ca0.pem # Host0から受け取ったもの。

home_server_poolを定義します。

home_server_pool Host0-pool {
type = fail-over
home_server = Host0 # home_serverを多重化した場合は複数行並べる。
}

あとは、proxy.conf を編集して、必要なものをHost0-poolに飛ばすように設定します。要するに、普通はproxy.confの中にあるhome_serverの設定が、RadSecではtlsファイルの中にあるということです。設定を有効にするために、radiusdをリスタートしておきます。

 

Host0側の設定

認証要求を受信するHost0でRadSecに関係するファイルは、sites-available/tlsだけです。とりあえずバックアップを作成しておくのが良いでしょう。

# (cd sites-available; cp -p tls tls.orig)
# cd sites-enabled
# ln -s ../sites-available/tls

ファイルtlsを編集します。listen {...}セクションの中にtls {...}セクションがありますが、Host0ではすべて自前の証明書をそのまま利用するので、変更不要です。(server.cnfをいじっている場合はprivate_key_passwordの変更を忘れずに)

clients radsec {...} セクションの中に、127.0.0.1の設定があります。この下に、Host1からの接続を受け入れる設定を追加します。

client Host1 {
ipaddr = <Host1のIPアドレス または *>
proto = tls
secret = radsec # Host1の設定に合わせるが、通常は"radsec"のままでよい。
}

Host1から2083/tcpが届くように、Firewallの設定を忘れずに。設定を有効にするために、radiusdをリスタートしておきます。

 

おわりに

あとは、Host1からradtestなどで認証が通ることを確認すれば終わりです。実は、FreeRADIUSのRadSec関係のエラー表示が不親切で、というかopensslライブラリのせいなんでしょうが、トラブルシューティングが面倒という問題があります。Good luck!

通常の用途でRadSecの有難味を感じることはほとんどないと思いますが、それなら、試しにHost0で ipaddr = * に設定の上、Host1のIPアドレスを変化させてみたらどうでしょう。これで、基地局側のシステムは、どこからでもRADIUSクライアントになれるんですよ(・∀・)ノ

(まぁ、汎用のVPNでもできるんですけどね……)

 

おわり