CubicLouve

Spring_MTの技術ブログ

バイナリファイルを見る方法

白く塗りつぶしたpngファイルの例でやってみる。

% convert -size 128x128 xc:white white.png

vimを使う場合

vim -b white.png

でバイナリモードでvimで開いた後に下記コマンドでバイナリダンプします。

:%!xxd
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
00000010: 0000 0080 0000 0080 0100 0000 00eb 455c  ..............E\
00000020: 6600 0000 0467 414d 4100 00b1 8f0b fc61  f....gAMA......a
00000030: 0500 0000 2063 4852 4d00 007a 2600 0080  .... cHRM..z&...
00000040: 8400 00fa 0000 0080 e800 0075 3000 00ea  ...........u0...
00000050: 6000 003a 9800 0017 709c ba51 3c00 0000  `..:....p..Q<...
00000060: 0262 4b47 4400 01dd 8a13 a400 0000 0774  .bKGD..........t
00000070: 494d 4507 e602 170e 1622 78a1 b740 0000  IME......"x..@..
00000080: 001f 4944 4154 48c7 63f8 8f06 1846 0546  ..IDATH.c....F.F
00000090: 0546 0546 0546 0546 0546 0546 0568 2b00  .F.F.F.F.F.F.h+.
000000a0: 0004 a0f8 6a22 6527 5400 0000 2574 4558  ....j"e'T...%tEX
000000b0: 7464 6174 653a 6372 6561 7465 0032 3032  tdate:create.202
000000c0: 322d 3032 2d32 3354 3134 3a32 323a 3334  2-02-23T14:22:34
000000d0: 2b30 303a 3030 d063 4c5a 0000 0025 7445  +00:00.cLZ...%tE
000000e0: 5874 6461 7465 3a6d 6f64 6966 7900 3230  Xtdate:modify.20
000000f0: 3232 2d30 322d 3233 5431 343a 3232 3a33  22-02-23T14:22:3
00000100: 342b 3030 3a30 30a1 3ef4 e600 0000 0049  4+00:00.>......I
00000110: 454e 44ae 4260 82                        END.B`.

ちなみにバイナリモードでファイルを開かないとバイナリ表示がおかしくなるので注意 下記はバイナリモードで開かなかった場合のバイナリダンプ

00000000: 3f50 4e47 0d0a 1a0a 0000 000d 4948 4452  ?PNG........IHDR
00000010: 0000 003f 0000 003f 0100 0000 003f 455c  ...?...?.....?E\
00000020: 6600 0000 0467 414d 4100 003f 3f0b 3f61  f....gAMA..??.?a
00000030: 0500 0000 2063 4852 4d00 007a 2600 003f  .... cHRM..z&..?
00000040: 3f00 003f 0000 003f 3f00 0075 3000 003f  ?..?...??..u0..?
00000050: 6000 003a 3f00 0017 703f 3f51 3c00 0000  `..:?...p??Q<...
00000060: 0262 4b47 4400 01dd 8a13 3f00 0000 0774  .bKGD.....?....t
00000070: 494d 4507 3f02 170e 1622 783f 3f40 0000  IME.?...."x??@..
00000080: 001f 4944 4154 483f 633f 3f06 1846 0546  ..IDATH?c??..F.F
00000090: 0546 0546 0546 0546 0546 0546 0568 2b00  .F.F.F.F.F.F.h+.
000000a0: 0004 3f3f 6a22 6527 5400 0000 2574 4558  ..??j"e'T...%tEX
000000b0: 7464 6174 653a 6372 6561 7465 0032 3032  tdate:create.202
000000c0: 322d 3032 2d32 3354 3134 3a32 323a 3334  2-02-23T14:22:34
000000d0: 2b30 303a 3030 3f63 4c5a 0000 0025 7445  +00:00?cLZ...%tE
000000e0: 5874 6461 7465 3a6d 6f64 6966 7900 3230  Xtdate:modify.20
000000f0: 3232 2d30 322d 3233 5431 343a 3232 3a33  22-02-23T14:22:3
00000100: 342b 3030 3a30 303f 3e3f 3f00 0000 0049  4+00:00?>??....I
00000110: 454e 443f 4260 3f0a                      END?B`?.

hexdumpコマンドを使う場合

受け取ったデータを8進数や16進数でダンプする。(デフォルト16進数) hexdumpはオプションなしでは、2バイト単位で処理し、リトルエンディアン(最下位のバイトから順番に表示)で表示します。 -C オプションをつけることで1バイトずつ処理をする。

なので、基本 -C オプションを付けて使う。

% hexdump -C white.png
00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 80 00 00 00 80  01 00 00 00 00 eb 45 5c  |..............E\|
00000020  66 00 00 00 04 67 41 4d  41 00 00 b1 8f 0b fc 61  |f....gAMA......a|
00000030  05 00 00 00 20 63 48 52  4d 00 00 7a 26 00 00 80  |.... cHRM..z&...|
00000040  84 00 00 fa 00 00 00 80  e8 00 00 75 30 00 00 ea  |...........u0...|
00000050  60 00 00 3a 98 00 00 17  70 9c ba 51 3c 00 00 00  |`..:....p..Q<...|
00000060  02 62 4b 47 44 00 01 dd  8a 13 a4 00 00 00 07 74  |.bKGD..........t|
00000070  49 4d 45 07 e6 02 17 0e  16 22 78 a1 b7 40 00 00  |IME......"x..@..|
00000080  00 1f 49 44 41 54 48 c7  63 f8 8f 06 18 46 05 46  |..IDATH.c....F.F|
00000090  05 46 05 46 05 46 05 46  05 46 05 46 05 68 2b 00  |.F.F.F.F.F.F.h+.|
000000a0  00 04 a0 f8 6a 22 65 27  54 00 00 00 25 74 45 58  |....j"e'T...%tEX|
000000b0  74 64 61 74 65 3a 63 72  65 61 74 65 00 32 30 32  |tdate:create.202|
000000c0  32 2d 30 32 2d 32 33 54  31 34 3a 32 32 3a 33 34  |2-02-23T14:22:34|
000000d0  2b 30 30 3a 30 30 d0 63  4c 5a 00 00 00 25 74 45  |+00:00.cLZ...%tE|
000000e0  58 74 64 61 74 65 3a 6d  6f 64 69 66 79 00 32 30  |Xtdate:modify.20|
000000f0  32 32 2d 30 32 2d 32 33  54 31 34 3a 32 32 3a 33  |22-02-23T14:22:3|
00000100  34 2b 30 30 3a 30 30 a1  3e f4 e6 00 00 00 00 49  |4+00:00.>......I|
00000110  45 4e 44 ae 42 60 82                              |END.B`.|
00000117

xxdコマンドを使う場合

ファイルを16進数でダンプする。 復元もできるのがポイント。

% xxd white.png
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
00000010: 0000 0080 0000 0080 0100 0000 00eb 455c  ..............E\
00000020: 6600 0000 0467 414d 4100 00b1 8f0b fc61  f....gAMA......a
00000030: 0500 0000 2063 4852 4d00 007a 2600 0080  .... cHRM..z&...
00000040: 8400 00fa 0000 0080 e800 0075 3000 00ea  ...........u0...
00000050: 6000 003a 9800 0017 709c ba51 3c00 0000  `..:....p..Q<...
00000060: 0262 4b47 4400 01dd 8a13 a400 0000 0774  .bKGD..........t
00000070: 494d 4507 e602 170e 1622 78a1 b740 0000  IME......"x..@..
00000080: 001f 4944 4154 48c7 63f8 8f06 1846 0546  ..IDATH.c....F.F
00000090: 0546 0546 0546 0546 0546 0546 0568 2b00  .F.F.F.F.F.F.h+.
000000a0: 0004 a0f8 6a22 6527 5400 0000 2574 4558  ....j"e'T...%tEX
000000b0: 7464 6174 653a 6372 6561 7465 0032 3032  tdate:create.202
000000c0: 322d 3032 2d32 3354 3134 3a32 323a 3334  2-02-23T14:22:34
000000d0: 2b30 303a 3030 d063 4c5a 0000 0025 7445  +00:00.cLZ...%tE
000000e0: 5874 6461 7465 3a6d 6f64 6966 7900 3230  Xtdate:modify.20
000000f0: 3232 2d30 322d 3233 5431 343a 3232 3a33  22-02-23T14:22:3
00000100: 342b 3030 3a30 30a1 3ef4 e600 0000 0049  4+00:00.>......I
00000110: 454e 44ae 4260 82                        END.B`.

xxd -r でdumpしたファイルから復元して新しいデータとして保存する

lsofの使い方まとめてみた

github.com

lsof コマンドはプロセスがオープンしているファイルの一覧を表示します。

manには下記のように記載されている。

lsof - list open files

ファイルはディスク上のファイルだけでなく、ネットワークソケット、デバイスなども含まれるため、オープンしているファイルを調べることで、ネットワークのリッスンしているポート(待受ポート)などもわかりネットワーク周りの調査でもよく使うコマンド。

表示項目

項目 説明
COMMAND プロセス名(+c num で必要な文字数取れる)
PID プロセスID
USER 実行ユーザー
FD ファイルディスクリプター(それに続く英字1文字は r read access、w write access、u read and write access を指す)
TYPE ファイルの種別、例) IPv4IPv4 socket、LINK は symbolic link fileとか
DEVICE バイス番号
SIZE/OFF ファイルサイズまたはオフセット、0t または 0xで始まる場合はオフセット
NODE ファイルのノード番号 だったりインターネットプロトコルだったりする
NAME ファイル名だったりマウントポイント名だったり
リモートアドレス(<net>:[<node>:]<port> とそれに続いて接続状態も表示される場合もある ) だったりする

オプション

lsof(8) - Linux manual page

オプション 説明
-n 名前解決をせずにIPアドレスを表示する。名前解決をしないので高速に表示されます
-P ポート番号をポート名に変換しない。 例) 443 ポートを https に変換しない
+c プロセス名の表示数(15まで、0を指定すると最大になる)
-i ネットワークファイルのみを対象とする。色々書き方があり、-iTCP だとTCPのみ、-i:ポート番号 で利用しているポートで絞り込める
形式は→ [46][protocol][@hostname|hostaddr][:service|port]
-U Unix domain socketの一覧を取得する

よく使うコマンド

UDP一覧

lsof -n -P +c 0 -iUDP 

複数の特定ポート

lsof -n -P +c 0 -i:8080,3000

create-clusterコマンドを使ってローカルでredis clusterを簡単に作成する方法

redis の中に 含まれている create-cluster コマンドを使うと、Redis Clusterを簡単にローカルで立てることができたのでそのメモ。

手順

redisをcloneしてくる

git clone git@github.com:redis/redis.git
cd redis

redisをビルドする

make

自分の環境ではmacOSでビルドは通っている。

create-clusterコマンドがあるdirectoryまで移動

cd utils/create-cluster

必要であれば config.sh を置いて環境変数を設定する

config.sh というファイルがあるとcreate-cluster は自動的にそれを読み込んでくれる。

設定可能な環境変数は下記を参照

github.com

BIN_PATHを設定すれば、任意のredis-cliコマンドの場所を指定できる。

redis clusterに必要なnodeを立てる

create-cluster start を実行してnodeを作る

 % ./create-cluster start
Starting 30001
Starting 30002
Starting 30003
Starting 30004
Starting 30005
Starting 30006

作成したnodeをclusterにする

% ./create-cluster create
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:30005 to 127.0.0.1:30001
Adding replica 127.0.0.1:30006 to 127.0.0.1:30002
Adding replica 127.0.0.1:30004 to 127.0.0.1:30003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: df85f1ae9a3ac6728d80db7e7545c036eefff225 127.0.0.1:30001
   slots:[0-5460] (5461 slots) master
M: c195571fa6c08fef6319591e71148817934f87b4 127.0.0.1:30002
   slots:[5461-10922] (5462 slots) master
M: 34a8974de69408ec6956834363392f3735cf6f96 127.0.0.1:30003
   slots:[10923-16383] (5461 slots) master
S: ca3c5200b2b57ea7242955024418df051a16609a 127.0.0.1:30004
   replicates df85f1ae9a3ac6728d80db7e7545c036eefff225
S: 15aebd8d8d14bd3df30ee5ee3c72d02b75101d12 127.0.0.1:30005
   replicates c195571fa6c08fef6319591e71148817934f87b4
S: 69f8274ef598072797ada3e2b7d458a50ebd4f62 127.0.0.1:30006
   replicates 34a8974de69408ec6956834363392f3735cf6f96
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join

>>> Performing Cluster Check (using node 127.0.0.1:30001)
M: df85f1ae9a3ac6728d80db7e7545c036eefff225 127.0.0.1:30001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 15aebd8d8d14bd3df30ee5ee3c72d02b75101d12 127.0.0.1:30005
   slots: (0 slots) slave
   replicates c195571fa6c08fef6319591e71148817934f87b4
M: c195571fa6c08fef6319591e71148817934f87b4 127.0.0.1:30002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 69f8274ef598072797ada3e2b7d458a50ebd4f62 127.0.0.1:30006
   slots: (0 slots) slave
   replicates 34a8974de69408ec6956834363392f3735cf6f96
S: ca3c5200b2b57ea7242955024418df051a16609a 127.0.0.1:30004
   slots: (0 slots) slave
   replicates df85f1ae9a3ac6728d80db7e7545c036eefff225
M: 34a8974de69408ec6956834363392f3735cf6f96 127.0.0.1:30003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

[OK] All 16384 slots covered. がでれば、clusterの作成が完了となる。

その他

ログの確認

% ./create-cluster tailall 

クラスタを止める

% ./create-cluster stop

デカフェの生茶は普通の生茶より美味しい

生茶にはデカフェ版があるのですが、これ普通の生茶より美味しい気がしているんですよね。

お茶の旨味はしっかりと残っているんだけど、渋みが減っていてすっきり飲みやすい。

夏におすすめの一品です。

店頭で並んでいることがほとんどないので、流行ったらおいてくれるようになるかな???

店頭に並ぶことを期待してブログに書いてみました。

デカフェ生茶流行れーーー

物理クロック 論理クロック

物理クロック

ほぼすべてのコンピューターには、内蔵されている水晶発振器によって時刻を計算しています。

水晶は安定した周波数の電気信号を発振するため、振動子として広く使われています。

パソコンの電源が切れたり、充電が切れたりしても、マザーボードに内蔵されているCMOSバッテリーにより水晶は時刻を計算し続けれます。

この水晶発振器は個体ごとに誤差があるため、異なるコンピューターでは全て同じ周波数で動作はしません。

(月で±15秒とか)

時刻同期

上記の通り、複数台のコンピューターがあると、徐々に時間はずれていき、読み出したときに異なる時刻を示すようになります。

これはclock skewと呼ばれます。

手動で時刻を合わせても発振器の誤差の影響などですぐに時刻がずれてしまうので、手動ではなく自動的にコンピュータの時刻同期ができれば、これらの問題を解決することができます。

これを実現するために用いられるのが時刻を同期させるプロトコルがNTPです。

www.spring8.or.jp

ja.wikipedia.org

xtech.nikkei.com

NTP

NTP は、正確な運針をもつ NTP サーバに一致させ、その後時刻を一定の誤差範囲内で維持する仕組みになっています。

つまり、NTP サーバの時刻変更に対して、NTP クライアントの時刻がこれに同期するというものではありません。

NTP プロトコルは、下記 3つで構成されています。

  • リファレンスクロック(stratum 0) : 原子時計GPS電波時計などを使った精度の高い外部時計をもったサーバー
  • NTP サーバ(stratum 1〜) : 信頼できる上位サーバから提供される時刻を利用して自分の時刻を保持し、他のマシンあるいは下位のサーバに時刻を提供する
  • NTP クライアント : NTP サーバから時刻を提供される

NTPはネットワークを介して時刻同期を行います。

単純に相手のサーバが通知してきた時刻を信頼するだけでは、 ネットワークの遅延により時刻のずれが発生してしまいます。

そのため、NTPではサーバ・クライアント間の通信において、 NTPメッセージを送信した時刻、受信した時刻を、 サーバ・クライアントそれぞれがメッセージの中に含めており、これらを使ってネットワークでの遅延時間を推測し、ずれの少ない時刻同期を図っています。

en.wikipedia.org

下記シーケンスを元に考えてみます。

f:id:Spring_MT:20210520162421p:plain

クライアントとサーバーは時刻はずれているとします。

パケットの往復時間(ラウンドトリップ)Δは下記になります。

Δ = (Tc2- Tc1) - (Ts2 - Ts1)

また、時刻差(タイムオフセット) θ はNTPサーバーの時刻と往復時間の半分(パケットの片道は往復の1/2として固定している) と NTPクライアントの時刻の差となります。

θ = (Ts2 + Δ / 2) - Tc2 = Ts2 + ((Tc2- Tc1) - (Ts2 - Ts1)/2) - Tc2 = (Ts2 + Ts1) / 2 - (Tc2 + Tc2) / 2

θ に基づいてNTPクライアントの時刻を調整します。

参照

www.infraexpert.com

www.nic.ad.jp

ja.wikipedia.org

その他の時刻同期の仕組み

NTP以外にも時刻同期をする仕組みはあります。

その一つにBerkeleyアルゴリズムを用いるものがあります。

NTPはクライアントが定期的にNTPサーバー(タイムサーバー)に通信して時刻を同期しているのに対して、Berkeleyアルゴリズムではタイムサーバーが全てのマシンに対して定期的にポーリングし、応答に基づいてメッセージの往復時間を計算し、現在の時間を平均化し、ローカルクロックを調整する必要があることをクライアントに通知します。

ja.wikipedia.org

論理クロック

クロックスキューの問題などで、物理クロックの完全な同期は現実的には難しいです。

しかし、例えばシステム中のイベントのタイムラインにおいて、イベントの相対順序を決めるためには時刻の絶対値は必ずしも必要ありません。

イベントAがイベントBの前に起こることを知る必要がある場合、Ta=2、Tb=6でも、Ta=4、Tb=10であっても、Ta < Tbが満たされていれば問題ありません。

このようなシチュエーションにおいてはインクリメントされるカウンタに基づいてイベントの順序付けを行うほうが安全性が高いです。

物理クロックではなく、インクリメントされるカウンタに基づくものを論理クロックと呼びます。

Lamportの論理クロック

Lamportの論文( https://www.microsoft.com/en-us/research/uploads/prod/2016/12/Time-Clocks-and-the-Ordering-of-Events-in-a-Distributed-System.pdf ) では、 クロックの同期は必要だが、絶対値的なものである必要はないことを示しました。

2つのプロセスが相互作用しない場合(並行な場合)、クロックを同期させる必要はなく同期していないことは観測できないため、問題にはならない、さらに通常重要なのは、すべてのプロセスが正確な時間に合意することではなく、イベントが発生する 順序 に合意することであると述べています。

論理クロックの同期のために、happens-before 関係を定義しています。

happens-before 関係 は 以下の3つの条件を満たしている最小の関係としています。(happens-before は日本語では事前発生と訳されます。データ指向アプリケーションデザイン p 199参照)

  1. aとbが同じプロセスのイベントで、bの前にaがくる(aがbよりも先に起こる)場合、a → bとなる。
  2. aがあるプロセスによるメッセージの送信であり、bが他の別のプロセスによる同じメッセージの受信であるならば、a → b (これはaがbに因果関係がある)
  3. a → b、b → cならば、a → c

また、a ↛ b かつ b ↛ a で、aとbのイベントが異なるイベントは concurrent(並行) と呼びます。

つまり、a bのどちらも先に行われていない、互いに相手を知らないのであれば、これらは並行していることになります。

全てのイベントに対して、全てのプロセスが合意する時間の値、論理クロックを定義します。

ここでは、論理クロックは下記のように定義します。

  • 各プロセスPiのクロックCiは、プロセス Piにおける任意のイベント a に番号 Ci<a> を割り当てる関数である
  • このシステム全体としてのクロックは、任意のイベント a に数値 C<a> を割り当てる関数 C とする。
    • bがPjというプロセスのイベントであれば、 C<b> = Cj<b> となる つまり、C はすべてのプロセスが合意する時間の数値を割り当てる

その上で、この論理クロックがイベントの発生する順序に基づいて正しく振る舞うための条件は、 あるイベント aが他のイベント bよりも先に発生した場合、a は b よりも早い時間に発生すべき ということになります。

これは、

イベントaとbにおいて、 a → b であれば C<a> < C<b>

となります。

これは 、前述の happens-beforeの関係を考えると、

  • C1 プロセスPiのイベントaとbにおいて、aがbの前に発生した場合、 Ci<a> < Ci<b>
  • C2 プロセスPiのメッセージ 送信 a で プロセスPjでのメッセージの受信 b の場合 Ci<a> < Cj<b>

の2つの条件を満たすことになります。

これらの条件を満たす実装のルールは下記の通りです。

  1. 各プロセスPiは連続する2つのイベントの間にCiを増加させる。つまりa → b であれば bのイベントの前にCiを増加させる 2-a. イベントaは プロセスPiで mというメッセージ送信のイベントだとすると、メッセージ m にはタイムスタンプ Tm = Ci <a> が含まれている 2-b. Piとは別のプロセスPjがメッセージ mを受信すると、PjはCjの値を現在の値以上かつ、Tmの値より大きい値をセットする

イベントaがプロセスPiで Ci<a> に発生すると、システム全体の論理クロック C<a> = Ci<a> に割り当てることで分散した環境での論理クロックが構築できます。

参照

medium.com

ieeexplore.ieee.org

www.distributed-systems.net CHAPTER6. COORDINATIONあたり

www.slideshare.net

  • データ指向アプリケーションデザイン p377あたり

他にも参考にした文献

www.spring8.or.jp

ja.wikipedia.org

xtech.nikkei.com

uchan.hateblo.jp

Tail Latencyについて

research.google

この論文では、大規模な分散システムでは、まれなパフォーマンスの低下であっても、全リクエストのかなりの部分に影響を与えるとあります。

つまり大規模な分散システムではテールレイテンシの影響が大きくなります。

テールレイテンシは大きなパーセンタイルのレスポンス値のことです。(大きいというのがp99なのかp99.9なのかは文脈次第です)

パーセンタイルの例としては、99 パーセンタイルのレスポンスタイムが 100 msとすると、平均して 100 リクエスト中の 99リクエストには 100 ms未満しかかからず、1 リクエストには 100 ms以上かかることを意味します。

例えば、各サーバが通常10msで応答し、99%のレイテンシーが1秒であるシステムを考えてみると、ユーザーのリクエストがそのようなサーバー1台だけで処理された場合、1/100の確率でユーザーのリクエストが遅く(1秒かかる)なります。

このサーバー群に対して、ユーザーのリクエストが100台のサーバーから並行してレスポンスを収集しなければならない場合、ユーザーのリクエストの63%が1秒以上かかることになります。

1台のサーバレベルで1秒以上の遅延が発生するのが1万件に1件のサービスであっても、そのようなサーバが2,000台あるサービスでは、5件に1件の割合(18%)で1秒以上の遅延が発生することになります。

これはテールレイテンシの増幅と呼ばれます。(データ指向アプリケーションデザインp 17のコラム参照)

Googleような大規模な分散システムではテールレイテンシが全体のパフォーマンスに大きく影響します。

マシンの共有リソースの競合( CPUとか )、バックグランド処理などいろいろな要因で高いテールレイテンシが発生します。

大規模システムにおいて、レイテンシの変動の要因をすべて排除することは現実的ではないですが、この論文では、突発的、一時的な遅延を隠蔽したり、回避するすることでテールレイテンシを改善する手法を紹介しています。

数十ミリ秒の時間スケールで動作するリクエスト内の即時応答での対応

多くのWebサービスでは、データアイテムの複数のレプリカを配置することで、スループットを向上させ、障害が発生しても可用性を維持しています。

この対応では、レプリカを使って、1つの高レベルのリクエスト内のレイテンシーの変動を抑えます。

Hedged Requests

遅延のばらつきを抑える簡単な方法は、 同じ リクエストを複数のレプリカに発行し、いずれかのレプリカが先に応答した結果を使用することです。

クライアントは、最初の結果を受け取ると、残りの未処理のリクエストをキャンセルします。

このようなリクエストは Hedged requests と呼ばれています。

en.wikipedia.org

(この Hedged は金融用語の意味での両掛けから引用していると思っています)

この技術をnaiveに実装すると、通常は許容できないほどの負荷が追加されますが、負荷の増加をわずかに抑えながら、ほとんどの遅延削減効果を得られる多くのバリエーションが存在します。

アプローチの1つに、最初のリクエストが、このクラスのリクエストに対する95パーセンタイルの予想待ち時間を超えて未処理になるまで、2番目のリクエストの送信を遅らせるというものがあります。

この方法では、追加の負荷を約5%に抑えつつ、レイテンシーテールを大幅に短縮することができます。

この技術が有効なのは、レイテンシーの原因が特定のリクエストに固有のものではなく、他のなんらかの形態の干渉によるものであることが多いためです。

論文内では、100台の異なるサーバに分散しているBigTableのテーブルに格納された 1000個のキーの値を読み取るGoogleベンチマークが紹介されていました。

10msの遅延後にヘッジ付きリクエストを送信すると、わずか2%のリクエスト数の増加で、1000個の値をすべて取得する際の 99.9%タイルの遅延が 1,800ms から 74msに短縮されたとありました。

Hedged requestsのオーバーヘッドは,プライマリリクエストよりも優先度の低いリクエストとしてタグ付けすることで,さらに低減することができます。

Tied Request

Hedged requests には、複数のサーバが同じリクエストを不必要に実行してしまうという脆弱な側面があります。

この余分な作業はは上記で紹介したような方法で緩和はできますが、この方法ではメリットが得られるのはごく一部のリクエストに限られてしまいます。

適切なリソースの消費で Hedged requests のより積極的な利用を可能にするには、リクエストをより速くキャンセルする必要があります。

一般的なレイテンシの変動要因は、リクエストが実行を開始する前のサーバでのキューイングの遅延です。

多くのサービスでは、リクエストが実際にスケジューリングされ、実行がはじまれば、その実行の完了時間のばらつきは大幅に減少します。

そこでGoogleでは、同時に複数のサーバにリクエストのコピーをエンキューし、サーバがこれらのコピーのステータスに関する更新情報を相互に通信できるようにしました。

サーバがサーバ間でステータスの更新を行うリクエストのことは Tied request と呼ばれています。

Tied request の最も単純な形式は、クライアントが2つの異なるサーバーにリクエストを送信し、それぞれのサーバーにもう一方のサーバーがタグ付けされます(結びつけられた tied)。

あるリクエストが実行を開始すると、そのリクエストは相手にキャンセルメッセージを送ります。 キャンセルメッセージに対応するリクエストは、もう一方のサーバーにまだキューが残っているときは、直ちに中止するか、大幅に優先順位を下げます。

Googleはこの手法をクラスタレベルの分散ファイルシステムに実装しており、中央値と末尾値の両方の遅延を減らすのに効果的であることを紹介しています。

その中では、サーバー間のキャンセルを行う Tied request は、レイテンシーの中央値(50パーセンタイル)を16%削減し、レイテンシー分布の末尾に向かうにしたがって効果が増していき、99.9パーセンタイルのレイテンシーで40%近い削減を達成したとありました。

数十秒から数分の時間スケールで実行され、より長期的な現象の影響を隠すことを目的としたリクエストを跨いだ長期的な適応

多くのシステムでは、各パーティションのコストが等しくなるようにデータを分割しようとしますが、各マシンに単一のパーティションを静的に割り当てることは、下記から実際には十分ではありません。

  • サーマルスロットリングや共有ワークロードの干渉などにより、ベースとなるマシンの性能は 時間軸上で均一でも一定でもありません。
  • 分割したのアイテムの割り当てに外れ値があると、データによる負荷の不均衡が発生する可能性があります(特定のアイテムが注目され、そのパーティションの負荷が増加する、有名人対応みたいないこと)

マイクロパーテーション

不均衡に対処するために、Googleのシステムの多くは、サービス内のマシンの数よりも 多くパーティションを生成し、これらのパーティションを特定のマシンに動的に割り当ててロードバランシングを行います。

ロードバランシングする側は、これらの小さなパーティションの1つをあるマシンから別のマシンに移すことに対しての責務があります。

選択的レプリケーション

マイクロパーティション方式の拡張機能として、負荷の不均衡を引き起こす可能性の高い特定のアイテムを検出、あるいは予測し、そのアイテムのレプリカを追加作成することができるようにします。

追加のレプリカを使用して、実際にマイクロパーティションを移動させることなく、これらのホットなマイクロパーティションの負荷を複数のマシンに分散させることができます。

遅延の原因の検定

中間サーバは、システム内の様々なマシンからの応答の遅延分布を観測し、特に遅いマシンを除外したり、検証を行うことでシステムのパフォーマンスが向上できる状況を検出することがあります。

遅延の原因は、無関係なネットワーク・トラフィックによる干渉や、そのマシン上の別のジョブのためのCPU動作の急増など一時的な現象であることが多く、システムの負荷が高いときに速度低下に気が付きやすいです。

システムの負荷が高いときであっても、システムはこれらの除外されたサーバーにシャドーリクエストを発行し続け、そのレイテンシーの統計を取り、問題が解決したときに再びサービスに組み込むことができるようにします。

大規模な情報検索(IR)システムでの対応

Good Enough (Not Best)

最良ではないわずかに不完全な("good-enough")結果で応答することで、エンド・ツー・エンドのレイテンシーが向上しユーザにとって最良のサービスとなる可能性があります。

カナリアリクエス

ファンアウトが非常に大きいシステムで起こりうる一つの問題は、あるリクエストがテストされていないコードパスを実行してしまい、何千ものサーバで同時にクラッシュしたり、非常に長い遅延が発生したりすることです。

このような相関性のあるクラッシュシナリオを防ぐために、Googleの検索システムの一部では、カナリアリクエスト と呼ばれる技術が採用されています。

これは、最初に何千ものリーフサーバにリクエストを送信するのではなく、ルートサーバがまず1つまたは2つのリーフサーバにリクエストを送信するというものです。

残りのサーバーは、ルートが適切な時間内にカナリアから成功した応答を得た場合にのみクエリが発行されるようになります。

カナリアリクエスト の段階では,1台のサーバが応答するのを待たなければならないため,全体的な遅延はわずかであり,大規模なファンアウトリクエストに対してすべてのサーバが応答するのを待たなければならない場合に比べて,変動ははるかに小さくなります。

カナリアリクエスト によってレイテンシーがわずかに増加するにもかかわらず、カナリアリクエスト は安全性が高いため、Googleの大規模ファンアウト検索システムのすべてのリクエストに使用される傾向があります。

ほかでの応用

spring-mt.hatenablog.com

パフォーマンスの変動の対応についてはAuroraにも応用されていることが言及されています。

これらを踏まえて

テールレイテンシへの対応を見ていると、これらを担うコンポーネントはサービスメッシュだよなあと思っています。

Hedge requestなどはenvoyでも実装がありそうです。

www.envoyproxy.io

github.com

github.com

マイクロパーティションのロードバランシング、カナリアなどもサービスメッシュが担う部分かと思います。

また、サーバーの切り離し、シャドーリクエストなどもサービスメッシュの範疇かなと思います。

参照

agnozingdays.hatenablog.com

https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/44875.pdf

qiita.com

gihyo.jp

medium.com

https://drkp.net/papers/latency-socc14.pdf

https://pdfs.semanticscholar.org/dede/f157ad3b5b4df21a6515b1b70ed8ad698422.pdf

証明書と認証局の確認

まずは証明書周りについての整理

証明書

証明書は電子文書。

ja.wikipedia.org

証明書の中には、公開鍵やそれに紐づく情報と証明書の発行元のデジタル署名が含まれています。

現在の公開鍵基盤として広く使われているX.509では、証明書の構造は ASN.1 という記法で定義されています。

www.ipa.go.jp

ASN.1で定義された内容をネットワーク経由で送るには、これをビット列に符号化する必要があり、この符号化ルールの一つがDistinguished Encoding Rules (DER) 。

docs.microsoft.com

DERでエンコードされ更にbase64エンコードしたものがPEMとなります。

証明書でよく見かけるのはこのPEM形式です。

証明書の作成

opensslは1.1.1以降であればEd25519が使えるようになっているので、これを使ってみます。

www.openssl.org

jnst.hateblo.jp

qiita.com

今回手元で確認するだけなので、秘密鍵の内容も記載していますが、本来であれば絶対に記載してはいけない内容です。

% openssl version
OpenSSL 1.1.1g  21 Apr 2020
% openssl genpkey -algorithm ed25519 -out private.pem 

% openssl asn1parse -in private.pem
    0:d=0  hl=2 l=  46 cons: SEQUENCE          
    2:d=1  hl=2 l=   1 prim: INTEGER           :00
    5:d=1  hl=2 l=   5 cons: SEQUENCE          
    7:d=2  hl=2 l=   3 prim: OBJECT            :ED25519
   12:d=1  hl=2 l=  34 prim: OCTET STRING      [HEX DUMP]:042034E86A39818F82B908DB25D3C64ED4053ED47A7855C2CA9303B9866F193C82BE

% openssl pkey -in private.pem -outform DER | od -An -tx1
           30  2e  02  01  00  30  05  06  03  2b  65  70  04  22  04  20
           34  e8  6a  39  81  8f  82  b9  08  db  25  d3  c6  4e  d4  05
           3e  d4  7a  78  55  c2  ca  93  03  b9  86  6f  19  3c  82  be

秘密鍵を生成後にASN.1フォーマットを確認しています。

さらにバイナリにして確認しています。

id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } なので、hexにすると 01 03 65 70 なんですが、なんか微妙に合わないけど、なんかまあ判別できそうな感じはします。

tools.ietf.org

  • CSR( Certificate Signing Request )の生成

次に証明書への署名をCAにリクエストするCSRを生成します。

% openssl req -new -out example.csr -key private.pem
% openssl asn1parse -in example.csr
    0:d=0  hl=3 l= 221 cons: SEQUENCE          
    3:d=1  hl=3 l= 144 cons: SEQUENCE          
    6:d=2  hl=2 l=   1 prim: INTEGER           :00
    9:d=2  hl=2 l=  93 cons: SEQUENCE          
   11:d=3  hl=2 l=  11 cons: SET               
   13:d=4  hl=2 l=   9 cons: SEQUENCE          
   15:d=5  hl=2 l=   3 prim: OBJECT            :countryName
   20:d=5  hl=2 l=   2 prim: PRINTABLESTRING   :JA
   24:d=3  hl=2 l=  14 cons: SET               
   26:d=4  hl=2 l=  12 cons: SEQUENCE          
   28:d=5  hl=2 l=   3 prim: OBJECT            :stateOrProvinceName
   33:d=5  hl=2 l=   5 prim: UTF8STRING        :Tokyo
   40:d=3  hl=2 l=  16 cons: SET               
   42:d=4  hl=2 l=  14 cons: SEQUENCE          
   44:d=5  hl=2 l=   3 prim: OBJECT            :localityName
   49:d=5  hl=2 l=   7 prim: UTF8STRING        :Shibuya
   58:d=3  hl=2 l=  12 cons: SET               
   60:d=4  hl=2 l=  10 cons: SEQUENCE          
   62:d=5  hl=2 l=   3 prim: OBJECT            :organizationName
   67:d=5  hl=2 l=   3 prim: UTF8STRING        :Foo
   72:d=3  hl=2 l=  12 cons: SET               
   74:d=4  hl=2 l=  10 cons: SEQUENCE          
   76:d=5  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
   81:d=5  hl=2 l=   3 prim: UTF8STRING        :Bar
   86:d=3  hl=2 l=  16 cons: SET               
   88:d=4  hl=2 l=  14 cons: SEQUENCE          
   90:d=5  hl=2 l=   3 prim: OBJECT            :commonName
   95:d=5  hl=2 l=   7 prim: UTF8STRING        :footest
  104:d=2  hl=2 l=  42 cons: SEQUENCE          
  106:d=3  hl=2 l=   5 cons: SEQUENCE          
  108:d=4  hl=2 l=   3 prim: OBJECT            :ED25519
  113:d=3  hl=2 l=  33 prim: BIT STRING        
  148:d=2  hl=2 l=   0 cons: cont [ 0 ]        
  150:d=1  hl=2 l=   5 cons: SEQUENCE          
  152:d=2  hl=2 l=   3 prim: OBJECT            :ED25519
  157:d=1  hl=2 l=  65 prim: BIT STRING
% openssl req -text -in example.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = JA, ST = Tokyo, L = Shibuya, O = Foo, OU = Bar, CN = footest
        Subject Public Key Info:
            Public Key Algorithm: ED25519
                ED25519 Public-Key:
                pub:
                    4d:85:35:84:30:4b:78:27:e6:57:2b:cc:3c:e2:55:
                    f5:79:52:ec:53:7e:fa:2a:96:6a:bd:f3:39:1b:28:
                    6c:74
        Attributes:
            a0:00
    Signature Algorithm: ED25519
         3d:cb:8e:d1:83:11:b4:54:3e:e4:a8:a1:42:70:67:ce:bc:21:
         eb:e4:82:57:74:24:03:94:51:e1:bc:b9:06:e2:7d:9c:7e:4f:
         09:3a:c1:1f:7b:30:3d:01:16:f3:13:e1:78:b1:47:39:4c:7a:
         a8:95:a0:89:22:b7:0d:b2:58:03
-----BEGIN CERTIFICATE REQUEST-----
MIHdMIGQAgEAMF0xCzAJBgNVBAYTAkpBMQ4wDAYDVQQIDAVUb2t5bzEQMA4GA1UE
BwwHU2hpYnV5YTEMMAoGA1UECgwDRm9vMQwwCgYDVQQLDANCYXIxEDAOBgNVBAMM
B2Zvb3Rlc3QwKjAFBgMrZXADIQBNhTWEMEt4J+ZXK8w84lX1eVLsU376KpZqvfM5
GyhsdKAAMAUGAytlcANBAD3LjtGDEbRUPuSooUJwZ868Ievkgld0JAOUUeG8uQbi
fZx+Twk6wR97MD0BFvMT4XixRzlMeqiVoIkitw2yWAM=
-----END CERTIFICATE REQUEST-----

CSRには公開鍵が含まれています。(秘密鍵は含まれません。)

CSRを元に証明書を作成します。

下記は自分の秘密鍵で自己署名した自己署名証明書の作成の例です。(自己署名証明書であれば、秘密鍵だけでも作成可能です)

% openssl x509 -req -days 700 -in example.csr -signkey private.pem -out sample.crt 
% openssl x509 -text -in sample.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            6b:c9:75:4e:4a:96:00:a3:b7:cf:c9:81:f1:70:16:4f:ca:b4:e2:5b
        Signature Algorithm: ED25519
        Issuer: C = JA, ST = Tokyo, L = Shibuya, O = Foo, OU = Bar, CN = footest
        Validity
            Not Before: Apr 28 07:13:16 2021 GMT
            Not After : Mar 29 07:13:16 2023 GMT
        Subject: C = JA, ST = Tokyo, L = Shibuya, O = Foo, OU = Bar, CN = footest
        Subject Public Key Info:
            Public Key Algorithm: ED25519
                ED25519 Public-Key:
                pub:
                    4d:85:35:84:30:4b:78:27:e6:57:2b:cc:3c:e2:55:
                    f5:79:52:ec:53:7e:fa:2a:96:6a:bd:f3:39:1b:28:
                    6c:74
    Signature Algorithm: ED25519
         bb:b6:68:cc:76:01:a4:38:7d:6c:4a:00:5e:c5:1f:f3:e8:f1:
         e8:0c:dc:62:03:bc:90:75:66:f0:d7:38:9a:cb:60:23:be:0a:
         b1:76:47:45:81:5a:5f:4c:0f:52:41:4a:9f:99:de:c5:1f:47:
         ac:75:44:3a:f4:8d:24:50:c1:00
-----BEGIN CERTIFICATE-----
MIIBdTCCAScCFGvJdU5KlgCjt8/JgfFwFk/KtOJbMAUGAytlcDBdMQswCQYDVQQG
EwJKQTEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB1NoaWJ1eWExDDAKBgNVBAoM
A0ZvbzEMMAoGA1UECwwDQmFyMRAwDgYDVQQDDAdmb290ZXN0MB4XDTIxMDQyODA3
MTMxNloXDTIzMDMyOTA3MTMxNlowXTELMAkGA1UEBhMCSkExDjAMBgNVBAgMBVRv
a3lvMRAwDgYDVQQHDAdTaGlidXlhMQwwCgYDVQQKDANGb28xDDAKBgNVBAsMA0Jh
cjEQMA4GA1UEAwwHZm9vdGVzdDAqMAUGAytlcAMhAE2FNYQwS3gn5lcrzDziVfV5
UuxTfvoqlmq98zkbKGx0MAUGAytlcANBALu2aMx2AaQ4fWxKAF7FH/Po8egM3GID
vJB1ZvDXOJrLYCO+CrF2R0WBWl9MD1JBSp+Z3sUfR6x1RDr0jSRQwQA=
-----END CERTIFICATE-----

自己署名した証明書を検証してみます。

% openssl verify -CAfile sample.crt sample.crt 
sample.crt: OK

検証とは

www.nic.ad.jp

CA

基本的に証明書の発行はCA(認証局)が行います。

CAはCSRを受け取ると、CSRから公開鍵を取得します。

また、CSRに基づいて証明書の種類に応じた検証(本人確認など)を行います。

確認が終わったら、証明書を作成します。

証明書を作成する際は、証明書にデジタル署名します。

ここでのデジタル署名では、CAの秘密鍵を使って行います。

また、署名に使うハッシュ関数CSRで指定できないので事前に確認が必要です。

自前でCAを作ってみる

よくある話ですが、自前でCAを作って証明書の発行をやってみます。

opensslにはCAを作るコマンドが同梱されています。

github.com

cnfは下記をコピーして使いました。

openssl/openssl.cnf at 4489655c23f1f7f412309e25a5b9fd7acf7db3f2 · openssl/openssl · GitHub

root CAを作る

% OPENSSL=/Users/hoge/http_sample/openssl/apps/openssl OPENSSL_CONFIG="-config ./openssl.cnf" ./CA.pl -newca
CA certificate filename (or enter to create)

Making CA certificate ...
====
/Users/haruyama.makoto/http_sample/openssl/apps/openssl req -config ./openssl.cnf -new -keyout ./demoCA/private/cakey.pem -out ./demoCA/careq.pem 
Generating a RSA private key
.....+....+..+....+...+...+..+...+.............+.....+......+.+..+...+...+.......+..............+.........+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+..+...+....+..+......+....+...........+...+....+...+...+.....+..........+.....+.+..............+......+.+..+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.........+.+...+..+.......+......+..+....+.....+....+............+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.....+.+.........+..+....+.....+..........+...........+...................+..+....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+........+....+.....+.........+......+...+...+............+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JA
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Shibuya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:CaSample
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:ca-sample.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
==> 0
====
====
/Users/hoge/http_sample/openssl/apps/openssl ca -config ./openssl.cnf -create_serial -out ./demoCA/cacert.pem -days 1095 -batch -keyfile ./demoCA/private/cakey.pem -selfsign -extensions v3_ca -infiles ./demoCA/careq.pem 
Using configuration from ./openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            5f:ea:3f:e3:bf:eb:68:e3:13:1c:b4:96:eb:ef:54:5f:5b:bb:cc:89
        Validity
            Not Before: Apr 30 17:38:14 2021 GMT
            Not After : Apr 29 17:38:14 2024 GMT
        Subject:
            countryName               = JA
            stateOrProvinceName       = Tokyo
            organizationName          = CaSample
            commonName                = ca-sample.com
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2
            X509v3 Authority Key Identifier: 
                70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2
            X509v3 Basic Constraints: critical
                CA:TRUE
Certificate is to be certified until Apr 29 17:38:14 2024 GMT (1095 days)

Write out database with 1 new entries
Data Base Updated
==> 0
====
CA certificate is in ./demoCA/cacert.pem

CAの秘密鍵demoCA/private/cakey.pem に、CAの証明書は demoCA/cacert.pem にできます。

この証明書は自己署名になります。

% ../openssl/apps/openssl asn1parse -in demoCA/private/cakey.pem
    0:d=0  hl=4 l=1308 cons: SEQUENCE          
    4:d=1  hl=2 l=  78 cons: SEQUENCE          
    6:d=2  hl=2 l=   9 prim: OBJECT            :PBES2
   17:d=2  hl=2 l=  65 cons: SEQUENCE          
   19:d=3  hl=2 l=  41 cons: SEQUENCE          
   21:d=4  hl=2 l=   9 prim: OBJECT            :PBKDF2
   32:d=4  hl=2 l=  28 cons: SEQUENCE          
   34:d=5  hl=2 l=   8 prim: OCTET STRING      [HEX DUMP]:F7989A7B8D8C5F94
   44:d=5  hl=2 l=   2 prim: INTEGER           :0800
   48:d=5  hl=2 l=  12 cons: SEQUENCE          
   50:d=6  hl=2 l=   8 prim: OBJECT            :hmacWithSHA256
   60:d=6  hl=2 l=   0 prim: NULL              
   62:d=3  hl=2 l=  20 cons: SEQUENCE          
   64:d=4  hl=2 l=   8 prim: OBJECT            :des-ede3-cbc
   74:d=4  hl=2 l=   8 prim: OCTET STRING      [HEX DUMP]:3F41FB1FBA7D297F
   84:d=1  hl=4 l=1224 prim: OCTET STRING      [HEX DUMP]:2B22E6FBC....

% ../openssl/apps/openssl x509 -text -noout -in demoCA/cacert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            5f:ea:3f:e3:bf:eb:68:e3:13:1c:b4:96:eb:ef:54:5f:5b:bb:cc:89
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = JA, ST = Tokyo, O = CaSample, CN = ca-sample.com
        Validity
            Not Before: Apr 30 17:38:14 2021 GMT
            Not After : Apr 29 17:38:14 2024 GMT
        Subject: C = JA, ST = Tokyo, O = CaSample, CN = ca-sample.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:9d:28:b4:02:86:ad:d0:0f:79:6b:2a:81:a3:3b:
                    fe:c9:97:80:fc:e1:e3:f7:8a:70:29:7b:55:99:e9:
                    e7:6e:a5:d8:45:4c:10:3c:71:90:b4:12:2e:0f:0d:
                    45:09:43:5a:09:3e:b8:73:32:43:52:64:2a:60:81:
                    46:0f:2b:ba:8c:d4:b3:1d:24:7a:f6:fa:9b:13:a6:
                    ce:f8:8e:45:54:64:39:48:43:18:c1:dd:ab:40:6e:
                    34:ab:39:1c:34:da:ae:06:82:5b:43:fc:7c:3d:99:
                    25:d7:96:11:94:3e:fa:52:42:7b:4c:eb:66:1a:c4:
                    ca:e8:d1:76:85:e5:94:0d:e8:e5:3e:84:17:9c:c8:
                    f3:96:91:1c:b1:38:e5:e6:d8:51:16:5f:ed:2c:38:
                    58:e9:d8:77:69:a8:ab:28:88:bc:c1:d7:36:8a:b5:
                    66:c5:1f:3f:93:94:48:de:a2:b0:90:e7:69:23:84:
                    66:e3:77:0b:ca:de:57:88:5c:b0:37:63:af:ee:51:
                    33:3e:ac:96:26:1c:58:2a:b7:91:35:85:34:cb:97:
                    6f:f4:6e:15:04:e7:36:03:8a:e8:86:c5:ae:cd:ea:
                    07:aa:48:c6:c5:2b:d6:6c:20:79:bf:5d:3d:b0:d6:
                    21:79:47:c6:6d:e6:89:c2:ec:20:72:46:13:52:11:
                    ae:bd
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2
            X509v3 Authority Key Identifier: 
                70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2
            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        7d:85:dd:92:00:7a:28:f5:d2:68:2f:b2:ad:67:4b:89:af:b8:
        e4:a1:c8:bb:9c:2b:f2:d5:0d:4f:d8:b0:41:4e:f0:9b:f4:12:
        76:3e:94:5c:ee:ff:97:eb:74:3c:c4:84:ba:bb:30:e4:94:a1:
        ed:ea:6e:45:cf:32:0b:ab:86:09:ae:44:3d:80:9d:e4:a7:60:
        87:fa:4a:d2:59:ca:d5:9a:60:9e:2c:37:7f:3d:b2:b3:e5:b2:
        ec:74:a2:7f:f5:7b:0f:c3:10:d5:19:c5:07:8e:3f:6c:ea:60:
        8b:b1:a1:55:3d:f0:58:46:0a:46:48:f3:92:7b:55:82:14:2c:
        ea:1d:7d:de:34:5a:df:2d:a6:b6:f4:5d:9c:d6:7b:16:fe:c7:
        3b:31:f0:d9:b7:6a:59:eb:39:d5:4e:e6:02:b5:52:bd:7c:7d:
        b5:37:de:81:17:5b:8b:23:c7:a9:6f:fe:13:d6:a2:03:cb:33:
        f6:50:d5:65:a1:6e:51:8a:71:e4:16:9c:e4:d7:0c:9b:e5:93:
        c7:84:68:ba:48:84:38:d4:12:64:5d:1f:ca:00:37:96:5d:a3:
        58:e4:f8:7f:79:dc:39:36:80:9e:76:e7:59:13:2a:85:c5:6d:
        b6:6f:f1:da:e0:e7:3c:d7:02:42:0f:e6:f9:9b:12:1a:50:00:
        64:ff:4b:98

中間CAの作成

CA.plとopenssl.cnfを中間CA用に書き換えたものを用意します。

% diff openssl.cnf openssl_intermidiate.cnf
76c76
< dir        = ./demoCA      # Where everything is kept
---
> dir        = ./intermidiateCA      # Where everything is kept
% diff CA.pl CA_intermidiate.pl
33c33
< my $CATOP = "./demoCA";
---
> my $CATOP = "./intermidiateCA";

ルートCAに署名をリクエストします。

% OPENSSL=../openssl/apps/openssl OPENSSL_CONFIG="-config ./openssl_intermidiate.cnf" ./CA_intermidiate.pl -newreq
Use of uninitialized value $1 in concatenation (.) or string at ./CA_intermidiate.pl line 145.
====
../openssl/apps/openssl req -config ./openssl_intermidiate.cnf -new  -keyout newkey.pem -out newreq.pem -days 365 
Ignoring -days without -x509; not generating a certificate
Generating a RSA private key
......+.......+......+..+.......+..+...+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+.....+...+...+...................+...........+...+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+.....+...............+.+...........+...+.......+..+.......+...+..+....+..+.......+...+.....+....+........+..........+.....+.......+......+..+.+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
....+.........+...+.....+............+.+..+....+.........+.........+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+.+...........+.+...+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Writing new private key to 'newkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JA
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Shibuya
Organization Name (eg, company) [Internet Widgits Pty Ltd]:IntermidiateCaSample
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:intermidiate.ca-sample.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
==> 0
====
Request is in newreq.pem, private key is in newkey.pem
% openssl req -text -in newreq.pem
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = JA, ST = Tokyo, L = Shibuya, O = IntermidiateCaSample, CN = intermidiate.ca-sample.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:af:f7:18:b6:83:b2:55:97:49:a3:89:f0:38:74:
                    a0:4c:23:9f:8b:5c:14:33:30:ca:9b:12:d0:6f:e8:
                    3d:27:42:0a:72:2a:4d:29:00:4b:55:2d:3d:fc:3f:
                    aa:ad:8b:ce:90:02:f9:d4:e8:90:9b:bc:8d:6f:d0:
                    cc:e1:77:42:ce:79:a5:55:db:ad:56:e3:86:bb:ce:
                    4d:c1:39:cd:b6:8b:74:86:e3:14:0d:fb:3a:69:21:
                    22:17:cb:c1:47:15:f8:fb:67:70:50:7e:48:95:71:
                    50:b9:3b:dc:70:b9:a1:d5:c6:b1:93:b4:32:24:5b:
                    cf:46:e8:0b:09:7f:8d:3d:55:75:d8:9a:0c:9b:b9:
                    9c:be:74:9e:71:a7:d4:73:e0:0d:26:00:f1:69:fe:
                    c3:d0:17:81:b4:a2:e8:82:46:8c:5e:66:90:92:70:
                    ff:6d:c9:b0:a8:d1:21:dd:59:a3:e3:ad:64:5b:b4:
                    b3:3f:fb:3f:f6:3e:f5:b2:8c:36:0b:e4:44:63:d1:
                    28:45:69:8e:79:98:56:d5:75:27:70:d2:db:e7:fe:
                    67:fb:d4:ff:96:cb:fe:98:60:db:67:2e:b9:37:74:
                    53:c2:f9:b7:6f:0e:a1:bd:93:ba:30:bb:0b:61:7d:
                    da:85:a9:ed:4a:49:f2:67:93:65:c3:02:91:68:a4:
                    b8:21
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha256WithRSAEncryption
         37:d6:ab:3f:14:fe:21:4a:d3:41:07:a3:81:43:7a:d2:37:83:
         be:c6:72:b5:65:31:34:a7:1c:be:b5:7b:27:33:d7:5e:60:1b:
         6b:8e:22:20:b8:77:12:c9:8e:f8:fe:80:91:d0:68:97:84:04:
         a5:32:97:e8:9c:e9:ef:14:48:94:a4:ae:11:94:72:0f:61:5a:
         97:16:56:87:73:f2:ba:62:24:3f:62:b0:7c:fd:89:80:eb:50:
         bb:3c:58:23:b3:2a:31:bc:75:04:87:b7:e3:9f:63:77:53:86:
         f0:c6:bb:ba:e0:d2:ba:34:ba:aa:3d:66:a7:94:f4:e9:b7:54:
         0b:46:5e:00:67:6a:95:44:b1:e8:39:2c:db:9a:c3:ba:64:df:
         30:3f:a4:0b:1b:62:fb:02:50:84:f2:42:91:61:e3:8c:a2:f9:
         dd:6e:b0:aa:1e:d2:7d:8c:ac:bd:bc:9a:a9:67:30:b1:69:e3:
         6e:b6:65:9f:13:48:e2:e7:cb:73:e5:77:87:a4:71:e5:15:cf:
         7b:91:dc:0b:db:e8:0c:73:7a:ba:b7:b3:7b:f0:17:ca:88:4c:
         52:c8:8f:77:d1:2f:1a:60:5c:11:54:d7:ac:b9:b0:2d:70:db:
         db:db:9a:85:36:93:3b:93:80:f2:d9:97:28:cc:41:56:d5:0b:
         d3:db:94:25

できたCSRを元に、root CAが署名して証明書を作成します。

 % OPENSSL=../openssl/apps/openssl OPENSSL_CONFIG="-config ./openssl.cnf" ./CA.pl -signCA
====
../openssl/apps/openssl ca -config ./openssl.cnf -policy policy_anything -out newcert.pem -extensions v3_ca -infiles newreq.pem 
Using configuration from ./openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            5f:ea:3f:e3:bf:eb:68:e3:13:1c:b4:96:eb:ef:54:5f:5b:bb:cc:8a
        Validity
            Not Before: Apr 30 18:36:05 2021 GMT
            Not After : Apr 30 18:36:05 2022 GMT
        Subject:
            countryName               = JA
            stateOrProvinceName       = Tokyo
            localityName              = Shibuya
            organizationName          = IntermidiateCaSample
            commonName                = intermidiate.ca-sample.com
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                A9:C2:76:74:B1:39:64:63:66:CA:CB:32:7B:36:3D:B1:A5:56:1D:FA
            X509v3 Authority Key Identifier: 
                70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2
            X509v3 Basic Constraints: critical
                CA:TRUE
Certificate is to be certified until Apr 30 18:36:05 2022 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
==> 0
====
Signed CA certificate is in newcert.pem
% openssl x509 -text -noout -in newcert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            5f:ea:3f:e3:bf:eb:68:e3:13:1c:b4:96:eb:ef:54:5f:5b:bb:cc:8a
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = JA, ST = Tokyo, O = CaSample, CN = ca-sample.com
        Validity
            Not Before: Apr 30 18:36:05 2021 GMT
            Not After : Apr 30 18:36:05 2022 GMT
        Subject: C = JA, ST = Tokyo, L = Shibuya, O = IntermidiateCaSample, CN = intermidiate.ca-sample.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:af:f7:18:b6:83:b2:55:97:49:a3:89:f0:38:74:
                    a0:4c:23:9f:8b:5c:14:33:30:ca:9b:12:d0:6f:e8:
                    3d:27:42:0a:72:2a:4d:29:00:4b:55:2d:3d:fc:3f:
                    aa:ad:8b:ce:90:02:f9:d4:e8:90:9b:bc:8d:6f:d0:
                    cc:e1:77:42:ce:79:a5:55:db:ad:56:e3:86:bb:ce:
                    4d:c1:39:cd:b6:8b:74:86:e3:14:0d:fb:3a:69:21:
                    22:17:cb:c1:47:15:f8:fb:67:70:50:7e:48:95:71:
                    50:b9:3b:dc:70:b9:a1:d5:c6:b1:93:b4:32:24:5b:
                    cf:46:e8:0b:09:7f:8d:3d:55:75:d8:9a:0c:9b:b9:
                    9c:be:74:9e:71:a7:d4:73:e0:0d:26:00:f1:69:fe:
                    c3:d0:17:81:b4:a2:e8:82:46:8c:5e:66:90:92:70:
                    ff:6d:c9:b0:a8:d1:21:dd:59:a3:e3:ad:64:5b:b4:
                    b3:3f:fb:3f:f6:3e:f5:b2:8c:36:0b:e4:44:63:d1:
                    28:45:69:8e:79:98:56:d5:75:27:70:d2:db:e7:fe:
                    67:fb:d4:ff:96:cb:fe:98:60:db:67:2e:b9:37:74:
                    53:c2:f9:b7:6f:0e:a1:bd:93:ba:30:bb:0b:61:7d:
                    da:85:a9:ed:4a:49:f2:67:93:65:c3:02:91:68:a4:
                    b8:21
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                A9:C2:76:74:B1:39:64:63:66:CA:CB:32:7B:36:3D:B1:A5:56:1D:FA
            X509v3 Authority Key Identifier: 
                keyid:70:05:DC:66:76:34:0B:A5:E8:B7:7C:AF:8F:5B:95:81:DE:F3:01:A2

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         25:b4:ef:8e:65:c7:6f:86:0c:91:63:f5:c4:3f:d0:3e:21:01:
         92:64:89:5b:71:d3:7d:fa:fd:64:eb:09:db:34:97:b1:6d:38:
         92:6f:8a:b4:c5:51:c0:85:c0:71:0d:ec:2b:71:50:77:6d:c0:
         f4:ca:3a:38:66:93:44:eb:aa:db:fa:07:22:14:5c:48:ab:18:
         b0:39:67:8a:80:59:b8:44:ac:84:3d:dd:aa:16:74:48:3d:aa:
         71:d2:37:fe:38:b6:9f:37:6c:fd:d4:79:ce:3d:0a:ca:31:68:
         4f:bb:19:c4:78:f0:32:1b:dd:5e:8f:42:e2:27:06:cb:b1:ff:
         c7:be:cf:3f:3b:84:d0:cd:c7:ba:e8:85:23:cc:1a:96:49:81:
         0d:7b:b6:1d:91:c7:58:b4:7d:2f:2f:f2:88:b0:ed:ad:29:36:
         14:43:1c:ee:c8:5c:37:29:df:dd:c4:38:e5:e0:70:5b:89:1b:
         a1:de:25:57:5e:c2:a6:fb:36:8a:e4:64:83:1e:e1:66:e3:a6:
         01:91:ac:08:89:95:e7:6c:4f:de:e1:f2:eb:f5:35:87:b2:42:
         c7:11:fa:f2:85:7e:30:db:52:71:45:3b:a0:5a:5f:15:6c:b4:
         98:81:f5:2c:ee:b5:fa:8a:63:fe:b9:8e:f9:ae:af:18:13:75:
         4d:b1:2e:4c

この証明書を元に中間CAを作ります。

% mkdir intermidiateCA
% mv new* intermidiateCA
% OPENSSL=../openssl/apps/openssl OPENSSL_CONFIG="-config ./openssl_intermidiate.cnf" ./CA_intermidiate.pl -newca
Directory ./intermidiateCA exists at ./CA_intermidiate.pl line 157.
CA certificate filename (or enter to create)
/Users/path/to/intermidiateCA/newcert.pem
 % tree intermidiateCA
intermidiateCA
├── cacert.pem
├── certs
├── crl
├── crlnumber
├── index.txt
├── newcert.pem
├── newcerts
├── newkey.pem
├── newreq.pem
└── private
    └── cakey.pem

# CAの作成時にうまく作成されないのでセットアップを自前でする
# serialの発行はもっとうまくできそう
cp intermidiateCA/newkey.pem intermidiateCA/private/cakey.pem 
echo 00 > ./intermidiateCA/serial

これで中間CAができました。

では実際に証明書を発行してみます。

% openssl genpkey -algorithm ed25519 -out server_key.pem 
% openssl req -new -out server_csr.pem -key server_key.pem

CSRの発行までは別でやってみて、署名した証明書を発行します。

% ../openssl/apps/openssl ca -config ./openssl_intermidiate.cnf -policy policy_anything -out server_certificate/server_crt.pem -extensions v3_ca -infiles server_certificate/server_csr.pem
Using configuration from ./openssl_intermidiate.cnf
Enter pass phrase for ./intermidiateCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: May  3 18:56:55 2021 GMT
            Not After : May  3 18:56:55 2022 GMT
        Subject:
            countryName               = JA
            stateOrProvinceName       = Tokyo
            localityName              = Shibuya
            organizationName          = ServerCaSample
            commonName                = server.example.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                36:B5:66:C2:18:A9:43:92:A3:34:64:84:1C:0F:9A:19:3E:52:6A:85
            X509v3 Authority Key Identifier: 
                A9:C2:76:74:B1:39:64:63:66:CA:CB:32:7B:36:3D:B1:A5:56:1D:FA
Certificate is to be certified until May  3 18:56:55 2022 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

発行された証明書を検証してみます。

% openssl verify -CAfile demoCA/cacert.pem <(cat ./intermidiateCA/cacert.pem ./server_certificate/server_crt.pem)
#でもいいし
% cat intermidiateCA/cacert.pem server_certificate/server_crt.pem > crt.pem
% openssl verify -CAfile demoCA/cacert.pem crt.pem
crt.pem: OK

検証成功しました。

opensslの検証の実装

github.com

このあたりから読んでいけばよさそう

macでのopensslのビルド

./Configure darwin64-x86_64-cc shared enable-ec_nistp_64_gcc_128 no-ssl2 no-ssl3 no-comp --openssldir=~/path/to/dir
make depend
make

makeだけであればバイナリがopensslのapps配下に作られれるので、それを使いました。

NGだったパターン

gist:2f51fa1bfa33f25d9c667db9d83c2412 · GitHub

参考資料

qiita.com

www.openssl.org

ja.wikipedia.org

www.ipa.go.jp

pebble8888.hatenablog.com

typewriter.hatenablog.jp

9cubed.info

ssl.sakura.ad.jp

www.ykrods.net

qiita.com