更新したのに古い証明書が出ていく
目標
証明書を起動時に一度だけ読み込むHTTPSサーバーについて、更新事故を再現し、ディスクではなくサーバーが提示する証明書を監視するスクリプトを2つ作ります。
なぜ重要なのか
更新ツールはファイルを書き換え、サーバーはメモリのものを提示します。その間に再起動がなければ、「更新成功」のログと「期限切れ間近」の警告が、同時に真になります。用意されているサーバー/opt/app/tlsserve.pyは、load_cert_chainをたった一度だけ呼ぶPythonのHTTPSサーバーで、実際のサーバーの大半がそうであるように、ファイルが変わっても読み直しません。このラボの監視スクリプトは、採点ツールが別に立ち上げたサーバーで、双方向(同じファイルならFRESH、違うファイルならSTALE)の検査を受けます。
ステップ
- 次のファイルを作成してください。CAの鍵と証明書(
/root/renew/ca.key・/root/renew/ca.crt、CN=Lab Root CA)、サーバーの鍵(/root/renew/server.key)、そしてCAが署名した3日間の証明書(/root/renew/v1.crt、SANDNS:www.lab.internal)です。 v1.crtをコピーして(コピー先:/root/renew/live.crt)、server.keyもコピーし(コピー先:/root/renew/live.key)、python3 /opt/app/tlsserve.py --cert /root/renew/live.crt --key /root/renew/live.key --port 8443を起動してください。openssl s_clientで受け取った証明書のserial=行を保存してください(保存先:/root/renew/02-served.txt)。- 同じ鍵で30日間の証明書(
/root/renew/v2.crt)を発行し、live.crtに上書きしてください(更新ツールがすることです)。サーバーは再起動しないでください。 - もう一度s_clientで
serial=を保存し(保存先:/root/renew/04-served.txt)、curl -sk https://127.0.0.1:8443/の本文も保存してください(保存先:/root/renew/04-body.txt)。ディスクはv2なのに、サーバーはv1のままである必要があります。 - 次のスクリプトを作成してください:
/root/renew/certdiff.sh <인증서파일> <host:port>(プレースホルダーは証明書ファイルとhost:portです)。ディスクのファイルとサーバーが提示する証明書のSHA-256フィンガープリントが同じならFRESHを出力して0、異なればSTALEを出力して1で終了する必要があります。live.crtと127.0.0.1:8443に対して実行した出力を保存してください(保存先:/root/renew/05-detect.txt)。 - サーバーを終了して再び起動したあと、s_clientの
serial=を保存してください(保存先:/root/renew/06-served.txt)。 - 次のスクリプトを作成してください:
/root/renew/servedcheck.sh <host:port> <초>(プレースホルダーはhost:portと秒数です)。サーバーが提示する証明書がその秒数以内に期限切れになるならEXPIRINGを出力して1、そうでなければOKを出力して0で終了する必要があります。127.0.0.1:8443 604800で実行した出力を保存してください(保存先:/root/renew/07-monitor.txt)。 - まとめを書いてください(保存先:
/root/renew/08-report.md)。v1とv2のシリアル番号、サーバーに新しいファイルを読み込ませた方法、監視はディスクではなくサーバーが提示する証明書を見る必要がある理由を書いてください。
参考
- s_clientは標準入力を待つので、
echo | openssl s_client -connect 127.0.0.1:8443 -servername www.lab.internal 2>/dev/null | openssl x509 -noout -serialのように使います。 - サーバーの終了:
pkill -f tlsserve.py。再び起動するときは、nohup ... &でバックグラウンドに置いてください。 - スクリプトの中で、受け取った証明書を一時的にファイルに保存するには、
openssl x509 -out <임시파일>で受け取ればよいです(プレースホルダーは一時ファイル名です)。 - よくある間違い: ステップ4の前にサーバーを再起動すると、事故が消えます。ステップ7の監視スクリプトがディスクのファイルを見ていると、採点ツールのサーバーで不合格になります。
CAと3日間のv1
/root/renew/にca.key・ca.crt(CN=Lab Root CA)・server.keyと、3日間のv1.crt(SAN DNS:www.lab.internal)を作成してください。
前のモジュールと同じ手順です。CAの自己署名、SAN付きのCSR、x509 -reqでの署名(-copy_extensions copy)です。CSRはステップ3でまた使うので、server.csrとして残しておいてください。
サーバーが持っている証明書を読む
v1.crt→live.crt、server.key→live.keyにコピーしてtlsserve.pyを8443で起動し、s_clientで受け取ったserial=行を/root/renew/02-served.txtに保存してください。
サーバーはnohupでバックグラウンドに置き、ログは/root/renew/server.logに出力してください。s_clientの出力全体をx509 -noout -serialに渡すと、serial=の行が1行出ます。
更新: ファイルを上書きする
同じ鍵で30日間の/root/renew/v2.crtを発行し、live.crtに上書きしてください。サーバーは再起動しないでください。
同じCSRにもう一度署名すればよいです(-days 30)。serialが新しく割り振られ、有効期限が延びます。cp v2.crt live.crtが、更新ツールがすることのすべてです。
ディスクはv2、サーバーはv1
s_clientのserial=を/root/renew/04-served.txtに、curl -sk https://127.0.0.1:8443/の本文を/root/renew/04-body.txtに保存してください。
サーバーは、起動時に読み込んだものを提示し続けます。2つのファイルとも、v1のserialが見えれば、事故が再現されたことになります。curlの-kは、自前のCAなので検証をオフにするもので、本文にはサーバー自身が語るserialがあります。
ディスクとサーバーを比べるスクリプト
/root/renew/certdiff.sh <인증서파일> <host:port>(プレースホルダーは証明書ファイルとhost:portです)を作成し(同じならFRESH・0、異なればSTALE・1)、live.crtと127.0.0.1:8443に対する出力を/root/renew/05-detect.txtに保存してください。
2つのフィンガープリントを求めます。ファイルはx509 -in ファイル -fingerprint -sha256、サーバーはs_clientの出力をx509 -fingerprint -sha256に渡します。サーバーから証明書を受け取れないなら、ERRORとして2を返すとよいです。採点ツールは、自分のサーバーで、同じファイルと違うファイルの2つのケースを実行します。
再起動: サーバーが新しいファイルを読む
サーバーを終了して再び起動したあと、s_clientのserial=を/root/renew/06-served.txtに保存してください。
pkill -f tlsserve.pyで終了し、同じコマンドで再び起動します。起動時にlive.crtを新しく読み込むので、今度はv2のserialが出るはずです。
サーバーが提示する証明書の期限監視
/root/renew/servedcheck.sh <host:port> <초>(プレースホルダーはhost:portと秒数です)を作成し(その秒数以内に期限切れならEXPIRING・1、そうでなければOK・0)、127.0.0.1:8443 604800の出力を/root/renew/07-monitor.txtに保存してください。
s_clientで受け取った証明書を、一時ファイルにx509 -outで保存したあと、-checkend <秒数>をかければよいです。ディスクのlive.crtを見てはいけません。採点ツールは、2日間の証明書を持つ自分のサーバーに、7日のウィンドウを与えて、EXPIRINGが出るかを見ます。
事故レポート
/root/renew/08-report.mdに、v1・v2のシリアル番号、サーバーに新しいファイルを読み込ませた方法、監視がサーバーの提示する証明書を見る必要がある理由を書いてください。
2つのserialは、v1.crtとv2.crtから-serialで取り出して、そのまま入れてください。「再起動」という言葉と「s_client」が入っていれば、採点ツールが結論を見つけます。