CubicLouve

Spring_MTの技術ブログ

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

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

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

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

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

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

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

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

物理クロック

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

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

パソコンの電源が切れたり、充電が切れたりしても、マザーボードに内蔵されている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

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

MacでMirageOSを動かしてみる

OCamlと仮想化の勉強のためMirageOSを触ってみることにしました。

setup

mirage.io 通りにやってみる

brew install opam
opam init
opam install mirage

Hello World

mirage.io

git clone https://github.com/mirage/mirage-skeleton.git

noopをやってみる

% cd tutorial/noop
% mirage configure -t unix
% make depend 
% make
% ls -l noop
lrwxr-xr-x  1 foo  1522739515  18  4 28 01:29 noop -> _build/main.native
% ./noop
% echo $?
0

Hello Worldやってみる

% cd tutorial/hello
% mirage configure -t unix
% make depend
% make
%  ./hello
2021-04-28 01:39:04 +09:00: INF [application] hello
2021-04-28 01:39:05 +09:00: INF [application] hello
2021-04-28 01:39:06 +09:00: INF [application] hello
2021-04-28 01:39:07 +09:00: INF [application] hello
%

4回helloがでるのは単純に loopが4回回ったら止まるからですね

github.com

参考

blog.ojisan.io

dev.realworldocaml.org

https://www.eurosys2020.org/wp-content/uploads/2020/04/slides/159_kuo_slides.pdf

データベースシステム 改訂2版の数式でわからなかったところメモ

p 37

集合は波括弧 {...} を用いて集合の要素を明示的に列挙する。

一般に、条件 P(x) があったとき、それをみたす対象だけを全て集めた集合を、

\displaystyle{
\{x \mid P(x)\}
}

と表記する。

a ∈ Aは aはAに属している、aはAの要素である。

∧ は論理積、AND

A ∧ Bは、Aであり、しかもBである。

ja.wikipedia.org

\displaystyle{
\{ (X_1,\cdots,X_n) | X_1 \in S_1 \land \cdots \land X_n \in S_n \}
}

集合 X1,..,Xnは、S1からSnまでの集合の各要素の組を要素する集合であり、これを S1,...,Snの直積集合と呼ぶ。

ja.wikipedia.org

\displaystyle{
S_1 × \cdots × S_n
}

p 39

下記リレーションスキーマが与えられたとき、

\displaystyle{
R(A_1, \cdots, A_n)

(各属性のドメインを D_1, \cdots D_n とする)
}

リレーションをタプル tiの集合 rとして定義する。

\displaystyle{
r = \{t_1 \cdots, t_m \}
}

各タプルtiは以下のような写像

\displaystyle{
t_i : \{ A_1,\cdots,A_n \} \to D_1 \cup \cdots \cup D_n
}

かつ

\displaystyle{
t_i(A_k) \in D_k  (1 \leqq k \leqq n, 1 \leqq i \leqq m)
}

という条件を満たすものとする。

ja.wikipedia.org

http://www.aoni.waseda.jp/sadayosi/course/past/set05/section1.2.pdf

集合 A から集合 B への写像 f とは,A の任意の要素 a に対して B のある要素 b を対応させる規則のことであり,

\displaystyle{
f : A \to B
}

で表す。 a に対応する要素 b は f(a) で表す。

A を f の定義域,B を f の値域という。

Aiは属性名(属性)で、Diは各属性のドメイン(定義域)。

A1からAnの属性名の集合が、D1からDnの和集合の写像であるとしている。

ja.wikipedia.org

継続的デリバリー(Continuous Delivery, CD)について

継続的デリバリー(CD)とはなにか?

根本は アジャイル宣言の背後にある原則 になるかと思います。

顧客満足を最優先し、価値のあるソフトウェアを早く継続的に提供します。

Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.

agilemanifesto.org から引用

書籍 継続的デリバリー でもこの部分を引用して本のタイトルをつけたと書いてあります。

さらにClean Agileからも引用してみます。

変更するたびに本番環境にコードをリリースするプラクティス

Clean Agile p88より

なるほど、わかりやすい。

Continuous Delivery Foundation (CDF)の定義も見てみます。

CD is a software engineering approach in which teams produce software in short cycles, ensuring that the software can be reliably released at any time.

CDは、チームが短いサイクルでソフトウェアを生産し、いつでも確実にソフトウェアをリリースできるようにするソフトウェアエンジニアリングのアプローチです。

github.com

コード、ソフトウェアという言葉が多く見受けられるが、データのリリースはどうなのだろうか?という疑問が若干わきます。

自分の中では価値を提供する変更のデリバリーであれば全部含むという認識でいるので、データのリリースも含めて考えます。

(ゲームでいうマスターデータとかの話)

継続的にという言葉の通り連続することが重要なのですが、それぞれの間隔を長くすることは無意味なので、デリバリーする間隔を短くするプラクティスということが暗黙的にあります。

コードの変更から本番環境へのリリースの間隔を短くしていく取り組みとも言えます。

なぜCDを行うのか?

リリースの間隔が短くリリース頻度が多いチームは逆のチームに比べて、平均修復時間が小さいこと、変更失敗率が低いことが調査でわかっています。

下記を参照のこと

www2.slideshare.net

speakerdeck.com

LeanとDevOpsの科学

ここで注目したいのは、加速化を推進してもパフォーマンス改善以外の項目に対してトレードオフが発生しないということです。(LeanとDevOpsの科学 p27あたり)

リリースを頻繁に行うためには、下記の取り組みが必要になってきます。

  • リリースに伴う各ステップのリードタイムを短くする
  • リリース単位を小さくする

これらの取り組みの結果、最終的にパフォーマンスがよくなります。

CDを行うための準備

プロセスを整理する

コードの変更、コードのpush、テスト、PR、マージ、deployのstepにおいて、どのような処理を行うのかなどを整理し、自動化をできるように整備します。

自動化の取り組み

継続的にそして、素早くデリバリするために各ステップの自動化は必須です。

自動化としては下記が挙げられると思います。

  • ユニットテストの自動化
  • ビルドの自動化
  • 受け入れテストの自動化
  • リリースの自動化

現状の分析

構成管理やリリース管理の成熟度

継続的デリバリー p487 に成熟とのレベルの定義があるのでこれで分析してみましょう

  • レベル3 : 最適化 プロセスの改善に注力する

  • レベル2 : 定量的な管理 プロセスが計測可能で制御されている

  • レベル1 : 一貫している 自動化されたプロセスがアプリケーションのライフサイクルに適用される

  • レベル0 : 繰り返し可能 プロセスは文書化され、一部は自動化されている

  • レベル-1 : リグレッションエラー多発 プロセスは繰り返せず管理も貧弱、そして対処療法を行っている

これらを使って分析し、step by stepで対応していくのがよいでしょう。

自分のプロジェクトを分析した結果を残しておきます。

ラクティス ビルド管理および
継続的インテグレーション
テスト データ管理 環境およびデプロイメント
レベル2
ビルドメトリクスを収集して可視化し、
それに基づいて作業する。
ビルドを壊れたままにしない
レベル2くらい
本番環境への変更の取り消しは滅多に発生しない
問題があればすぐに見つかり、すぐに修正される。
非機能要件の定義は甘い
受け入れテストは自動化されていない。
レベル2くらい
データベースの更新やロールバックはデプロイのたびにテストされる。
データベースのパフォーマンスを管理、最適化する。
レベル1くらい?
一部の環境ではデプロイを自動化する。
新しい環境は手軽に作成する。
全ての構成情報を外に出してバージョン管理できてる
全ての環境に対して同じ手順でデプロイする
ボタンを押すだけでは完結していない。。

今できてないことは、受け入れテストの自動化、デプロイメントの自動化になります。

自分たちの課題の分析

受け入れテストの自動化

QAチームで今は手動テストを行っている。

シフトレフトしていきたいが取り組みとしては滞っている。

機能テストをよりリッチにしていくなども考えている。

受け入れテストの自動化ができていないことがデプロイの自動化に踏み込めない原因でもある

デプロイの自動化

本番環境へのデプロイ環境への自動化はできていない。(検証環境はできている)

手順はこんな感じでやっている

  1. Docker imageはmasterにmergeされると全部buildされてpushされている
  2. QAはどのimageを使うかを選んで反映しておく。
  3. QAチームからサインオフがでる *ここでDocker imageのハッシュ値が決まる
  4. 本番環境のdeployサーバーにsshする
  5. deployコマンドを打つ
    • この中で DB schemaの変更を行う専用のPodのimageを先に更新して、このPodに入ってスクリプトと叩く
    • kubectl apply(をラップしたコマンド)でimageを更新を含むkubernetesの更新を行う。

自動化できていない原因は下記の通り

受け入れテストの整備

反映後の受け入れテストの自動テストが整備されていないため切り戻しが自動でできない。

DBのschemaアプライ

DB schemaのアプライが同期的に実行できない場合もあるので、ここを順々に実行する方法を探している

だた、基本的には後方互換性を担保して開発しているので問題が起きにくい状態ではある。。

監査、RBAK

特に操作ログの保持が難しい。(改ざんをどう防ぐかとか)

このような分析をもとに次につなげていく。

さらに少し考えてみた

大規模サービスにおいて、継続的デリバリをするのであれば、継続的デリバリの中からデータベースの管理は切り離さないとだめだと思う。

データベースのバージョン管理はしつつ、デリバリする際にバージョンが該当のものでなければ止めるという制御を入れる。

ALTERとかカラム追加で時間がダウンタイムが発生する場合、デリバリするタイミングで気がつくとそれはもう手遅れなので前もって気がつくのがいいが、デリバリを止められる仕組みさえあればいい。

と考えてみたが、継続的デリバリ12章に理想が書いてあった。。

受け入れテストまで整備するべきかどうかもあるけど、正直エラーがあったら切り戻すで割り切らないと多分一生できん気がする