2007/02/15

NTP認証: ntp-keygenコマンドとX.509証明書

NTP認証シリーズの第三回。今回は、公開鍵認証に入る前の準備篇。

NTP認証: ユニキャスト・共通鍵認証篇』で既に紹介済みだが、ntpパッケージには、ntp-keygenというコマンドが付属している。このコマンドで、NTPの認証に使用する共通鍵や公開鍵・証明書を生成することができる。基本的な使い方は簡単で、引数なしで起動すれば、公開鍵・証明書を生成してくれる。オプションとして-Mオプションをつければ、共通鍵も生成する。共通鍵ファイルについては、『NTP認証: ユニキャスト・共通鍵認証篇』で述べた通りだ。

では、このコマンドで生成された公開鍵・証明書はどうなっているのか、というのが今回のテーマだ。おさらいとして、公開鍵・証明書を生成するところからやってみよう。
# dd if=/dev/urandom of=/root/.rnd bs=1024 count=1
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.240445 seconds, 4.3 kB/s
# ntp-keygen
Using OpenSSL version 90801f
Random seed file /root/.rnd 1024 bytes
Generating RSA keys (512 bits)...
RSA 0 40 46     1 11 24                         3 1 2
Generating new host file and link
ntpkey_host_ホスト名->ntpkey_RSAkey_ホスト名.3380508833
Using host key as sign key
Generating certificate RSA-MD5
X509v3 Basic Constraints: critical,CA:TRUE
X509v3 Key Usage: digitalSignature,keyCertSign
Generating new cert file and link
ntpkey_cert_ホスト名->ntpkey_RSA-MD5cert_ホスト名.3380508833
#
最初のddコマンドは、ntp-keygenコマンド実行前に/root/.rndがない場合、エラーになるのを避けるためだ。

メッセージを見ると、RSA 512bitの鍵を生成してる。今時512bitでもなかろうに、とも思わなくもないが、NTPプロトコル上の制限なのか…。

実際に生成されたファイルを確かめてみよう。
# cd /etc/ntp
# ls -F
keys
ntpkey_RSA-MD5cert_ホスト名.3380508833
ntpkey_RSAkey_ホスト名.3380508833
ntpkey_cert_ホスト名@
ntpkey_host_ホスト名@
ntpservers
step-tickers
# cat ntpkey_RSAkey_ホスト名.3380508833
# ntpkey_RSAkey_ホスト名.3380508833
# Thu Feb 15 15:13:53 2007
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,389C92663ECF5DB9

wrSy9Q++1KwQ13Day9uY8TlvpYweLEjHmLtd0YiJFFvdNahQMRru4Zc+YL+o4VZk
<<略>>
RiARMG0NVXvkBwpVIIykS5GhGVEjqbT9+ckvZ8C0q3E=
-----END RSA PRIVATE KEY-----
#
むむ?パスワードを指定した覚えはないが…ソースコードを当たってみると、-p パスワードオプションが指定されなかった場合は、gethostname()で得られるホスト名が使われるようだ。実際にそうなっているか、openssl rsaコマンドを使って確認してみよう。
# openssl rsa -text -noout < ホスト名.3380508833
Enter pass phrase: ← ホスト名を入力
Private-Key: (512 bit)
modulus:
00:e2:7c:35:92:2a:de:15:18:1d:98:97:9c:5f:74:
f6:4f:9b:e9:c7:0a:4a:db:2e:15:fc:6c:00:f6:8c:
<<略>>
06:7b
#
確かにRSA 512bitになっている。

証明書を確認してみよう。
# cat ntpkey_RSA-MD5cert_ホスト名.3380508833
# ntpkey_RSA-MD5cert_ホスト名.3380508833
# Thu Feb 15 15:13:53 2007
-----BEGIN CERTIFICATE-----
MIIBSzCB9qADAgECAgTJfnihMA0GCSqGSIb3DQEBBAUAMB0xGzAZBgNVBAMTEmlu
YXp1bWEuZGVzdHJveWVyczAeFw0wNzAyMTUwNjEzNTNaFw0wODAyMTUwNjEzNTNa
MB0xGzAZBgNVBAMTEmluYXp1bWEuZGVzdHJveWVyczBaMA0GCSqGSIb3DQEBAQUA
A0kAMEYCQQDifDWSKt4VGB2Yl5xfdPZPm+nHCkrbLhX8bAD2jP//XaEh9g11C++l
/xPXAxA4Q+88ehQq840V2wgq8o6pgznbAgEDoyAwHjAPBgNVHRMBAf8EBTADAQH/
MAsGA1UdDwQEAwIChDANBgkqhkiG9w0BAQQFAANBANaYyZ0ZUCd+fYt9DbuNMmVb
T/pcR2rD2s7QuI2tJVa3ebmal/dz3nAPlfEadm35pQSAmjIpB0ebbOef1+EcqSA=
-----END CERTIFICATE-----
# openssl x509 -text -noout -in ntpkey_RSA-MD5cert_ホスト名.3380508833
Certificate:
Data:
Version: 3 (0x2)
Serial Number: -914458463 (-0x3681875f)
Signature Algorithm: md5WithRSAEncryption
Issuer: CN=ホスト名
Validity
Not Before: Feb 15 06:13:53 2007 GMT
Not After : Feb 15 06:13:53 2008 GMT
Subject: CN=ホスト名
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:e2:7c:35:92:2a:de:15:18:1d:98:97:9c:5f:74:
f6:4f:9b:e9:c7:0a:4a:db:2e:15:fc:6c:00:f6:8c:
ff:ff:5d:a1:21:f6:0d:75:0b:ef:a5:ff:13:d7:03:
10:38:43:ef:3c:7a:14:2a:f3:8d:15:db:08:2a:f2:
8e:a9:83:39:db
Exponent: 3 (0x3)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage:
Digital Signature, Certificate Sign
Signature Algorithm: md5WithRSAEncryption
d6:98:c9:9d:19:50:27:7e:7d:8b:7d:0d:bb:8d:32:65:5b:4f:
fa:5c:47:6a:c3:da:ce:d0:b8:8d:ad:25:56:b7:79:b9:9a:97:
f7:73:de:70:0f:95:f1:1a:76:6d:f9:a5:04:80:9a:32:29:07:
47:9b:6c:e7:9f:d7:e1:1c:a9:20
#
極々シンプルな自己署名証明書になっている。有効期限は一年間だ。シリアル番号がランダマイズされているのは偉い…のか、管理するのが面倒だったからなのか(笑)。仕様的には問題ないはずだが、負のシリアル番号は初めて見た。

自己署名なので、当然IssuerとSubjectが同一になっている。マニュアルによれば、これはそれぞれ、-s-iオプションで変更できることになっている。

-i name
Set the suject name to name. This is used as the subject field in certificates and in the file name for host and sign keys.
-s name
Set the issuer name to name. This is used for the issuer field in certificates and in the file name for identity files.
しかし、オプションの名前から考えて、これは逆なんじゃなかろうか?実際に確かめてみよう。
# rm *.3380508833
rm: remove 通常ファイル `ntpkey_RSA-MD5cert_ホスト名.3380508833'? y
rm: remove 通常ファイル `ntpkey_RSAkey_ホスト名.3380508833'? y
# ntp-keygen -i "subject.localnet" -s "issuer.localnet"
Using OpenSSL version 90801f
Random seed file /root/.rnd 1024 bytes
Generating RSA keys (512 bits)...
RSA 0 12 19     1 11 24                         3 1 2
Generating new host file and link
ntpkey_host_issuer.localnet->ntpkey_RSAkey_issuer.localnet.3380513148
Using host key as sign key
Generating certificate RSA-MD5
X509v3 Basic Constraints: critical,CA:TRUE
X509v3 Key Usage: digitalSignature,keyCertSign
Generating new cert file and link
ntpkey_cert_issuer.localnet->ntpkey_RSA-MD5cert_issuer.localnet.3380513148
# ls
keys                                           ntpkey_host_ホスト名
ntpkey_RSA-MD5cert_issuer.localnet.3380513148  ntpkey_host_issuer.localnet
ntpkey_RSAkey_issuer.localnet.3380513148       ntpservers
ntpkey_cert_ホスト名                 step-tickers
ntpkey_cert_issuer.localnet
# openssl x509 -text -noout -in ntpkey_RSA-MD5cert_issuer.localnet.3380513148
Certificate:
Data:
Version: 3 (0x2)
Serial Number: -914454148 (-0x36817684)
Signature Algorithm: md5WithRSAEncryption
Issuer: CN=subject.localnet
Validity
Not Before: Feb 15 07:25:48 2007 GMT
Not After : Feb 15 07:25:48 2008 GMT
Subject: CN=issuer.localnet
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:c5:c8:2d:6a:95:05:1e:7f:76:b3:7e:7a:f7:5b:
85:ff:00:76:b1:fe:32:62:d4:fe:41:9a:da:05:2f:
04:0f:f9:0b:97:b7:b7:0b:90:72:ba:9e:42:de:0a:
d5:d8:3d:83:c2:e3:7d:b0:84:a4:56:ac:bf:f5:f0:
c3:9e:6a:2e:11
Exponent: 3 (0x3)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage:
Digital Signature, Certificate Sign
Signature Algorithm: md5WithRSAEncryption
16:a5:2b:bb:19:8e:79:e2:08:6d:f8:76:ed:99:db:f8:ed:22:
46:af:90:67:62:c5:cb:09:c7:03:e8:ea:1f:21:c0:90:3d:08:
db:60:69:7c:e6:8e:47:5b:6a:9f:e9:e0:96:04:f7:a8:e7:d5:
08:eb:c3:53:67:6f:29:7f:40:9d
#
思った通り逆になっている。ファイル名はどうなるのかと思ったら、すべてに対して-sで指定したもの(issuer.localnet)が使われている。まあ、Issuerと言えば認証局(Certificate Authority, CA)のことで、CAは複数subjectに対して複数の証明書を発行するということを考えれば、ファイル名にIssuerの名前でなく、Subjectの名前が使われるのが自然だろう。そうでなければ、証明書のファイル名が衝突してしまうからだ。

しかし、自己署名証明書のIssuerとSubjectが違うってのはどうだろう(笑)?

第一回:『NTP認証: ユニキャスト・共通鍵認証篇
第二回:『NTP認証: ブロードキャスト・共通鍵認証篇
第三回:『NTP認証: ntp-keygenコマンドとX.509証明書
第四回:『NTP認証: ユニキャスト・公開鍵認証篇
第五回:『NTP認証: マルチキャスト・共通鍵認証篇

サブインターフェース

なんだか、Analyticsの解析結果を見てると、「linux サブインターフェース」で飛んでくる人が多いようだ。なので、これについて書いてみる。

普通、Linuxのネットワークインターフェースにはeth0などの名前が付いている。これには、ifconfigを使ってIPアドレスを割当てたりすることが可能だ。しかし、一つのインターフェースには一つのIPアドレスしか割当てられない。一つの物理インターフェースに複数のアドレスを割当てるにはどうすればよいか?その一つの回答が「サブインターフェース」だ。

例えば、Linux boxが、192.168.55/24のネットワークに接続されていたとしよう。接続しているインターフェースのデバイスは、eth0だ。このeth0には、192.168.55.6というアドレスが割当てられているとする。これに加えて、192.168.55.7というアドレスを追加したい。
答は簡単で、eth0に対するサブインターフェース対してifconfigでアドレスを割当ててやればよい。サブインターフェース名は、物理インターフェース名と、1~255のサブインターフェース番号を「:」でつないだもの(例えばeth0:1)で指定する。
# ifconfig eth0:1 192.168.55.7 netmask 255.255.255.0
確認のためifconfigコマンドを引数なしで起動すると、次のような結果を得る。
eth0:1    Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
inet addr:192.168.55.7  Bcast:192.168.55.255  Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
この状態を起動時から有効にするには、/etc/sysconfig/network-scripts/ifcfg-eth0:1のようなファイルを作ればよい。書式は、物理インターフェースの設定ファイル(/etc/sysconfig/network-scripts/ifcfg-eth0など)と同じだが、HWADDRなどは指定しない。

サブインターフェースの使用に関しては、注意しなければならない点がある。『NTPDの謎』で指摘した問題だが、UDPのサーバ(NTPサーバなど)を使用する場合に、サブインターフェースを使っていると、正しく通信できない場合がある。詳しくは、前の記事を読んで欲しい。

なお、物理インターフェースに複数のIPアドレスを割当てる方法は他にもある。例えば、物理インターフェースをIEEE802.1qタグVLAN(Tag VLAN)インターフェースとして設定する方法だ。これについてはいずれ書きたい。

2007/02/14

NTP認証: ブロードキャスト・共通鍵認証篇

NTP認証シリーズの第二回。前回は、共通鍵認証・ユニキャストだったが、今回はユニキャストの代わりにブロードキャスト(broadcast)を使う。認証を行わない場合のブロードキャストの設定については、『NTP broadcast設定』で取り上げた。これに認証を加えようというわけだ。

NTP認証は、ブロードキャスト設定を行ったときにこそ必要になる。なぜなら、broadcastclient設定を行ったクライアントは、認証を有効にしていない場合、ブロードキャストで流れてきたNTPパケットを無条件で信用し、そのパケットを送信したサーバに時刻同期しようとするからだ。悪意のある攻撃者がネットワークに接続した場合、簡単に時刻を混乱させることができる。

サーバ側
共通鍵を生成する部分に関しては、前回と同じ。詳しくは、そちらを参照して欲しい。

設定ファイル/etc/ntp.confについては、前回の設定に加えて、ブロードキャストの設定が必要。ただし、『NTP broadcast設定』で述べた方法と違い、broadcast サーバ名に続けて、key 鍵識別子オプションを指定する。
keys /etc/ntp/keys
trustedkey 10
broadcast 192.168.55.255 key 10
ユニキャストの場合と同様、trustedkeyコマンドで指定した鍵識別子の内一つをbroadcastコマンドのkeyオプションで指定する。

設定を変更したら、ntpdを再起動する。

クライアント側
まず、『NTP broadcast設定』でも指摘したが、ファイアウォール(iptables)が動いている場合は、ntp:udpを許可する必要がある。サーバからのNTPブロードキャストを受け取れるようにするためだ。FC5だと、system-config-networkを使って変更するか、/etc/sysconfig/iptablesを直接編集し、サービスiptablesを再起動する。

次に、共通鍵ファイルを準備する。これは前回とまったく同じ。/etc/ntp/keysに必要な鍵を追加する。

さらに、/etc/ntp.confの中で、broadcastclientコマンドを指定する。
restrict 192.168.55.0 mask 255.255.255.0 nomodify notrap
broadcastclient
これは、『NTP broadcast設定』での設定とまったく同じ。

最後に、この/etc/ntp.confの中で、使用する鍵識別子を指定する。
keys /etc/ntp/keys
trustedkey 10
これは、前回とまったく同じ。

変更したら、ntpdを再起動する。

確認
これも前回と同じで、クライアント側でntpqを起動し、peerコマンドで確認すればよいが、注意を要する点がある。ユニキャストの場合と違い、ntpdを再起動してすぐは、peerコマンドの出力に、NTPサーバのエントリが出力されない。
# service ntpd restart
ntpd を停止中:                                             [  OK  ]
ntpd: 時間サーバと同期中:                                  [  OK  ]
ntpd を起動中:                                             [  OK  ]
# ntpq
ntpq> peer
remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
LOCAL(0)        LOCAL(0)        10 l    3   64    1    0.000    0.000   0.001
ntpq>
NTPクライアントは、正しい鍵で認証できるサーバからのNTPブロードキャストを受け取って、しばらく時間を置いてから、ユニキャストでそのサーバと時刻同期を行う。再起動直後は、タイミングにもよるが、まだサーバからのNTPブロードキャストを受け取っていないので、peerコマンドの出力には対応するエントリが出てこない。しばらく時間をおくと、対応するエントリが現れる。
ntpq> peer
remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*LOCAL(0)        LOCAL(0)        10 l   23   64   17    0.000    0.000   0.001
ntpserver.local 213.186.41.134   3 u    3   64   17   10.357    0.814   7.753
ntpq>
さらに時間をおくと、そのサーバと時刻同期できるはずだ。

第一回:『NTP認証: ユニキャスト・共通鍵認証篇
第二回:『NTP認証: ブロードキャスト・共通鍵認証篇
第三回:『NTP認証: ntp-keygenコマンドとX.509証明書
第四回:『NTP認証: ユニキャスト・公開鍵認証篇
第五回:『NTP認証: マルチキャスト・共通鍵認証篇

NTP認証: ユニキャスト・共通鍵認証篇

NTP認証シリーズの第一回。ユニキャスト(unicast)で設定したサーバ=クライアント間で、共通鍵(symmetric key: 共有鍵・対称鍵)を使って認証を行う場合について。「認証を行わないユニキャストによる時刻同期ができている」という前提に、共通鍵認証だけを加える。

サーバ側
まず、共通鍵認証を行うためには当然、共通鍵を作る必要がある。これは、手作業で行うこともできるが、自動的に生成させるのが簡単だ。FC5ではntpdのバージョンは、4.2なので、ntp-keygenというコマンドが入っているはずだ。このコマンドは基本的に、公開鍵認証を行うための秘密鍵と証明書を生成するためのものだが、-Mオプションをつけて実行すると、16個の共通鍵が自動的に生成される。鍵や証明書は、/etc/ntpに生成されるので、rootで作業する必要がある。
# ntp-keygen -M
# cd /etc/ntp
# ls
keys
ntpkey_cert_ntpserver.localnet
ntpkey_host_ntpserver.localnet
ntpkey_MD5key_ntpserver.localnet.3533248690
ntpkey_MD5_ntpserver.localnet
ntpkey_RSAkey_ntpserver.localnet.3533248690
ntpkey_RSA-MD5cert_ntpserver.localnet.3533248690
ntpservers
step-tickers
このntpkey_*が新たに生成されたもの。ファイルスタンプを時刻を表す整数として、ntpkey_*_ホスト名.ファイルスタンプの形式になっているものが実ファイル。そうでないものは、それらに対するシンボリックリンクだ。これらのファイルは、所有者rootで、パーミッションを600にしておいた方が無難だ。
# chown root.root ntpkey_*
# chmod 600 ntpkey_*
この内、共通鍵認証に使うの共通鍵ファイルは、ntpkey_MD5key_*。既存の共通鍵ファイルを退避し、代わりにこのファイルに対するシンボリックリンクを作成する。
# mv keys keys.org
# ln -s ntpkey_MD5_ntpserver.localnet keys
以上で共通鍵の生成は終了だ。なお、この共通鍵ファイルの中身は、次のようになっているはずだ。
# ntpkey_MD5key_ntpserver.localnet.3533248690
# Mon Feb 12 11:04:55 2007
1 MD5  Vbevc\~F{3Yg(p6 # MD5 key
2 MD5  dPw#mEg+9=yc5Y] # MD5 key
<<略>>
10 MD5  ;XlkqE~Q2Uc#*&2 # MD5 key
<<略>>
15 MD5  lF943;ZrNNVHqYw # MD5 key
16 MD5  XKw$i#m%.TQ]lD" # MD5 key
#」から行末までは、お馴染みの通り無視されるつまり、コメント。各行は、空白区切りのカラムから成っている。第一カラムは、鍵識別子(key identifier)。1から65,535までの整数を指定する。第二カラムは、鍵形式(key format)。現在のバージョンでは、MD5だけが許されている。第三カラムは、鍵そのもの。16文字以下の印刷可能文字列を指定する。この文字列には、空白および「#」を含めてはいけない。

次に、/etc/ntp.confの変更。FC5では、共通鍵ファイルを指定するkeysコマンドは既に記述されているはず。それに加えて以下の太字の部分を追加する。
keys /etc/ntp/keys
trustedkey 10
ここで、trustedkeyコマンドに続けた引数10は、keysコマンドで指定した共通鍵ファイル中の鍵識別子。ここで指定した鍵識別子で指定した鍵のみが時刻同期時の認証で有効。鍵を複数指定する場合は、鍵識別子を空白で区切って並べる。設定変更を終えたら、ntpdを再起動する。
# service ntpd restart


なお、コマンドntp-keygenを実行した際に、「RAND_load_file /root/.rnd not found or empty」といったようなメッセージが出力され、鍵を生成できない場合がある。これは、メッセージの通り、/root/.rndを以下のように生成すればよい。
# dd if=/dev/urandom of=/root/.rnd bs=1024 count=1
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.240445 seconds, 4.3 kB/s
#


クライアント側
まず、共通鍵ファイル/etc/ntp/keysを準備する。鍵は、サーバと同じのものを準備する必要がある。上のサーバの例では、鍵識別子10の鍵だけが有効になっているので、クライアント側の共通鍵ファイルには、少なくともこの鍵をコピーしておく必要がある。逆に言えば、他の鍵はコピーしておく必要はない。むしろ、セキュリティの観点から言えば、コピーしない方がいいだろう。共通鍵ファイルの内容は、以下の通り。
10 MD5  ;XlkqE~Q2Uc#*&2 # MD5 key
このファイルは、所有者をrootにして、パーミッションを600にしておく。
# cd /etc/ntp
# chown root.root keys
# chmod 600 keys


次に、/etc/ntp.confを変更する。クライアント・サーバで鍵識別子10を使用するとしよう。認証なしでサーバと時刻同期が取れているなら、serverコマンドのオプションとして、key 10を付ける。また、trustedkeyコマンドにやはり鍵識別子10を指定する。
server 192.168.55.133 key 10
keys /etc/ntp/keys
trustedkey 10

設定変更を終えたら、ntpdを再起動する。
# service ntpd restart


確認
クライアント側でntpqを起動し、peerコマンドを使って確認すればよい。ただし、時刻同期は即時に行われるとは限らない。以下の実行例は、ntpdを再起動してしばらくたった後のものであることに注意して欲しい。

正常に動作している場合は、次のようになるはずだ。
# ntpq
ntpq> peer
remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntpserver.local 209.132.176.4    2 u  531 1024  377   10.367    3.617   4.396
LOCAL(0)        LOCAL(0)        10 l    5   64  377    0.000    0.000   0.001
ntpq>
もし、クライアント側でtrustkeyコマンドを追加していないか、鍵識別子を間違っているなどの問題があった場合は、次のような表示になる。
ntpq> peer
remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
ntpserver.local .NKEY.          16 u    -   64    0    0.000    0.000 4000.00
LOCAL(0)        LOCAL(0)        10 l    2   64    1    0.000    0.000   0.001
ntpq>
上の実行例で、refid.NKEY.になっていることに注目して欲しい。この場合、syslogには、次のようなメッセージが記録されているはずだ。
Feb 14 17:28:43 ntpclient ntpd[16217]: transmit: key 10 not found for 192.168.55.133


一方、サーバとクライアントの鍵識別子の指定が違っている場合、例えば、サーバ側では鍵識別子11を、クライアント側では鍵識別子10を指定しているような場合は、
ntpq> peer
remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
ntpserver.local .INIT.          16 u    -   64    0    0.000    0.000 4000.00
*LOCAL(0)        LOCAL(0)        10 l   59   64   37    0.000    0.000   0.001
ntpq>
のように、refid.INIT.、stratumが最大値の16になる。

第一回:『NTP認証: ユニキャスト・共通鍵認証篇
第二回:『NTP認証: ブロードキャスト・共通鍵認証篇
第三回:『NTP認証: ntp-keygenコマンドとX.509証明書
第四回:『NTP認証: ユニキャスト・公開鍵認証篇
第五回:『NTP認証: マルチキャスト・共通鍵認証篇

NTP認証: 予告篇

このブログでもNTPについて何度か取り上げてきた([1][2]) 。この中で認証については何も書かなかった。認証方式と通信方式の組合せによって設定が異なるので、何回かに分けて書いてみたい。
まず、NTPの認証には、共通鍵(symmetric key: 共有鍵・対称鍵)を使う方法と、公開鍵(public key)を使う方法がある。ntp.confの中ではそれぞれ、keyコマンドおよびautokeyコマンドにより指定される。
一方、NTPの通信方式にもいくつかの方法がある。ユニキャスト(unicast)でクライアント=サーバ間もしくはピア間で通信する方法が一般的だ。これに加えて、サーバからのブロードキャストでクライアントにサーバの存在を知らせる方法や、マルチキャスト(multicast)を使う方法などがある。

NTPにおける認証は、クライアントがサーバの時刻に同期する、という点だけを捉えれば、クライアントが正しいサーバを確認することを意味する。つまり、悪意のあるサーバから時刻を受け取らないようにするための仕組みであると言える。
サーバが正しく認証を行ったクライアントであることを確認することもできる。しかし、普通に設定すれば、サーバは認証が有効化されていないクライアントに対してもNTP応答を行う。

ウェブページを検索してみると、そもそもNTPの認証に関するページが少ないが、ブロードキャストのときにどのように認証を行えばよいか、また、公開鍵認証でどのように設定すればよいか書いてあるページはさらに少ない。このブログでは、その辺りについても書く予定だ。

なお、認証を行わないユニキャストによる時刻同期ができていることを前提条件とする。また、『NTP broadcast設定』では、「NTPブロードキャストで認証を行わない場合は、ntpdへ渡すオプションに-Aを付ける」と書いたが、この-Aオプションが指定してあるとNTP認証は正常に動作しない。サーバ側でもクライアント側でもこのオプションを指定していないことを確認する。

第一回:『NTP認証: ユニキャスト・共通鍵認証篇
第二回:『NTP認証: ブロードキャスト・共通鍵認証篇
第三回:『NTP認証: ntp-keygenコマンドとX.509証明書
第四回:『NTP認証: ユニキャスト・公開鍵認証篇
第五回:『NTP認証: マルチキャスト・共通鍵認証篇

2007/02/09

Linux上のpingコマンドで経路上のMTUを調べる

@ITの記事『pingでMTUサイズを調査する』と同じことをLinuxでやる方法。つまりは、Linuxのpingコマンドでフラグメント禁止を指定するにはどうすればいいか、ということ。簡単に言うと、-M hintオプションを使用する。まずは、実行結果をご覧あれ。解る人にはこれだけで解るだろう。
$ ping -c 1 -s 1500 192.168.55.7
PING 192.168.55.7 (192.168.55.7) 1500(1528) bytes of data.
1508 bytes from 192.168.55.7 (192.168.55.7): icmp_seq=1 ttl=255 time=4.64 ms

--- 192.168.55.7 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.641/4.641/4.641/0.000 ms
$ ping -c 1 -s 1500 -M do 192.168.55.7
PING 192.168.55.7 (192.168.55.7) 1500(1528) bytes of data.
From murakumo (192.168.140.195) icmp_seq=1 Frag needed and DF set (mtu = 1500)

--- 192.168.55.7 ping statistics ---
0 packets transmitted, 0 received, +1 errors

$ ping -c 1 -s 1472 -M do 192.168.55.7
PING 192.168.55.7 (192.168.55.7) 1472(1500) bytes of data.
1480 bytes from 192.168.55.7 (192.168.55.7): icmp_seq=1 ttl=255 time=2.96 ms

--- 192.168.55.7 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.963/2.963/2.963/0.000 ms
$
一回目の実行では、-Mオプションを指定していないため、MTUの制限よりも大きいサイズを-sオプションで指定しても応答が返っている。
二回目の実行では、同じサイズで-M doを指定しているので、断片化(フラグメンテーション/fragmentation)が抑制され、応答が返らない。つーか、そもそも送信していない。
最後の実行では、-M doを指定しているが、サイズに適正値を指定しているため、応答が返っている。

この-M hintオプションには、dodontおよびwantが指定できるらしいが、do以外はよく解らない。ならばmanを引け、と言われそうだが、実はFC5のmanpageには、このオプションの記述がない。なぜこのオプションに気付いたかというと、次のように実行したからだ。
$ ping
Usage: ping [-LRUbdfnqrvVaA] [-c count] [-i interval] [-w deadline]
[-p pattern] [-s packetsize] [-t ttl] [-I interface or address]
[-M mtu discovery hint] [-S sndbuf]
[ -T timestamp option ] [ -Q tos ] [hop1 ...] destination
$ ping -M 1
ping: wrong value for -M: do, dont, want are valid ones.
$
なんだかまだ知らないオプションがたくさんありそうだ。

2007/02/08

RHL9用のbind-9.2.8.*.rpmを作る

Red Hat Linux release 9 (Shrike)は、EOLになって久しい。なので当然、RPMパッケージの最新版は手に入らない。が、なんとかしなければならないときがある。実に情けない感じだが…

注意:この手順は私がてきとーにハックしたもので、内容の正しさについては何の保障もしません。できたRPMを使う場合は、自己責任で

大まかな手順は以下の通り。
  1. 場所の準備
  2. 材料の準備
  3. ビルド
まずはRPMをビルド(build)するための場所を準備する。 適当な作業ディレクトリ(例えば、自分のホームディレクトリ)に移動し、次のように実行する。
$ mkdir -p RPM/BUILD RPM/RPMS/i386 RPM/SOURCES RPM/SRPMS RPM/SPECS
$ echo %_topdir $PWD/RPM > ~/.rpmmacros
ここで、~/.rpmmacrosは、RPMをビルドするための設定ファイル。以下、この作業ディレクトリを%{_topdir}と呼ぶ。

次にビルドする材料を準備する。一つは、RH9用のbindパッケージを作るためのsrc.rpm。もう一つは、BINDの最新版のtarball。Fedora Lagacy Projectは既に終了しているが、ミラーサイトはまだ健在なところが多いので、そこから入手する。BINDの最新版は、ISCから入手すればよい。%{_topdir}に移動し、例えば次のように実行する。
$ cd RPM/SRPMS/
$ wget http://ftp.kddilabs.jp/Linux/packages/fedora.legacy/redhat/9/os/SRPMS/bin
d-9.2.1-16.src.rpm
<<略>>
100%[====================================>] 3,998,722 263.41K/s ETA 00:00

00:18:36 (263.41 KB/s) - `bind-9.2.1-16.src.rpm' を保存しました [3998722/3998722]

$ cd ../SOURCES/
$ wget http://ftp.isc.org/isc/bind9/9.2.8/bind-9.2.8.tar.gz
<<略>>
100%[====================================>] 5,208,805 284.40K/s ETA 00:00

00:19:50 (284.40 KB/s) - `bind-9.2.8.tar.gz' を保存しました [5208805/5208805]

$
この%{_topdir}/RPM/SRPMS/bind-9.2.1-16.src.rpmの中からスペックファイルを取り出し%{_topdir}/RPM/SPECSへ、パッチその他(*.patch, bind-manpages.tar.bz2, keygen.c, named.init, named.logrotate, named.sysconfig, rfc1912.txt)を取り出し%{_topdir}/RPM/SOURCESへ置く。
$ rpm2cpio ../SRPMS/bind-9.2.1-16.src.rpm | cpio -i "*.patch" bind-manpages.tar.bz2 keygen.c named.init named.logrotate named.sysconfig rfc1912.txt
7931 blocks
$ ls
bind-9.2.0rc3-varrun.patch bind-9.2.8.tar.gz named.init rfc1912.txt
bind-9.2.1-config.patch bind-manpages.tar.bz2 named.logrotate
bind-9.2.1-key.patch keygen.c named.sysconfig
$ cd ../SPECS/
$ rpm2cpio ../SRPMS/bind-9.2.1-16.src.rpm | cpio -i bind.spec
7931 blocks
$ ls
bind.spec
$
続いて、bind.specに以下のパッチbind.spec.patch:
--- bind.spec~  2007-02-08 23:55:33.000000000 +0900
+++ bind.spec 2007-02-08 23:34:20.000000000 +0900
@@ -3,7 +3,7 @@
Name: bind
License: BSD-like
Group: System Environment/Daemons
-Source: ftp://ftp.isc.org/isc/bind9/%{version}/bind-%{version}.tar.bz2
+Source: ftp://ftp.isc.org/isc/bind9/%{version}/bind-%{version}.tar.gz
Source1: bind-manpages.tar.bz2
Source2: named.sysconfig
Source3: named.init
@@ -12,11 +12,11 @@
Source6: rfc1912.txt
Patch: bind-9.2.0rc3-varrun.patch
Patch1: bind-9.2.1-key.patch
-Patch2: bind-9.2.1-config.patch
+Patch2: bind-9.2.8-nslookup.patch
Url: http://www.isc.org/products/BIND/
Buildroot: %{_tmppath}/%{name}-root
-Version: 9.2.1
-Release: 16
+Version: 9.2.8
+Release: 1

BuildRequires: openssl-devel gcc glibc-devel >= 2.2.5-26 glibc-kernheaders >= 2.4-7.10 libtool pkgconfig

@@ -61,7 +61,7 @@
%setup -q -n %{name}-%{version}
%patch -p1 -b .varrun
%patch1 -p1 -b .key
-%patch2 -p1 -b .configure
+%patch2 -p1 -b .nslookup

%build
#CHROOT=/etc/named/chroot
を当てる。
$ patch < bind.spec.patch
patching file bind.spec
$
また、次のパッチファイル%{_topdir}/RPM/SOURCES/bind-9.2.8-nslookup.patchを準備する。
--- bind-9.2.8/bin/dig/Makefile.in~ 2004-08-19 08:22:52.000000000 +0900
+++ bind-9.2.8/bin/dig/Makefile.in 2007-02-08 23:38:35.000000000 +0900
@@ -48,7 +48,7 @@

SRCS = dig.c dighost.c host.c nslookup.c

-MANPAGES = dig.1 host.1 nslookup.1
+MANPAGES = dig.1 host.1 # nslookup.1

HTMLPAGES = dig.html host.html nslookup.html

これで材料の準備は終わり。

最後、ビルド。
$ cd ../SPECS/
$ rpmbuild -bb bind.spec > build.log 2>&1&
[1] 9557
$
後は、tail -f build.logなりでビルドが終了するのを待つ。ビルドが終わると、%{_topdir}/RPM/RPMS/i386にRPMができている。
$ cd ../RPMS/i386/
$ ls
bind-9.2.8-1.i386.rpm bind-devel-9.2.8-1.i386.rpm
bind-debuginfo-9.2.8-1.i386.rpm bind-utils-9.2.8-1.i386.rpm
$

2007/02/07

NTP broadcast設定

に「NTPDを使って、ブロードキャストで時刻同期させる方法が判らない」と書いた。この解決篇。

次のようなネットワークを考える。
NTPサーバ
192.168.55.133。外部の上位stratumサーバと同期し、ローカルネットワーク192.168.55/24にntpをブロードキャストする。
NTPクライアント
192.168.55.6。NTPDブロードキャストクライアントとして構成される。
まずはNTPサーバ側だが、上位stratumサーバとの時刻同期の部分は省くとして、ブロードキャストサーバとしての設定は、/etc/ntp.confに以下の様な行を追加すれば良い。
broadcast 192.168.55.255
また、ファイアウォール(iptables)が動作している場合は、ntp:udpを許可しておく必要がある。これは、FC5だと、system-config-networkを使えばよい。設定は、/etc/sysconfig/iptablesに以下のように反映される
-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 123 -j ACCEPT


続いてNTPクライアント側だが、まず、/etc/ntp.confに以下のような行を追加する。
restrict 192.168.55.0 mask 255.255.255.0 nomodify notrap
broadcastclient
次に、NTPサーバと同様に、ファイアウォールが動作している場合は、ntp:udpを許可する。私は、これを忘れていたため、時刻同期ができなかったようだ。
なお、NTPブロードキャストで認証を行わない場合は、ntpdへ渡すオプションに-Aを付ける必要がある。起動時に行うには、/etc/sysconfig/ntpdOPTIONSの部分を編集する。

時刻同期ができているかどうかは、NTPクライアント側で次のように確認する。
# ntpstat
synchronised to NTP server (192.168.55.133) at stratum 4
time correct to within 167 ms
polling server every 128 s
#
ちなみに、NTPサーバ=NTPクライアント間の通信は、次のように行われているようだ
# tcpdump -n -p udp port ntp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
11:32:40.425917 IP 192.168.55.133.ntp > 192.168.55.255.ntp: NTPv4, Broadcast, length 48
11:32:41.385443 IP 192.168.55.6.ntp > 192.168.55.133.ntp: NTPv4, Client, length 48
11:32:41.386969 IP 192.168.55.133.ntp > 192.168.55.6.ntp: NTPv4, Server, length 48
ブロードキャストパケットが、NTPサーバからNTPクライアントに届いた後、NTPクライアントからNTPサーバへNTPパケットが送られ、NTPサーバからNTPクライアントに応答がある。そんなもんかな?

XenのDomUでXserverやGDMが起動しない

前の記事で触れた件の中間報告。

Red HatのBugzillaで報告されているBug 206082と同等の現象と思われる。

結論としては、新しいxorg-x11-serverのリリースを待て、ということか。

XenのDomUで、仮想コンソールにログインプロンプトが出ない・訂正

前の記事に嘘があったので訂正。

FC5でDomUをyum updateすると、仮想コンソールからログインできなくなる問題に対して、chcon -t tty_device_t /dev/xvc0(あるいは、chcon --reference=/dev/tty1 /dev/xvc0)とすればよい、と書いた。これは嘘ではないが、その後が嘘。というのは、再起動すると、この効果はなくなってしまうのだ。

で、解決篇。次のように実行する。
# ls -lZ /dev/xvc0
crw------- root root system_u:object_r:device_t /dev/xvc0
# semanage fcontext -a -t tty_device_t -f -c /dev/xvc0
# restorecon /dev/xvc0
# ls -lZ /dev/xvc0
crw------- root root system_u:object_r:tty_device_t /dev/xvc0
#
この内、semanageで若干時間がかかる。

なお、この情報源はこれ。BugzillaでBug 213277として扱われている。

2007/02/06

xen-3.0.3 & kernel-xen0-2.6.18-1.2257にしたら…

今日、yum updateすると、xenとkernel-xen0がそれぞれ、
  • xen-3.0.3
  • kernel-xen0-2.6.18-1.2257
へ更新された。すると、Xorgのxserverやgdmが動かなくなった。カーネルを、Runlevel 5で起動するとGDMの画面が表示されないし、Runlevel 3で動かしても、
# startx
とすると、GUIな画面は表示されず、TTY画面に[Ctrl]+[Alt]+[F1]で戻っても表示が乱れている。
なんとなく、な憶測だが、これは、このバージョンがBlkifを使っているからではないかと睨んでいる。詳細が判り次第、ここで報告する。

また、このバージョンでは、Dom0上のループバックデバイスを使用せずにDomUを起動する仕組みが有効になっているようだ。これを利用すると、ループバックデバイスを用いる場合の倍の速度が出る、というホンマかいな?
既存のDomUに対しては、設定ファイル中の
disk = [ 'file:/var/xen/rescue.img,xvda,w' ]
disk = [ 'tap:aio:/var/xen/rescue.img,xvda,w' ]
の様に変更すればよい。こちらの環境では、特に問題なく動いているようだ。修正したDomUを起動後、Dom0上でlosetup -aを実行しても、それに対応する/dev/loop*は存在しないことが確認できる。

2007/02/02

NTPDの謎

NTPDは、その実現する機能の割には設定が難しいソフトウェアの一つだ。とは言うものの、普通に使う分には、ネットで検索すればまあ動くものが出来上がる。しかし、未だに解決できない問題が二つある。
  • ブロードキャスト/マルチキャストによる同期
  • サブインターフェースを持たせた場合の動作
がそれだ。

前者は、いろいろやってみたが良くわからない。サーバがブロードキャストアドレスでNTPパケットを流すところまではできたのだが、クライアントの設定が不明だ。

後者の問題はこうだ。NTPサーバとなるマシンntp1がインターフェースeth0を持っている。このインターフェースにサブインターフェースeth0:1およびeth0:99を作成し、それぞれ192.168.1.1/24および192.168.1.99/24を割当てる。このとき、NTPクライアントとなる他の機器server1で、NTPサーバを192.168.1.99を指定すると、同期が取れない場合がある。特に、server1とntp1の間にファイアウォールがある場合などに問題になる。
この原因は判っていて、NTPサーバが192.168.1.99宛に届いた問合パケットに対して、応答パケットが192.168.1.1から出て行くからだ。つまり、こういうことだ。サーバserver1のアドレスを192.168.254.1としよう。さらに、ソースアドレスsとデスティネーションアドレスdを持つパケットを[s=>d]と表すとする。このケースでは、問合パケットは、[192.168.254.1=>192.168.1.99]になり、応答パケットには、ソースとデスティネーションを逆転させた[192.168.1.99=>192.168.254.1]が期待される。だが、これが何故か[192.168.1.1=>192.168.254.1]になってしまう。
NTPクライアント側は、自分が送信先に指定したサーバからの応答があると期待しているので、それとは違うソースアドレスからのパケットは無視する。もしserver1とntp1の間にステートフルなファイアウォールが存在すれば、応答パケットが問合せパケットに対応するものだとは理解できないので、おそらく応答パケットは破棄されてしまう。

どちらもまだ解決方法を知らない。

解決篇「NTP broadcast設定」

ルーティングでハマる

普通のLinuxデストリビューションでは、デフォルトでルーティング動作が無効化されている。つまり、Linux機が二つのインターフェースを持っていても、この間のL3レベルでの転送は行わない、ということだ。これを有効にするには、sysctlコマンドを使って、
# sysctl net.ipv4.ip_forward = 1
#
と実行すればよい。起動時からルーティングを有効にしたいなら、/etc/sysctl.confの中の対応する部分(見れば判る)を変更する。

なのだが、ものの頁には、/etc/sysconfig/networkの中に、FORWARD_IPV4=yesを追加すればよい、と書いてある。これは、昔のRed Hat系ディストリビューションなんかでは正しいようなのだが、少なくとも、FC5では正しくないようだ。実際、/etc/init.d/networkの中を眺めてみても、この変数を処理する部分は無いようだ。

と、言う事実を知らず、Linux機をルータに仕立てる作業をしていたのだが、ここでハマってしまった。ルーティングしていない、ということであれば、単に通信ができないという症状になるので、すぐに気付きそうなものだが、そう単純ではないのだ。
例えば、Linux機をrouter1としよう。これには二つのインターフェースeth0およびeth1が付いているが、上のように間違った設定をしているため、ルーティングは無効になっている。このeth0側にpc1というマシンを接続する。このpc1(に割当てたIPアドレス)とeth0(に割当てたIPアドレス)の間の通信ができるよう設定し、pc1のデフォルトルートは、eth0に向ける。この状態でpc1から、eth1(に割当てたIPアドレス)へのHTTPは、ルーティングされないので、当然接続を確立できない。ここまでは想定内だ。
しかし、pc1からeth1へのPINGは正常に応答があるのだ!これが理解できなかったので、非常に苦労した。

2007/02/01

RPMからインストールせずにファイルを取り出す

簡単に言うと、rpm2cpioを使ってCPIO形式に変換し、cpioで取り出せばよい。以下、実行例。
$ ls
php-4.3.11-2.8.4.mjm.src.rpm
$ rpm2cpio php-4.3.11-2.8.4.mjm.src.rpm | cpio -i "*.patch"
10212 blocks
$ ls
php-4.2.2-cxx.patch php-4.3.4-easter.patch
php-4.2.2-lib64.patch php-4.3.6-umask.patch
php-4.3.1-dlopen.patch php-4.3.6-xelement.patch
php-4.3.1-odbc.patch php-4.3.7-select.patch
php-4.3.1-tests.patch php-4.3.8-gdnspace.patch
php-4.3.11-2.8.4.mjm.src.rpm php-4.3.8-round.patch
php-4.3.11-CVE-2006-1990.patch php-4.3.9-CVE-2005-3353.patch
php-4.3.11-gdheaders.patch php-4.3.9-CVE-2005-3388.patch
php-4.3.11-shtool.patch php-4.3.9-CVE-2005-3389.patch
php-4.3.11-shutdown.patch php-4.3.9-CVE-2005-3390.patch
php-4.3.2-db4.patch php-4.3.9-CVE-2005-3883.patch
php-4.3.2-libtool15.patch php-4.3.9-CVE-2006-0208.patch
php-4.3.3-install.patch php-4.3.9-CVE-2006-0996.patch
php-4.3.3-miscfix.patch php-4.3.9-htmlunescape.patch
php-4.3.4-config.patch
$
これで私が何をしたいか解ったあなた、鋭いです。つーか、同じような下らない仕事、したことありますね?