NHPは階層化・分散化されたシステムを指向しています。その手段として、NHPサーバをツリー型に連携・同期します。イメージとしては、NTPと同様なシステムを目指しています。この草案では、その連携・同期に関わる手順・操作を提案します。この草案のヴァージョンは、0.4.0です。この草案は、NHP(0.3.0)の仕様には含まれていませんが、nhp.cgi(0.2.x)では試験的に実装されています。
2017-12-15
1. 概要 2. get_ip_address (status=16) 3. check_identifier (status=23) 4. get_publickey (status=28) 5. register_this_server (status=18,19) 6. unregister_this_server (status=21,22) 7. check_this_server_registered (status=25,26) 8. update_registered_server (status=29,30) 9. nhpd (status=31) 10. 返り値 11. その他 NHPサーバはサーバ間で連携・同期するためにサーバ間通信を行なっています。この連携・同期の最大の目的は、大まかに言えば、上位サーバの祝日データが更新された時、下位サーバも同様に更新させることです。この更新をしてもらうために下位サーバは上位サーバに登録します。この登録を削除する操作も用意しています。また、この登録が有効であるかを確認する手段も用意しています。この、下位サーバの更新(status=29)、上位サーバへの登録(status=18)、登録の削除(status=21)、登録の確認(status=25)、の4つがサーバ管理者が直接実行できる操作で、その他の操作はシステム同士で行われる操作です。システム同士で行われる操作は主にセキュリティに関するもので、成りすまし防止やパスワードの暗号化を担っています。 ここでは、まず、システム間のみで用いられるステイタスリクエスト(status=16,23,28)について詳解し、その後、サーバ管理者が実行するステイタスリクエスト(status=18,21,25,29)の手順・操作について言及します。このステイタスリクエスト(status=18,21,25,29)にはそれぞれ対になるステイタスリクエスト(status=19,22,26,30)があり、それについても詳解します。最後に、これらを周期的・自動的に実行し、実際に連携・同期させるnhpd(status=31)について考えます。 現状、NHPはHTTP上で運用されており、このNHPサーバ間通信もHTTPによる送信と受信、またはその繰り返しにより成立します。HTTPクライアントでは、通常のCGI同様、"?"の後に引数status=XXのように指定します。ステイタスリクエストのナンバー以外にパラメータが必要な場合は、ナンバーに続けて","で区切って付加します。また、すべての返信のMIMEタイプはtext/plainになります。 各ステイタスリクエストの返り値(出力)は、ステイタスリクエスト16はIPアドレス(xxx.xxx.xxx.xxx)、ステイタスリクエスト23は16文字以上の英数字、ステイタスリクエスト28は鍵長128bit以上のRSA暗号鍵の「公開指数,公開鍵」となり、それ以外は仕様の7. 返り値と10. 返り値に規定されたものになります。また、端末から実行されたステイタスリクエストの端末への出力に関しては、ステイタスリクエスト0(祝日データの取得)とステイタスリクエスト1(サーバのステイタス情報の取得)以外は未定義となっていますが、nhp.cgiの実装ではステイタスリクエスト1に準拠しています。 以下の項目名は、nhp.cgi内の関数名、もしくはログステイタスに対応する通称であり、草案として規定しているものではありません。草案として規定しているのは、ステイタスリクエストナンバーのみです。 また、X_で始まるステイタス情報の項目名・出力形式などは草案の前段階である試案です。ステイタス情報は最初の二行以降は人間の目で確認するためのもので人間が目で見てわかればいいという位置づけなのですが、非対話的処理にも堪えうるような項目名・出力形式を目指しています。 なお、以下のすべての事例ではcountryを省略しています。複数のcountryに対応するNHPサーバでデフォルトでないcountryに個別でステイタスリクエスト(status=18,21,25,29)を送る場合は、countryの指定が必要です。 get_ip_addressは、相手方サーバに自己のIPアドレスを問い合わせます。相手方は、問い合わせてきたホストのIPアドレスをxxx.xxx.xxx.xxx形式で返します。このIPアドレスは、自己の同定やセキュリティキーの一部として使われます。
check_identifierは、ステイタスリクエストを要求してきたサーバが本当にそのステイタスリクエストを要求してきたサーバなのかを確認します。多くのステイタスリクエストにはランダムな文字列(ident_key)が付加されており、NHPサーバはステイタスリクエストを要求してきたサーバにこの文字列の一部(先頭6文字 ident_key_6)で問い合わせ、そのサーバが正しい文字列(ステイタスリクエストに付加されていたident_keyと同じident_key)を返せるかを確認し、確認がとれた後、要求されたステイタスリクエストを実行します。 ident_keyは、英数字のみ16文字以上(大文字小文字は区別します)ですが、nhp.cgiの実装では20桁の数値のみが用いられています。
SERVER_Aは、ident_keyを保持し、かつident_keyをステイタスリクエストXXに付加してSERVER_Bに送信します。SERVER_BがステイタスリクエストXXを受けると付加されているident_keyの先頭6文字をとり、ident_key_6として、自己のURL(SERVER_B_URL)の後に続けてステイタスリクエスト23をSERVER_Aに送信します。SERVER_Aは保持しているident_keyの中からident_key_6に該当するident_keyを探し、SERVER_Bに返します。SERVER_Bは、最初にステイタスリクエストXXで受け取ったident_keyとステイタスリクエスト23で取得したident_keyを比較し、同一であればステイタスリクエストXXを実行します。 NHPサーバはパスワードをRSA暗号化して通信します。get_publickeyはそのためのRSA暗号公開鍵を取得します。SERVER_Aは公開鍵を得るため、自己のURL(SERVER_A_URL)とident_keyをステイタスリクエスト28に付加してSERVER_Bに送ると、SERVER_Bはident_keyを確認(check_identifier)し、確認できたら公開鍵を返します。この時、SERVER_Bは返信した公開鍵に対応する秘密鍵を保持しており、続いて来るであろう暗号化されたセキュリティキーの復号化に備えます。 ステイタスリクエスト28で得られるRSA暗号公開鍵は、「公開指数,公開鍵」とし、鍵長は128bit以上とします。
register_this_serverは、上位サーバに自動更新の登録をします。ステイタスリクエスト18は端末からのみ実行可能です。この場合、設定ファイルに上位サーバを指定しておく必要があります(自動更新の設定)。ステイタスリクエスト19は、ステイタスリクエスト18から起動され、実際に上位サーバへの登録を実行するシステムコマンドです。ステイタスリクエスト18は、まず、公開暗号鍵を取得し、パスワードを暗号化してステイタスリクエスト19を実行します。 自動更新の登録の際のパスワードは、nhp.cgiの実装では自動生成しており、管理者は意識する必要はありません。このパスワードは、nhp.country_code.keyに記録されています。パスワード自体に文字種文字数等の制限はありませんが、RSA暗号の公開鍵長はパスワードよりも長い必要があります。nhp.cgiの実装では40桁弱(128bit以下)の数値のみになっています。
SERVER_Aは、まず、前項の要領でSERVER_Bから公開鍵を取得します(A1-B2)。そして、B2により返ってきた公開鍵でパスワードを暗号化し、A3のenc_keyとします。A3のpk_idはB2で取得した公開鍵の先頭10桁になります。SERVER_Bは、A3を受け、ステイタスリクエスト23でSERVER_Aのident_keyを確認し、確認が完了した後、pk_idに合致する秘密鍵でenc_keyを複合し、複合されたパスワードとともにSERVER_Aを登録します。登録の書式・様態などは実装によります。B4では返り値のみが返り、これを受けてSERVER_Aの端末から実行されたステイタスリクエスト18がステイタス情報をSERVER_Aの端末に出力して終了します。 enc_keyは、数値化されたパスワードを公開指数と公開鍵でべき剰余したものです。 既登録のアカウントに重ねてステイタスリクエスト18を送信した場合、現状の実装では上書きで登録されます。 unregister_this_serverは、上位サーバに登録されている自己の登録を抹消します。最初に自己のIPアドレスを取得した後は、前項のregister_this_serverとほぼ同じ手順で進行し、条件が整うと登録が抹消されます。 SERVER_Aの端末からステイタスリクエスト21が実行されると、まず、自己のIPアドレスをSERVER_Bに問い合わせ(A0)、SERVER_A_IP_ADDRESSを取得します(B0)。次にSERVER_Bから公開鍵を取得し(A1-B2)、enc_keyを生成します。このenc_keyは、「SERVER_A_IP_ADDRESS,password,ident_key」をMD5でハッシュ値を取り、そのハッシュ値を公開指数と公開鍵でべき剰余したものです。enc_keyが生成できたら「SERVER_A_URL,enc_key,ident_key,pk_id」とともにSERVER_Bにステイタスリクエスト22を送ります(A3)。SERVER_Bは、check_identifierでSERVER_Aからのアクセスであることを確認し(B3-A4)、pk_idに合致する暗号鍵で複合したenc_keyと「REMOTE_ADDR(SERVER_A_IP_ADDRESS),password,ident_key」のMD5によるハッシュ値を比較し、一致すればSERVER_Aの登録を抹消し、その結果の返り値をSERVER_Aに返します(B4)。SERVER_Aはその返り値を受け、ステイタス情報を端末に出力してステイタスリクエスト21は終了します。
check_this_server_registeredは、自己が上位サーバに登録されているかを確認します。この草案では登録の削除はサーバ管理者が任意独断で行えるとしているので、常にサーバ管理者により登録が削除されている可能性があります。ステイタスリクエスト25は、これを確認するためのものです。 登録の確認(ステイタスリクエスト25)は、前項の登録の削除(ステイタスリクエスト21)と同一の手順で進行し、最後に登録を削除するようなことはせず、ただ登録に関する情報を返り値として返して終了するだけです。SERVER_Aは、その返り値を受けて、ステイタス情報を端末に出力して終了します。 返り値が0ならば、このサーバは正しく登録されています。0以外の場合は、仕様の7. 返り値および10. 返り値を参照して下さい。nhp.cgiの実装では返り値とは別にステイタス情報「X_THIS_SERVER_REGISTERED」として返り値に対応した文字列を表示します。
update_registered_server(ステイタスリクエスト29)は、ステイタスリクエスト30を登録されているサーバ毎に実行し、登録されているNHPサーバの祝日データを更新します。また、更新の必要がない時は祝日データファイルへの最終アクセス時刻(最後に祝日データが確認された時刻)を更新します。nhp.cgiの実装ではファイルのタイムスタンプを更新しています。 ステイタスリクエスト29は端末からだけではなく、ネットワーク上からも実行可能です。ただし、パスワードによる認証が必要なためネットワーク上から実行できるのは登録されたNHPサーバだけです。つまり、ネットワーク上からステイタスリクエスト29を送信する状況は、下位サーバが上位サーバに対し下位サーバ(自分自身)の更新を強制する場合のみになります。 まず、端末におけるステイタスリクエスト29の使用法について言及します。端末からstatus=29を実行した場合は、登録されているすべてのサーバに対し更新を試みます。 [root@nhp html]# ./nhp.cgi status=29 Content-type: text/plain #0,20171212190445,0.3.0,JPN,1,status=29 #1,20150101,20190302,201712121904,201711240955,0, #COUNTRY,JPN #NHP_SERVER_URL,http://nhp.karing.jp/nhp.cgi #DEFAULT_REQUEST_LEVEL,1 #X_CONF_URL,NONE 0 #X_REGISTER_GUEST_SERVER,OK #X_AUTO_UPDATE,ON #X_NHPD,RUNNING #X_LOG_STATUS,UPDATE_REGISTERED_SERVER #X_CGI_VERSION,0.2.18 #X_SYNC_SERVER,--- http://aoi.example.jp/~nhp/nhp.cgi -- 0 --- #X_SYNC_SERVER,--- http://nhp1.example.com/nhp.cgi -- 0 --- 上記の例では、登録されているサーバは二つあり、その更新の成否について「X_SYNC_SERVER」においてそれぞれ表示されています。URLに続いた数値が返り値で、0は成功を示しています。その他の値は失敗を示しています。返り値の詳細は仕様および11. 返り値を参照して下さい。 登録されているサーバを個別に更新したい場合は、status=29の後に","で区切って対象のURLを指定します。 [root@nhp html]# ./nhp.cgi status=29,http://aoi.example.jp/~nhp/nhp.cgi この上記二つは、自分自身にステイタスリクエスト29を実行させる(自己に登録されているサーバの祝日データを更新する)ためのものですが、自己が登録している上位サーバにステイタスリクエスト29を実行させる(自己の祝日データを更新させる)ためには、status=29,updateを実行します。 [aoi@nhp public_html]# ./nhp.cgi status=29,update 実行すると「X_CONF_URL」にその結果が表示されます。 #X_CONF_URL,http://nhp.karing.jp/nhp.cgi OK renewal 240 「X_CONF_URL」は、本来、上位サーバの状態を示すためのものですが、上位サーバの状態は更新の可否とほぼ同義です。renewalが表示されれば、status=29,updateは成功です。 ここまで、ステイタスリクエスト29の使用法について説明してきましたが、厳密に言えば、これらは草案によるものではなく、nhp.cgiの実装です。サーバ間通信の規約は仕様または草案によるものですが、端末からの入力形式や実行法は規定されていません。また、概要でも触れたようにX_で始まるステイタス情報の項目名・出力形式は草案の前段階の試案です。 ここから、ステイタスリクエスト29の草案による主な規定になります。まず、ステイタスリクエストを端末から実行し、登録されているサーバの祝日データを更新する場合です。登録されたサーバ{server_1,server_2,server_3}があるとすると、ステイタスリクエスト29はそれぞれのサーバにステイタスリクエスト30を実行していきます。すべて終了すると「X_SYNC_SERVER」にそれぞれの結果を表示する上記のようなステイタス情報を出力して終了します。
各登録サーバにステイタスリクエスト30を送る手順は前項・前々項のステイタスリクエスト22,26と同一です。SERVER_Aは自己のIPアドレスを問い合わせ、公開鍵を取得し、enc_keyおよび他のパラメータを生成し、ステイタスリクエスト30を送信します。ステイタスリクエスト29は、これを各登録サーバに実行していきます。 enc_keyはステイタスリクエスト22,26と同様に「SERVER_A_IP_ADDRESS,password,ident_key」をMD5でハッシュ値を取り、そのハッシュ値を公開指数と公開鍵でべき剰余したものです。 ステイタスリクエスト30とステイタスリクエスト22,26は実行手順は同じですが、ステイタスリクエスト30ではパラメータが増えています。それが上記A3のs_infoです。s_infoは4つのパラメータから構成されています。 s_info=MD5ハッシュ値,ルートサーバからの階層,エラーの伝搬階層,ルートサーバからの時間的距離 「MD5ハッシュ値」は、祝日データのMD5ハッシュ値で祝日データの同一性を調べるためのものです。ステイタスリクエスト2で出力される全祝日データのMD5ハッシュ値です。「ルートサーバからの階層」は、ルートサーバを0とし、SERVER_Aがルートサーバから何番目のサーバであるかを示します。「エラーの伝搬階層」は、応答のなくなった上位サーバを持つNHPサーバを1として自己が何番目のサーバであるかを示します。ルートサーバまで問題がない場合は0になります。「ルートサーバからの時間的距離」は、ルートサーバからの更新が到達するまでの時間を分単位で示しています。この時間は上位サーバの時間的距離に自己の上位サーバへの時間的距離を足したものです。自己の上位サーバへの時間的距離は、nhpdの周期Rと祝日データの更新間隔Eとすると、この時間的距離Tは「T=R(E/R)+R((E%R))&&1)」で求めます(/の除算は整数の商、%は剰余、&&は論理積)。Tは、更新間隔E以上の周期Rの整数倍の最小値です。詳細はnhpdで解説します。 ステイタスリクエスト23の確認が取れ(B3-A4)、enc_keyによる認証をクリアすると、SERVER_Aからステイタスリクエスト30のパラメータとして送られてきた祝日データのMD5ハッシュ値と自己の祝日データのMD5ハッシュ値を比較し、異なる場合はSERVER_Bは祝日データを更新します。更新法は仕様または草案の規定外ですが、ステイタスリクエスト2で全ての祝日データを取得し、更新することを想定しています。nhp.cgiの実装もそうしています(B4-A5)。また、祝日データに更新の必要がない場合は、B4とA5のセッションはなくなり、SERVER_Bの祝日データの最終確認時刻を更新するだけになります。ステイタスリクエスト30が終了するとSERVER_Bは返り値をSERVER_Aに返し(B5)、SERVER_Aはそれを受けてステイタス情報を端末に出力して終了します。 ステイタスリクエスト29はネットワーク上からも実行可能です。先述したstatus=29,updateの場合です。この場合は、ステイタスリクエスト29を実行するのは端末のあるサーバではなく、自己を登録している上位サーバです。ネットワーク上から上位サーバにステイタスリクエスト29を実行させると上位サーバはステイタスリクエスト30でこちらの祝日データを更新させます。端末からステイタスリクエスト29を実行した場合は、個別に指定しない限り、登録されているサーバ全てを更新させますが、ネットワーク上から実行した場合はアクセスしてきたサーバのみを更新させます。
SERVER_Aの端末からstatus=29,updateを実行すると、SERVER_Aは上位サーバであるSERVER_Bにステイタスリクエスト29を送信します(A0)。それを受けて、上位サーバはステイタスリクエスト29の実行者がSERVER_Aかを確認するためステイタスリクエスト23をSERVER_Aに送信します(B0)。確認ができたら、SERVER_Bはenc_keyを生成するため、自己のIPアドレス(B1-A2)と公開鍵(B2-A4)を取得し、各パラメータを生成し、ステイタスリクエスト30をSERVER_Aに送信します(B4)。ここからは前述したステイタスリクエスト30と同じですが、ステイタスリクエスト30が終了した後(A7)、最後、SERVER_Bがステイタスリクエスト29の返り値をSERVER_Aに返し(B7)、SERVER_Aがそれを受け、ステイタス情報を端末に出力して終了します。 nhpd(ステイタスリクエスト31)はステイタスリクエスト29(厳密にはステイタスリクエスト30)を自動的・周期的に実行する機能です。これまでのステイタスリクエストとは異なり、nhpdは草案によるものではなく、nhp.cgiの実装です。祝日データの更新はルートサーバが祝日データを更新してから1440分(一日)以内に終了しなくてはならない、という規定のみが草案による規定であり、それを実現するための実装がnhpdです。nhpdの設定、使用法については自動更新の設定を参照して下さい。 ルートサーバの端末からステイタスリクエスト29が実行された時は即座に下位サーバにも更新が伝搬していくので、自動的・周期的アクセスは不要にも思えますが、実際の更新時まで対象のサーバが不通であることに気づかなかったということを避けるためとその祝日データがいつの時点での情報であるかを示し、できるだけ最新の状態を保つことの大きく二つの観点から自動的・周期的アクセスは必要であると考えています。また、草案としては更新・同期に関してステイタスリクエスト29の作為的実行を規定してはいない(管理者の実際の行動まで規定していない)ので、ステイタスリクエスト29を管理者が実行しなくても、ルートサーバの祝日データが更新された時は自動的に更新・同期するようなシステムを構築しようというのがnhpdの主旨です。 nhpdは周期的(デフォルトでは2時間毎)にステイタスリクエスト29を実行し、下位サーバの祝日データベースを更新・同期します。前述したように更新の必要がない時は最終確認時刻を更新します。また、nhpdは上位サーバの状態も監視しており、上位サーバによる最後のアクセスからどの程度の時間が経ったかを確認しています。デフォルトでは最終アクセスから3時間が経っても次のアクセスがない場合は、ステイタスリクエスト29,updateで上位サーバに自己の更新を要請します。実際にそうなる時はおそらく何らかの問題が生じており、何らかの対処が必要になる事態であることが予想されます。これらの異常は「X_CONF_URL」に表示されます。 nhpdはデフォルトでは2時間毎に起動します。仮に上位サーバのnhpdが停止しているとすると上位サーバからのアクセスがなくなり、最終アクセスから3時間でnhpdは異常と判断します。nhpdは2時間毎に起動するのでこの異常を捉えるのに4時間かかります。この4時間(240分)が上位サーバとの時間的距離になります。時間的距離はルートサーバから積算して行き、最大1440分(24時間)となります。ルートサーバからの時間的距離が1440分を越えるようなサーバは規定により上位サーバになることができません。自己の上位サーバへの時間的距離の計算方法は、nhpdの周期Rと祝日データの更新間隔Eとすると、この時間的距離Tは「T=R(E/R)+R((E%R))&&1)」で求めます(/の除算は整数の商、%は剰余、&&は論理積)。Tは、更新間隔E以上の周期Rの整数倍の最小値です。現状のnhpdの周期と最終確認時刻からの期限の値は仮のものです。これらの値の適正値についてはこれから検討を要する大きな課題です。 成功は0になります。以下の返り値は仕様の7. 返り値以外に該当するもので仕様に該当するエラーではその仕様の返り値が返ります。 501 … ident_key不一致 502 … 認証エラー 503 … ident_key取得エラー 504 … RSA公開鍵取得エラー 505 … IPアドレス取得エラー 506 … ident_key不整合 508 … 登録未対応 509 … 抹消済み 510 … 無効なセッション 512 … root server protection 515 … server error 516 … unknown error 509の「抹消済み」は何らかのステイタスリクエストが要請された時、それに必要な登録がない場合に返されますが、厳密には抹消されたのか元々ないのかはわかりません。ただし、下位サーバに登録の設定が残っている場合は抹消されたことが予想されます。510は通信が開始されていない時に想定外のリクエストを受け取った場合に返されます。512の「root server protection」は設定ファイルでルートサーバであることが設定されているサーバの祝日データを自動更新などで上書きしようとしている時に返されます。設定ファイルでルートサーバであることが設定されているサーバは自動更新による祝日データの上書きを拒絶します。515の「server error」は、単純に言えば、nhp.cgiのエラーではなく、Webサーバがエラーを返している場合の返り値です。なお、各エラー名は通称です。 nhpdの返り値(NHPD_SYNC_ENDとしてループ一回ごとにログに記載される値)は、登録されたサーバを更新するごとに桁を上げていき、更新に成功した場合を0、失敗した場合を1とし、2進数の総和をとったものです。登録されたサーバが5台あり、一番目と四番目のサーバの更新に失敗したときは、01001となり、ログに記載される値は9(1+8)となります。ただし、nhpdは草案によるものではないのでこの値も草案によるものではありません。 この草案は複数のサーバ間にまたがる事象を規定しています。これを鑑み、不測の事態に対しても管理者が柔軟な対応ができるように、管理者は強い権限を有する、とします。具体的には、登録された下位サーバの登録の抹消や、rsa.dbやident_key.dbなどの一時ファイルの扱いなどに関しては何の通告もなしに任意独断で対処、処理することができ、それらの行為がNHPサーバの適切な管理運用の範囲を逸脱しない限り、それらの行為に関して何の責任も生じない、とします。 また、この草案では試案、未定義となっている規定が多々あります。必ずしも規定することが正しいわけではありませんが、何を規定して何を規定しないかも含め、検討の余地が多々あります。さしあたってはステイタス情報の各項目とその形式などは確定したいと思っています。また、nhpdの周期や期限に関してはケーススタディが必須であると考えています。 事実上、nhp.cgiはこの草案そのものです。とはいえ、nhp.cgiの実装は流動的でもあり、バグなのか、修正されているのか判別のつかない状況もあるのではないかと思っています。何かおかしなことがあった時は気軽にご報告、ご意見などいただければ幸いです。 |