2012-05-09

小野秀貴: bindでDNSSECをはじめてみる

◆DNSSECについて

DNSSECとはDNSレコードの改ざんを防ぐためのDNSの拡張です。
DNSリソースを提供するDNS権威サーバでリソースレコードに署名をして、DNSキャッシュサーバで署名を検証することで応答が正しいことを保証するという仕組みです。
JPRS DNSSEC関連情報などでも詳しく解説されています。

ここではドメイン管理者が行う作業という視点でみてみます。
DNSSEC対応するための作業内容は、以下の6つになります。

1. キャッシュサーバのDNSSEC対応
2. KSKの作成
3. ZSKの作成
4. ゾーンの署名
5. 権威サーバのDNSSEC対応
6. DSの上位サーバへの登録依頼

なお、KSK(Key Signing Key)はZSKに署名するための鍵、ZSK(Zone Signing Key)はゾーンのレコードに署名するための鍵です。
またDS(Delegation Signer)はKSK公開鍵から求められる情報です。

実運用時には定期的にKSK,ZSKを更新し再署名、DSの再登録が必要となります。
KSK,ZSKそれぞれについて事前公開法/二重署名法のどちらかを選択して行うなど複雑な作業になります。
また注意深く行わないと最悪すべてのレコードの署名が不正となってしまいます。
今回は更新関連の部分については省略します。


◆パッケージ導入

今回はDNSソフトウェアとしてbindを利用します。bindはすでにDNSSECに対応しているので他に必要なものはありません。
まずはOpenBlockS 600Dにbindを導入します。
インストールされていない場合は以下のようにインストールします。
# aptitude install bind9 bind9utils dnsutils
インストールされたbindのバージョンは9.7.3です。


◆DNSSECの設定

次に設定にうつります。

1. キャッシュサーバのDNSSEC対応

まずはキャッシュサーバのDNSSEC対応を行います。
bindでDNSSEC対応するためには、トラストアンカーを設定する必要があります。
トラストアンカーはルートゾーンのKSK公開鍵情報を含んでいるものが、/etc/bind/bind.keysとしてbind9パッケージで提供されています。
これを利用するには、/etc/bind/named.confに以下の一行を追加します。
 include "/etc/bind/bind.keys";
 さらにDNSSECの検証を有効にするために/etc/bind/named.conf.optionsにdnssec-validation yes;を追加します。
 options {
        // 省略
        dnssec-validation yes;
 };
参考までにbind 9.8以降ではdnssec-validation auto;が追加されていてDNSSEC検証ができる状態になっています。

実際にjpドメインのsoaを取得して確認してみます。
 # dig +dnssec +m @localhost jp. soa

 ; <<>> DiG 9.7.3 <<>> +dnssec +m @localhost jp. soa
 ; (1 server found)
 ;; global options: +cmd
 ;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40502
 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 8, ADDITIONAL: 1

 ;; OPT PSEUDOSECTION:
 ; EDNS: version: 0, flags: do; udp: 4096
 ;; QUESTION SECTION:
 ;jp.                   IN SOA

 ;; ANSWER SECTION:
 jp.                    86400 IN SOA z.dns.jp. root.dns.jp. (
                                1335400203 ; serial
                                3600       ; refresh (1 hour)
                                900        ; retry (15 minutes)
                                1814400    ; expire (3 weeks)
                                900        ; minimum (15 minutes)
                        )
 jp.                    86400 IN RRSIG SOA 8 1 86400 20120521174504 (
                                20120421174504 22584 jp.
                                a34Q3DmotSpmVl9al8jE2qsbQXl+cyLMyh4F98ILGxL7
                                gs1K0B2zx5qn7Q+gIUw4YPLWnFi3Los8NGyEb/08QkMO
                                DEUPTHm4/qQ1Pwq+7F+FYoWkQGcqh3aydsLShMZ4jELZ
                                BU1KFsLv1hX/v6AKNYft4TDtfg9YLTZU2gRU8Sc= )

 ;; AUTHORITY SECTION:
 以下省略
statusがNOERRORでflagsにadが表示されていることからDNSSEC検証が成功したことが確認できました。
以上でキャッシュサーバの対応は完了です。
次は権威サーバの設定にうつります。

2. KSKの作成

対象ドメインはexample.jpとして、権威サーバではまずKSKを生成します。
今回は生成された鍵をおく場所を/etc/bind/keysとします。
KSKの生成はdnssec-keygenコマンドで行います。

生成に使用するパラメタは以下にします。
KSKの鍵長: 2048bit
アルゴリズム: RSASHA256 (アルゴリズム番号:8)
 # mkdir /etc/bind/keys
 # cd /etc/bind/keys
 # dnssec-keygen -r /dev/urandom -a RSASHA256 -b 2048 -f KSK example.jp.
 Generating key pair....................................+++ .......................+++
 Kexample.jp.+008+44380
これで生成完了です。OpenBlockS 600DでKSKの生成に要した時間は約4秒でした。
前述したように今回は鍵の更新を考慮していません。実際の運用時には有効期日などのタイミング用のオプションを付加して生成する必要があります。

3. ZSKの作成

つぎにZSKを生成します。
ZSKもKSKと同様にdnssec-keygenコマンドで生成します。

生成に使用するパラメタは以下にします。
ZSKの鍵長: 1024bit
アルゴリズム: RSASHA256 (アルゴリズム番号:8)
 # dnssec-keygen -r /dev/urandom -a RSASHA256 -b 1024 example.jp.
 Generating key pair...++++++ ..........................................................................................................++++++
 Kexample.jp.+008+27015
生成に要した時間はOpenBlockS 600Dで約1.5秒でした。

この時点で/etc/bind/keysにはKSK,ZSKの公開鍵、秘密鍵が格納されています。
 # ls
 Kexample.jp.+008+27015.key  Kexample.jp.+008+27015.private       Kexample.jp.+008+44380.key Kexample.jp.+008+44380.private
4. ゾーンの署名

次にゾーンファイルへの署名をします。
署名はdnssec-signzoneコマンドで行います。
署名する前のゾーンファイルを/etc/bind/example.jp.zoneとします。

なお署名に使用するパラメタは以下にします。
不在証明の方式: NSEC3
 # dnssec-signzone -r /dev/urandom -a -S -3 9999 -K /etc/bind/keys -d /etc/bind -o example.jp. /etc/bind/example.jp.zone
なお、-S(Smart Signing)オプションを利用するとKSKとZSKを探し出して必要な署名をしてくれ、署名後のゾーンファイルは/etc/bind/example.jp.zone.signedというファイル名で保存されます。-3の後の文字はNSEC3用のシードなので適当な数字(16進数)です。
 # ls -l example.jp.zone*
 -rw-r--r-- 1 root bind  396 Apr 26 12:25 example.jp.zone
 -rw-r--r-- 1 root bind 4593 Apr 26 12:37 example.jp.zone.signed
example.jp.zone.signedの中身を確認すると、RRSIGやDNSKEYなどのレコードが追加されているのが確認できます。
なお、zoneファイルのSOA SERIALはdnssec-signzoneでは自動的にはアップデートはされないのでオリジナルのzoneファイルで事前に更新しておくか-Nオプションで自動更新する必要があります。

5. 権威サーバのDNSSEC対応

bindの読み込むzoneファイルを上記で生成した署名付きのものに変更します。
DNSSEC導入前に/etc/bind/named.conf.local で
 zone "example.jp." {
        type master;
        file "/etc/bind/example.jp.zone";
 };
のような設定をしている場合は、以下のように変更します。
 zone "example.jp." {
        type master;
        file "/etc/bind/example.jp.zone.signed";
 };
さらにDNSSECを有効にするためにoptionsにdnssec-enable yes;の記述が必要ですが、bind 9.7ではデフォルトで有効になっているため記載する必要はありません。
つまり上記の署名されたzoneファイルを読み込ませるようにするだけです。

6. DSの上位サーバへの登録依頼

最後に、上位のドメインからの信頼の連鎖を形成するためにDSを登録してもらう必要があります。
さきほどdnssec-signzoneを実行した際に、/etc/bind/dsset-example.jp というファイルが生成されています。
内容を確認すると以下のようになっています。
 example.jp.             IN DS 44380 8 1 2713C1E0B7D78AA3E4B8D7455328E258B2DBD8D8
 example.jp.             IN DS 44380 8 2 FFC0C009AED9F20F0A7603829D1D402D52BE5112CB47A8F2AC65F7B6 E77E496B
これを上位のドメインに登録してもらう必要がありますが、DSの登録に対応/非対応や登録方法などは業者によって異なりますのでここでは省略します。


◆OpenBlockS 600Dでの性能

DNSSEC対応して性能面で問題になる点としては以下が考えられます。

- 署名の性能
- 権威サーバでの応答処理
- キャッシュサーバでの署名検証に要するコスト

OpenBlockS 600Dがどの程度耐えられるか検証してみます。

- 署名の性能

zoneのレコード数が数個であれば問題ありませんがレコード数が増えると署名に要するコストを考える必要があります。
そこで、レコード数を増やしたときの署名に要する時間を測定してみます。

測定方法は、まずexample.jp.zoneファイルに以下の一行を追加します。
 $INCLUDE /etc/bind/example.jp-sub.zone
example.jp-sub.zoneファイルを以下のように作成します。このレコード数を100,1000,10000として実験します。
 bar-1-1-1 IN A 10.1.1.1
 bar-1-1-2 IN A 10.1.1.2
 bar-1-1-3 IN A 10.1.1.3
 bar-1-1-4 IN A 10.1.1.4
        .
        .
dnssec-signzoneコマンドで署名を行い処理に要する時間を測定しました。オプション等は上記のdnssec-signzoneコマンド実行時と同じものを使用しました。
結果を以下に示します。

 レコード数   署名に要した時間
 100                  9秒
 1000             82秒
 10000        798秒

以上のようにほぼレコード数に比例して増えていくようです。

- 権威サーバでの応答処理

権威サーバではDNSSEC使用時の応答に署名(RRSIG)もくっついてきますので多少負荷があがると想定されます。
そこでDNSSEC未使用時/使用時で処理数を比較します。

検証用の権威サーバではダミーのTLD(foo)を作成し、外部にqueryがでないようにしました。
上記署名の検証で用いた10000エントリのデータを使用して、ドメインはexample.jpのかわりにfooとします。

測定は別のIntelマシン(Linux)から行いました。マシンスペックはCore2Duo 2.13GHzです。ネットワーク構成を以下に示します。

















検証にはbindに附属のqueryperfというツールを使用しました。queryperfはaptのバイナリではインストールされないため、今回はbind 9.9.0のソースを展開してコンパイルしました。
 $ cd bind-9.9.0/contrib/queryperf
 $ ./configure
 $ make
クエリ用のファイルquery.dataを以下のように作成しました。
 bar-1-1-1.foo. A
 bar-1-1-2.foo. A
 bar-1-1-3.foo. A
 bar-1-1-4.foo. A
         .
         .
  以下略(計10000エントリ)
検証は以下の3パターンで行いました。

1. 署名されていないzoneデータを使用、queryperfではDNSSECを使用しない
2. 署名されているzoneデータを使用、queryperfではDNSSECを使用しない
3. 署名されているzoneデータを使用、queryperfではDNSSECを使用

1,2では
 $ ./queryperf -s 192.168.1.211 -l 10 -d ./query.data
3では
 $ ./queryperf -D -s 192.168.1.211 -l 10 -d ./query.data
結果は以下のようになりました。

1. 587 クエリ/秒
2. 588 クエリ/秒
3. 510 クエリ/秒

DNSSECを使用すると処理できるクエリ数は1割ほど低下するようです。

- キャッシュサーバでの署名検証に要するコスト

最後にキャッシュサーバの処理能力を検証します。
OpenBlockS 600Dをキャッシュサーバとします。権威サーバにはもう一台別のPC(Core2Duo 2.0GHz)を使用します。
ネットワーク構成は以下のようになります。


PC2は権威サーバで設定は前述の検証でのOpenBlockS 600Dの設定と同様にします。
参考までにPC-PC2間でqueryperfを行ったところ8800クエリ/秒の性能でした。

検証は以下の3パターンで行いました。

1. キャッシュサーバでdnssec-validation no、queryperfでDNSSEC無効
2. キャッシュサーバでdnssec-validation yes、queryperfでDNSSEC無効
3. キャッシュサーバでdnssec-validation yes、queryperfでDNSSEC有効

前述の検証と同様にqueryperfを使用しました。なお、キャッシュサーバではそれぞれの検証前にはrndc flushでキャッシュデータの全削除を行いました。
クエリの数は10000以下なので全てのデータはキャッシュサーバのキャッシュに格納されていない状態です。

1. 168 クエリ/秒
2. 106 クエリ/秒
3. 107 クエリ/秒

キャッシュサーバでDNSSECのバリデーションを有効にすると性能が36%程度落ち込む結果になりました。


◆まとめ

bindでDNSSECの設定を行いました。
OpenBlockS 600Dで性能の測定を行い以下の結果となりました。

- 署名の性能はレコード数が少なければ気にならない
- 権威サーバでの応答処理の落ち込みは軽微である
- キャッシュサーバでの署名検証はかなり重い処理である




0 件のコメント:

コメントを投稿