TT Lab
はじめる
学ぶ 学習パス コース

Tomcat & nginxの運用

プライベートCAで証明書を発行しnginxに適用する

TT Labで続きを見る

目標

プライベートCAを作って、SANを含むサーバー証明書を発行し、チェーンファイルを構成してnginxにHTTPSを適用し、期限監視スクリプトまで作れるようになります。

なぜ重要なのか

証明書障害の大半は、暗号学ではなく、チェーンの欠落と期限切れの2つです。中間証明書を抜かすと、ブラウザーでは動くのに、連携相手のシステムでだけ失敗します。ブラウザーは中間証明書をキャッシュしたり、自動的に取得したりしますが、サーバー間のHTTPクライアントは、そうしないからです。「開発者のPCでは動くのですが」は、この症状の典型です。そして、期限切れは予告なしには来ないのに、担当者の交代とアラートの漏れで、毎年事故が起きます。プライベートCAで一度自分で作ってみれば、この構造が身に付きます。

ステップ

  1. /root/ng/tlsディレクトリを作成して、RSA 2048ビットの秘密鍵を/root/ng/tls/server.keyとして生成します。
  2. その鍵でCSRを作成して、/root/ng/tls/server.csrに保存します。サブジェクトにCN=labhub.local、O=LabHub、C=KRを含める必要があります。
  3. プライベートCAを作ります。/root/ng/tls/ca.keyと/root/ng/tls/ca.crtです。CA証明書のサブジェクトはCN=LabHub Root CAで、有効期間は3650日以上、basicConstraintsにCA:TRUEがある必要があります。
  4. CAでCSRに署名して、/root/ng/tls/server.crtを作成します。SANにDNS:labhub.localとIP:127.0.0.1の両方が入っている必要があり、発行者(issuer)がCAのサブジェクトと同じである必要があります。
  5. /root/ng/tls/fullchain.pemを作成します。サーバー証明書 → CA証明書の順につなげ、ファイルの中に証明書がちょうど2つある必要があります。openssl verify -CAfile ca.crt server.crtが成功する必要があります。
  6. nginxにポート8443のHTTPSサーバーブロックを追加します。ssl_certificateはfullchain、ssl_certificate_keyはserver.key、ssl_protocolsはTLSv1.2 TLSv1.3だけを許可します。openssl s_client -connect 127.0.0.1:8443 -CAfile /root/ng/tls/ca.crtの結果に、Verify return code: 0が出る必要があります。
  7. ポート8088のすべてのリクエストが、https://へ301リダイレクトされるようにします。curl -s -o /dev/null -w '%{http_code} %{redirect_url}' http://127.0.0.1:8088/xの結果が301で、リダイレクトURLがhttps://で始まり、8443を含む必要があります。
  8. /root/ng/certcheck.shを作成します。引数を2つ(인증서파일 임계일수、韓国語の語は、順に「証明書ファイル」「しきい値の日数」を意味します)受け取って、残りの有効期間がしきい値の日数より多ければ終了コード0、しきい値の日数以内に迫っていれば、0以外の終了コードで終わります。証明書ファイルがなければ、やはり0以外の終了コードで終わる必要があります。

参考

サーバー秘密鍵の生成

/root/ng/tlsディレクトリを作成して、RSA 2048ビットの秘密鍵を/root/ng/tls/server.keyとして生成します。

RSA 2048ビットが、今も標準的な選択です。生成した鍵が正常かを確認するopensslのサブコマンドも、一緒に身に付けておいてください。

CSRの生成

その鍵でCSRを作成して、/root/ng/tls/server.csrに保存します。サブジェクトにCN=labhub.local、O=LabHub、C=KRを含める必要があります。

CSRのサブジェクト情報は、-subjで一度に指定できます。国コードは、2文字の大文字です。

プライベートCAの作成

プライベートCAを作ります。/root/ng/tls/ca.keyと/root/ng/tls/ca.crtです。CA証明書のサブジェクトはCN=LabHub Root CAで、有効期間は3650日以上、basicConstraintsにCA:TRUEがある必要があります。

CA証明書は、通常のサーバー証明書と違う必要があります。どの拡張がCAであることを示すかを、確認してください。openssl reqに-x509を指定すると、自己署名証明書ができます。

CAによるサーバー証明書への署名

CAでCSRに署名して、/root/ng/tls/server.crtを作成します。SANにDNS:labhub.localとIP:127.0.0.1の両方が入っている必要があり、発行者(issuer)がCAのサブジェクトと同じである必要があります。

最近のブラウザーとライブラリは、CNではなくSANを見ます。openssl x509で署名するとき、拡張をファイルで渡さないと、SANが入りません。

チェーンファイルの構成

/root/ng/tls/fullchain.pemを作成します。サーバー証明書 → CA証明書の順につなげ、ファイルの中に証明書がちょうど2つある必要があります。openssl verify -CAfile ca.crt server.crtが成功する必要があります。

サーバー証明書とCA証明書をつなげます。順序が重要です。作ったあとは、検証コマンドで、実際に信頼のパスが成立するかを確認してください。

nginxへのHTTPS適用

nginxにポート8443のHTTPSサーバーブロックを追加します。ssl_certificateはfullchain、ssl_certificate_keyはserver.key、ssl_protocolsはTLSv1.2 TLSv1.3だけを許可します。openssl s_client -connect 127.0.0.1:8443 -CAfile /root/ng/tls/ca.crtの結果に、Verify return code: 0が出る必要があります。

証明書と鍵がペアでないと、nginxは起動すらしません。プロトコルは、非推奨のバージョンを除いて指定してください。

HTTP → HTTPSのリダイレクト

ポート8088のすべてのリクエストが、https://へ301リダイレクトされるようにします。curl -s -o /dev/null -w '%{http_code} %{redirect_url}' http://127.0.0.1:8088/xの結果が301で、リダイレクトURLがhttps://で始まり、8443を含む必要があります。

rewriteよりreturnのほうが、明確で速いです。ステータスコードとLocationヘッダーの両方が合っている必要があります。

期限の監視スクリプト

/root/ng/certcheck.shを作成します。引数を2つ(인증서파일 임계일수、韓国語の語は、順に「証明書ファイル」「しきい値の日数」を意味します)受け取って、残りの有効期間がしきい値の日数より多ければ終了コード0、しきい値の日数以内に迫っていれば、0以外の終了コードで終わります。証明書ファイルがなければ、やはり0以外の終了コードで終わる必要があります。

openssl x509には、「残りの有効期間がN秒以上か」を終了コードで教えてくれるオプションがあります。監視スクリプトはこれを使えば、日付のパースが不要です。