ちょっと話題の記事

Amazon Linuxにおけるシステム時計とNTP

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

よく訓練されたアップル信者、都元です。Amazon Linuxは初期状態でNTPによるシステムクロックの同期を行うようになっています。具体的には、ntpdがインストール済みで、自動起動もONになっています。

$ chkconfig --list ntpd
ntpd                0:off     1:off     2:on     3:on     4:on     5:on     6:off

その設定ファイルは/etc/ntp.confにありますが、このファイルを参照した所、これら4つのNTPサーバを利用して時刻同期を行っているようです。

server 0.amazon.pool.ntp.org iburst
server 1.amazon.pool.ntp.org iburst
server 2.amazon.pool.ntp.org iburst
server 3.amazon.pool.ntp.org iburst

NTP POOL PROJECT

これらのサーバは、NTP POOL PROJECTが提供する、タイムサーバの仮想クラスタです。ドメイン名にamazonが入っていますが、AWSが管理するタイムサーバではないことに注意が必要です。NTP POOL PROJECTは、世界中のサーバが参加する巨大なクラスタを作ることによって、数多くのクライアントから発せられる大量の時刻同期のリクエストに安定して動作するタイムサーバを提供することを目的としています。

このNTPプールを利用したい場合、通常は 0.pool.ntp.org 等の名前を利用しますが、OS等のソフトウェアベンダがデフォルト値として利用する名前は、vendor zoneという特別な名前を利用しなければならないことになっています。ドメイン名にamazonが入っているのはそのためです。また、NTP POOL PROJECTは、商用利用に際してそのベンダに対してコントリビューションを求めています。恐らくAWSもリソースまたは金銭等、何らかのコントリビューションをしているはずです。

というわけで、これらのドメイン名は、世界中のどこかのNTPサーバに繋がっています。試しに、時間隔を開けつつ何度かDNSにドメイン名を解決させてみましょう。色々なIPアドレスが返ってくるはずです。

実験1: 基本的な同期の動作確認

検証用のAmazon Linux 64bit 最新版 t1.micro を立ち上げます。後の検証のため、VPCのpublic-subnet内にインスタンスを立ち上げ、EIPを振っておきましょう。Security Groupは、22/tcpのみ開けておいてください。

まず、NTPのログ出力を調整しましょう。/etc/ntp.confを編集して、以下のようにしてください。これにより、/var/log/ntp.logにNTPの動作ログが出るようになります。

# Enable additional logging.
#logconfig =clockall =peerall =sysall =syncall
logconfig +clockall +peerall +sysall +syncall
logfile /var/log/ntp.log

続いてntpdをリスタートし、ログファイルをモニタします。さらに、10秒おきに現在時刻を出力します。

$ sudo /etc/init.d/ntpd restart
$ tail -f /var/log/ntp.log &
$ while :; do date '+%F %T' ; sleep 10 ; done

この状態のまま、もう一つコンソールを開いて、別のコンソールから時間変更してみます。まずは時計を5分進めてみました。

$ sudo date -s "`date --date '5 minutes' '+%F %T'`"

ちなみに、ずらしてみる時間は、1000秒(=16分強)を超えないようにしてください。ntpdは、1000秒以上のズレを検知した場合、単純なクロックの誤差ではなく、なにかもっとヤバいことが起きているのではないか、と判断し、同期をやめてしまいます。

モニタを見てみると、下記の11行目で時計が5分進んだことがわかります。

2013-03-08 05:14:10
2013-03-08 05:14:20
 8 Mar 05:14:26 ntpd[23025]: XXX.XXX.XXX.XXX 942a 8a sys_peer
2013-03-08 05:14:30
2013-03-08 05:14:40
2013-03-08 05:14:50
 8 Mar 05:14:53 ntpd[23025]: XXX.XXX.XXX.XXX 8014 84 reachable
 8 Mar 05:14:53 ntpd[23025]: XXX.XXX.XXX.XXX 941a 8a sys_peer
 8 Mar 05:14:54 ntpd[23025]: XXX.XXX.XXX.XXX 941a 8a sys_peer
2013-03-08 05:15:00
2013-03-08 05:20:10
2013-03-08 05:20:20
2013-03-08 05:20:30
2013-03-08 05:20:40
2013-03-08 05:20:50

ちなみに、ntpq -pコマンドで各タイムサーバの状況を確認できます。offsetを見ると、各タイムサーバと約300000ミリ秒=5分のズレがあることが分かります。

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 some.timesvr.aa XXX.XXX.XXX.XXX  2 u   47   64    1    7.996  -299906 299906.
 some.timesvr.bb XXX.XXX.XXX.XXX  2 u   44   64    3   10.339  -299910 299909.
 some.timesvr.cc XXX.XXX.XXX.XXX  2 u   13   64    3    8.415  -299906 299907.
 some.timesvr.dd XXX.XXX.XXX.XXX  2 u   12   64    7   22.161  -299907 299907.

このまましばらく待つ(15分程度掛かりました)と、ntpdのログが流れ、時刻が修正されたのが分かります。

2013-03-08 05:34:01
2013-03-08 05:34:11
2013-03-08 05:34:21
2013-03-08 05:34:31
2013-03-08 05:34:41
2013-03-08 05:34:51
 8 Mar 05:34:52 ntpd[23025]: 0.0.0.0 c612 02 freq_set kernel -318017.726 PPM
 8 Mar 05:34:52 ntpd[23025]: 0.0.0.0 c61c 0c clock_step -299.898849 s
 8 Mar 05:29:53 ntpd[23025]: 0.0.0.0 c618 08 no_sys_peer
 8 Mar 05:29:53 ntpd[23025]: XXX.XXX.XXX.XXX 8024 84 reachable
 8 Mar 05:29:53 ntpd[23025]: XXX.XXX.XXX.XXX 8024 84 reachable
 8 Mar 05:29:53 ntpd[23025]: XXX.XXX.XXX.XXX 8024 84 reachable
 8 Mar 05:29:54 ntpd[23025]: XXX.XXX.XXX.XXX 8024 84 reachable
2013-03-08 05:30:01
2013-03-08 05:30:11

ntpqで確認してみると、タイムサーバとのズレが数ミリ秒におさまっていることがわかります。ちなみに、最左にある記号は「タリーコード」と呼ばれ、*がついているのが現在同期しているサーバです。

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+some.timesvr.aa XXX.XXX.XXX.XXX  2 u    5   64    1   79.720    0.481   0.557
-some.timesvr.bb XXX.XXX.XXX.XXX  2 u    3   64    1    3.291    6.108   0.075
+some.timesvr.cc XXX.XXX.XXX.XXX  2 u    3   64    1   56.675   -1.760   0.075
*some.timesvr.dd XXX.XXX.XXX.XXX  2 u    3   64    1   34.801    1.629   0.085

実験2: Security GroupのOutboundを全て閉じてみる

ntpdは、タイムサーバの123/udpに対して通信をしています。従って、VPC Security GroupでのOutboundを閉じてしまうと、時刻の同期ができなくなるはずです。その設定をしてみてください。(設定後は、SSHの再接続が必要かもしれません)

no outbound

その上で同様にモニタを始め、今度は時計を5分遅らせてみましょう。

$ sudo date -s "`date --date '5 minutes ago' '+%F %T'`"
2013-03-08 05:55:00
2013-03-08 05:55:10
2013-03-08 05:55:20
 8 Mar 05:55:29 ntpd[23555]: XXX.XXX.XXX.XXX 942a 8a sys_peer
2013-03-08 05:55:30
 8 Mar 05:55:35 ntpd[23555]: 0.0.0.0 c628 08 no_sys_peer
2013-03-08 05:55:40
2013-03-08 05:55:50
2013-03-08 05:56:00
2013-03-08 05:51:10
2013-03-08 05:51:20
2013-03-08 05:51:30
  (略)
2013-03-08 05:54:40
2013-03-08 05:54:50
 8 Mar 05:54:57 ntpd[23555]: XXX.XXX.XXX.XXX 8023 83 unreachable
2013-03-08 05:55:00
2013-03-08 05:55:10
 8 Mar 05:55:19 ntpd[23555]: XXX.XXX.XXX.XXX 8053 83 unreachable
2013-03-08 05:55:20
 8 Mar 05:55:25 ntpd[23555]: XXX.XXX.XXX.XXX 8023 83 unreachable
2013-03-08 05:55:30
 8 Mar 05:55:37 ntpd[23555]: XXX.XXX.XXX.XXX 8033 83 unreachable
2013-03-08 05:55:40
2013-03-08 05:55:50

途中、何度かタイムサーバへの同期を試みていますが、当然unreachableとなり、時刻の同期は失敗しました。ちなみにntpqの結果は以下の通りです。

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 some.timesvr.aa XXX.XXX.XXX.XXX  2 u   41   64  360    0.000    0.000   2.945
 some.timesvr.bb XXX.XXX.XXX.XXX  2 u   30   64  360    0.000    0.000   7.679
 some.timesvr.cc XXX.XXX.XXX.XXX  2 u   29   64  360    0.000    0.000   1.539
 some.timesvr.dd XXX.XXX.XXX.XXX  2 u   67   64  360    0.000    0.000   3.799

ホストに到達できないため、タリーコードは全て空白になってしまっています。

実験3: Security GroupのOutboundを123/udpのみ許可する

Outboundの123/udpを許可してみます。

outbound-123/udp

期待通り、タイムサーバにreachableとなり、無事に時刻が修正されました。

2013-03-08 06:02:10
2013-03-08 06:02:21
2013-03-08 06:02:31
2013-03-08 06:02:41
2013-03-08 06:02:51
 8 Mar 06:02:55 ntpd[23555]: XXX.XXX.XXX.XXX 8034 84 reachable
2013-03-08 06:03:01
2013-03-08 06:03:11
 8 Mar 06:03:14 ntpd[23555]: XXX.XXX.XXX.XXX 8064 84 reachable
2013-03-08 06:03:21
 8 Mar 06:03:22 ntpd[23555]: XXX.XXX.XXX.XXX 8034 84 reachable
 8 Mar 06:03:28 ntpd[23555]: XXX.XXX.XXX.XXX 904a 8a sys_peer
 8 Mar 06:03:28 ntpd[23555]: 0.0.0.0 c612 02 freq_set kernel 195838.247 PPM
 8 Mar 06:03:28 ntpd[23555]: 0.0.0.0 c61c 0c clock_step +300.206810 s
 8 Mar 06:08:29 ntpd[23555]: 0.0.0.0 c618 08 no_sys_peer
 8 Mar 06:08:29 ntpd[23555]: XXX.XXX.XXX.XXX 8054 84 reachable
 8 Mar 06:08:29 ntpd[23555]: XXX.XXX.XXX.XXX 8044 84 reachable
 8 Mar 06:08:29 ntpd[23555]: XXX.XXX.XXX.XXX 8014 84 reachable
2013-03-08 06:08:31
 8 Mar 06:08:31 ntpd[23555]: XXX.XXX.XXX.XXX 8014 84 reachable
2013-03-08 06:08:41
2013-03-08 06:08:51

実験4: VPC内部にNTPサーバを自前で設置する

ntp

ここまでは、VPC内のインスタンスを外のNTPサーバと直接通信をさせましたが、サーバの台数が多い場合は、そのネットワークを代表する自前のNTPサーバをネットワーク内に設け、そのサーバが外部と時刻同期し、その他諸々のサーバは自前のNTPサーバと時刻を同期する、といった二段構えの体制も必要になって来ます。

ではこの検証環境を作っていきましょう。ここまで検証に利用してきたサーバを ntp-public と呼ぶことにし、これを代表のNTPサーバとして利用します。

また、これとは別に private-subnet(即ちigw無し)を作成し、そこにntp-privateというインスタンス(スペックはntp-publicと同様)を起動し、図のような構成を作ってください。ntp-privateはprivate-subnetに属しますので、もちろんEIPは不要です。SecurityGroupはdefault(VPC作成時に自動作成される、同じVPC内の通信は全て許可するようになっている)でOKです。また、ntp-publicの方にもdefault SecurityGroupを追加しておいてください。

SSHでntp-privateに入るためにはntp-publicを踏み台(bastion)として使います。接続コマンドは以下の通り。

$ ssh -i secretkey.pem -oProxyCommand='ssh -W %h:%p ec2-user@<ntp-publicのEIP>' ec2-user@10.0.1.100

ntp-privateに入ったら、/etc/ntp.confでntp-publicと同じようにログの設定を行います。また、NTPサーバとしてデフォルトで設定されている*.amazon.pool.ntp.orgをコメントアウトし、ntp-publicのIPアドレスである10.0.0.100を指定します。

# server 0.amazon.pool.ntp.org iburst
# server 1.amazon.pool.ntp.org iburst
# server 2.amazon.pool.ntp.org iburst
# server 3.amazon.pool.ntp.org iburst
server 10.0.0.100 iburst

この設定を有効にするため、ntpdを再起動しておきましょう。

$ sudo /etc/init.d/ntpd restart

先ほどと同じ仕組みを使って、時刻をモニタしましょう。3行目で時刻を狂わせましたが、12行目で修正が起こっています。

2013-03-08 08:56:07
2013-03-08 08:56:17
2013-03-08 09:01:26
2013-03-08 09:01:36
2013-03-08 09:01:46
  (略)
2013-03-08 09:16:17
2013-03-08 09:16:27
2013-03-08 09:16:37
2013-03-08 09:16:47
 8 Mar 09:16:54 ntpd[17642]: 0.0.0.0 c612 02 freq_set kernel -326332.384 PPM
 8 Mar 09:16:54 ntpd[17642]: 0.0.0.0 c61c 0c clock_step -299.246796 s
 8 Mar 09:11:56 ntpd[17642]: 0.0.0.0 c618 08 no_sys_peer
 8 Mar 09:11:56 ntpd[17642]: 10.0.0.100 8024 84 reachable
2013-03-08 09:11:57
2013-03-08 09:12:07
2013-03-08 09:12:17
2013-03-08 09:12:27
2013-03-08 09:12:37

まとめ

VPCのSecurityGroupは、非VPCのEC2 SecurityGroupと違い、Outboundの通信制御も可能です。デフォルトでは、Outboundは全許可の設定になっている(下図)ので、セキュリティを重視した環境でない限り、あまり意識することはないかもしれません。

all outbound

しかし、セキュリティを考えるあまり、外部との通信が不要だと判断したサーバについて、実験2のように全Outbound通信を禁止してしまうと、NTPによる時刻同期が止まってしまうことになります。ntpdは、時刻の同期に失敗しても特に大きなリアクションはとらないので、この事は見過ごされがちです。

また、今までの個人的な経験からの印象ですが、実機上のシステムクロックと比較して、VMのシステムクロックはズレが大きい気がしています。そのため、EC2においてNTPによる時刻同期は恐らく重要な要素なのではないかと考えています。数秒〜数十秒程度のズレは軽視されがちですが、システムクロックというのは暗号化や電子署名の基礎要素となっていたり、思っている以上に大事な要素です。唐突に電子証明書の署名検証が失敗するようになってしまった、等のトラブルを発生させないためにも、システムクロックは出来る限りNTPによって同期すべきでしょう。