ちょっと話題の記事

セキュアな時刻同期Network Time Security(NTS)をOpenWRTルーターに設定する

2024.01.09

ども、大瀧です。 NTPにセキュリティ機能を追加したNTSという時刻同期サービスを知っていますか。本ブログではルータ向けLinuxディストリビューションOpenWRTで時刻同期にNTSを構成する様子をご紹介します。

動作確認環境

  • ハードウェア: GL-iNet GL-MT2500 ファームウェア 4.5.0release6(rc)
  • OpenWRT: バージョン21.02
  • Chrony: バージョン4.1-2
  • NTS公開サーバー: time.cloudflare.com

time.cloudflare.com とは

time.cloudflare.comはNTSに対応するCloudflareの公開タイムサーバーです。以下のブログで紹介されてます。

その後RFC8915の策定に合わせてポート番号を変更したとのブログが以下です。

AWSの公開NTPサーバーにも接続を試行してみましたがエラーになったので、NTSには未対応のようでした。

OpenWRTのNTS構成

今回の環境ではbusybox-ntpdで時刻同期するのが既定でしたが、busybox-ntpdはNTSをサポートしないため今回はChronyを選択します。OpenWRTのChronyパッケージはchronychrony-ntsの2つがありますが、chrony-ntsNTSを有効化してコンパイルしたバイナリを含むパッケージchronyパッケージとは排他関係という点に注意が必要です。chrony-ntsのみインストールします。

まずは /etc/config/system を編集してbusybox-ntpdを無効化します。

/etc/config/system

config system
	option log_size '64'
	option urandom_seed '0'
	option compat_version '1.0'
	option ttylogin '1'
	option zonename 'UTC'
	option hostname 'takipone_router'
	option log_proto 'udp'
	option conloglevel '8'
	option cronloglevel '10'

config timeserver 'ntp'
	option enabled '0'
# /etc/init.d/sysntpd restart

続いてchrony-ntsパッケージをインストールします。

# opkg install chrony-nts
Installing chrony-nts (4.1-2) to root...
Downloading https://fw.gl-inet.com/releases/v21.02.3/packages-4.0/aarch64_cortex-a53/packages/chrony-nts_4.1-2_aarch64_cortex-a53.ipk
Configuring chrony-nts.
Updating database.
Database update completed.
#

では、ChronyのNTPクライアントにtime.cloudflare.comを設定しましょう。serverディレクティブのhostnameオプションにセットし、ntsオプションを付加して値yesを設定します。

/etc/config/chrony

config server
	option hostname 'time.cloudflare.com'
	option maxpoll '12'
	option iburst 'yes'
	option nts 'yes'

config dhcp_ntp_server
	option iburst 'yes'
	option disabled 'no'

config allow
	option interface 'lan'

config makestep
	option threshold '1.0'
	option limit '3'

config nts
	option rtccheck 'yes'
	option systemcerts 'yes'

これでOKです。Chronyを再起動し、NTSの認証情報を表示するchronyc authdataコマンドとタイムサーバーの状態を表示するchronyc sourcesコマンドで確認してみます。

# /etc/init.d/chronyd restart
# chronyc authdata
Name/IP address             Mode KeyID Type KLen Last Atmp  NAK Cook CLen
=========================================================================
time.cloudflare.com          NTS     1   15  256  11h    0    0    8  100
# chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* time.cloudflare.com           3   6    77    25    -35us[-1333us] +/-   64ms
#

NTSの認証に成功し、正常に時刻同期している様子がわかりますね。

ちなみに今回のハードウェアにはRTC(リアルタイムクロック)が搭載されていないため、ルーターの再起動時に時刻が保持されず次回起動時のNTS-KEでサーバー証明書の検証に支障があるかなと思ったのですが、システムログを見る限りdriftファイルでリカバリして正常に起動できている感じが見えました。

Mon Jan  8 12:55:47 2024 daemon.info chronyd[13226]: Frequency -248.761 +/- 1.271 ppm read from /var/run/chrony/drift

おまけ: serverとpoolの選択

Cloudflare公開タイムサーバーは、DNSでIPv4とIPv6にそれぞれ2つずつ、計4つのIPアドレスを返してきます。

# host time.cloudflare.com
time.cloudflare.com has address 162.159.200.123
time.cloudflare.com has address 162.159.200.1
time.cloudflare.com has IPv6 address 2606:4700:f1::1
time.cloudflare.com has IPv6 address 2606:4700:f1::123
#

Chronyには、NTP Pool Project向けに複数のNTPサーバーを設定するpoolディレクティブがあるので、serverディレクティブの代わりにpoolディレクティブが有効なのか考えてみました。

NTP PoolはDNSで複数のNTPサーバーのIPアドレスを返しpoolディレクティブはそれを簡便に構成するためのディレクティブで、ChronyはそれらのNTPサーバーからNTPのレスポンスを評価して近くて安定したNTPサーバーを選択します。対してCloudflare公開タイムサーバーはIP AnycastによってNTPクライアントに近いタイムサーバーが常にNTPクライアントに向くため、Cloudflare公開タイムサーバーの中からNTPサーバーを選択するのはあまり意味がなさそうです。

一方、ChronyによるNTPサーバーの死活判定はserver/poolディレクティブを問わずDNS名前解決の結果のIPアドレスごとに行います。上記のようにCloudflare公開タイムサーバーをセットしたserverディレクティブ1つの設定だけでも、返ってくるIPアドレスそれぞれを死活判断し正常なNTPサーバーを利用することを期待できます。以上から、今回はpoolディレクティブではなくserverディレクティブで支障なく運用できそうです。死活監視周りの解説は以下のブログが詳しいです。

どのIPアドレスを選択しているのかはchronyc-nオプション(ホスト名の代わりにIPアドレスを表示)やシステムログから見えます。

# chronyc -n sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* 2606:4700:f1::123             3   6    17    37   -642us[ -762us] +/-   64ms
#
Mon Jan  8 12:55:51 2024 daemon.info chronyd[13226]: Selected source 2606:4700:f1::123 (time.cloudflare.com)

ちなみに、NTSのクッキーファイルもIPアドレスごとに保存しているのが確認できます。

# ls /var/run/chrony/
162.159.200.1.nts    162.159.200.123.nts  2606:4700:f1::1.nts  chronyd.pid          chronyd.sock         drift
#

まとめ

NTSをサポートするCloudflare公開タイムサーバーをOpenWRTから利用する様子をご紹介しました。時刻同期はTLSを支える大事な技術要素だと思うので、セキュリティ対応ももしかしたら今後一般的になるかもしれないですね。

参考URL