TLS 証明書チェーン不整合が引き起こす問題の背景
TLS ハンドシェイクでは、サーバーはリーフ証明書(サイト証明書)だけでなく、信頼チェーンを構成する中間 CA 証明書もあわせて送信する必要があります。クライアントはルート CA をトラストストアに保持していますが、中間 CA はサーバー側が提示しなければ検証できません。この「中間証明書の欠落」や「提示順序の誤り」が、チェーン不整合(Chain Incomplete / Chain Out of Order)と呼ばれるエラーの実体です。
現場では、証明書を手動更新した際に中間 CA を付け忘れたケース、あるいは CSR を再発行せずにファイルだけ差し替えたケースで多く発生します。Chrome や Firefox はトラストストアにキャッシュした中間 CA を使って一時的に補完する挙動を持つため、開発者環境では問題が見えにくい一方、curl や古い Android クライアント、B2B API クライアントでは即座に検証エラーとなります。本番影響が顕在化するまでタイムラグが生じやすい点が、この障害の厄介なところです。
openssl による診断フロー
まず、サーバーが実際に送信している証明書チェーンを確認します。次のコマンドで接続先が提示するすべての証明書を出力できます。
openssl s_client -connect example.com:443 -showcerts 2>/dev/null
depth=0 がリーフ証明書、depth=1 が中間 CA、depth=2 以降がルートまたは上位の中間 CA です。チェーンが正しく構成されている場合、出力末尾に Verify return code: 0 (ok) が現れます。verify error:num=20:unable to get local issuer certificate などのエラーが出た場合は中間 CA が欠落しています。
続いて、手元にある証明書ファイル単体を検証します。
# リーフ証明書の発行者・有効期限・SAN を確認
openssl x509 -in server.crt -noout -text | grep -E "Issuer|Subject|Not After|DNS:"
# 中間 CA とルートの連鎖を検証
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt -untrusted intermediate.crt server.crt
server.crt: OK が返れば、ファイルとしての連鎖は正常です。ここで問題がなくても、サーバー設定で中間 CA を送信していなければ実クライアントへの影響は残ります。診断は「ファイルの正しさ」と「サーバーが実際に送信しているか」の2軸で行うことがポイントです。
送信済みの証明書チェーンを PEM として抽出したい場合は、-showcerts の出力から -----BEGIN CERTIFICATE----- 〜 -----END CERTIFICATE----- のブロックをそれぞれファイルに切り出し、順序通りに並んでいるか確認します。発行者(Issuer)とサブジェクト(Subject)が前後の証明書で一致しているかを目視するだけでも、順序の誤りを素早く発見できます。
中間 CA 証明書の正しい配置手順
修復の核心は「フルチェーンファイルを正しい順序で作成し、Web サーバーに設定する」ことです。順序はリーフ → 中間 CA → (必要に応じてルート)です。ルート CA はクライアントのトラストストアに含まれるため、送信の省略は可能ですが含めても問題ありません。
# フルチェーンを作成(ルートは省略可)
cat server.crt intermediate.crt > /etc/ssl/certs/fullchain.crt
nginx の場合、ssl_certificate ディレクティブにこのフルチェーンファイルを指定します。
ssl_certificate /etc/ssl/certs/fullchain.crt;
ssl_certificate_key /etc/ssl/private/server.key;
Apache HTTP Server(2.4.8 以降)では、SSLCertificateFile にフルチェーンをそのまま指定できます。旧来の SSLCertificateChainFile ディレクティブは非推奨であり、現行 Apache では使用しないのが原則です。
SSLCertificateFile /etc/ssl/certs/fullchain.crt
SSLCertificateKeyFile /etc/ssl/private/server.key
設定変更後は文法チェックを行ってからリロードします。
# nginx
nginx -t && systemctl reload nginx
# Apache
apachectl configtest && systemctl reload apache2
修復後の検証と影響範囲の事前確認
リロード直後に openssl s_client で再確認します。Verify return code: 0 (ok) が返ることを確認してから、次の工程に進んでください。
openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt 2>&1 | tail -5
curl でも検証します。-v オプションで TLS ネゴシエーションの詳細が表示されるため、SSL certificate verify ok が出ることを確かめます。
curl -v https://example.com/ 2>&1 | grep -E "SSL|TLS|verify"
影響範囲の事前確認として、作業前に以下の観点でリスクを洗い出しておくことが重要です。
- API クライアントが証明書を厳格に検証しているか(Java 系クライアントは独自のトラストストアを持つため、CA バンドルの更新が別途必要な場合がある)
- ロードバランサーや CDN で TLS ターミネーションをしている場合、LB 側の証明書設定も同期が必要か
- OCSP ステープリングを有効にしている場合、中間 CA 変更後に OCSP レスポンダの URI が変わっていないか
- 証明書を複数サービスで共用している(SNI ベースの仮想ホスト)場合、全 vhost に反映されているか
ステージング環境で同じ手順を先に試し、testssl.sh や sslyze のようなツールで網羅的にスキャンしてから本番適用するパターンが、現場での標準的な進め方です。特に testssl.sh --severity MEDIUM example.com のように深刻度フィルタを使うと、チェーン問題以外の設定ミスも同時に洗い出せます。
切り戻し手順と運用上の注意点
証明書ファイルを上書きする前に、必ず既存ファイルをタイムスタンプ付きでバックアップしておきます。
cp /etc/ssl/certs/fullchain.crt /etc/ssl/certs/fullchain.crt.bak.$(date +%Y%m%d%H%M%S)
問題が生じた場合は、バックアップを元のパスに戻して systemctl reload nginx するだけで切り戻せます。リロードは進行中の接続を維持したまま設定を再読み込みするため、restart は通常不要です。切り戻し後も必ず openssl s_client で実際の送信チェーンを再確認してください。
運用上の重要な注意点として、証明書の更新作業を自動化している場合(Certbot の renew フック等)、フルチェーンの生成処理もフック内に組み込んでおかなければ、次回の自動更新時にチェーン不整合が再発します。Let’s Encrypt を使用している場合、Certbot が生成する fullchain.pem はリーフ + 中間 CA を含んでいるため、そのまま ssl_certificate に指定するのが最も安全な運用です。手動で中間 CA を結合するファイル操作を挟んでいる場合は、その手順が自動更新後も確実に実行されるか検証しておく必要があります。
2026年の現行環境における差分と留意点
2026年時点では、Let’s Encrypt の普及により、多くのサービスで証明書のライフサイクル管理が自動化されています。Certbot や acme.sh が正しく設定されていれば、チェーン不整合は自動更新の過程でほぼ解消されます。問題が残るのは、自動化が不完全なエッジケース、あるいは商用 CA から手動取得した証明書を運用している環境です。
Kubernetes 環境では cert-manager が事実上の標準となっており、Ingress リソースへの証明書配布と更新を一括管理します。Certificate リソースで issuerRef を正しく設定していれば、チェーンも自動的に組み立てられます。従来型 VM での手動管理とは診断アプローチが異なるため、対象環境を確認してから作業に入ることが重要です。
TLS 1.3 が標準となった現在、セッション再開の仕組みが TLS 1.2 とは異なります。チェーン不整合の影響がセッションキャッシュにより隠蔽されるケースは TLS 1.3 ではほぼなくなっていますが、レガシークライアントとの互換性を確認する場面では -tls1_2 オプションを添えて旧バージョンでの挙動も検証しておくと安心です。
また、2021年に発生した DST Root CA X3 失効の経験を機に、クロス署名証明書の扱いと各種クライアントのトラストストア更新サイクルへの関心が高まりました。CA 自体がクロス署名チェーンを切り替えるタイミングで、フルチェーンの構成が変わることがあります。CA からの通知メールを見逃さず、証明書発行時に配布される中間 CA ファイルが以前と同一かどうかをフィンガープリントで確認する習慣が、現場では定着しつつあります。
# 中間 CA のフィンガープリントを確認
openssl x509 -in intermediate.crt -noout -fingerprint -sha256
チェーン不整合は再現性が高く原因が明確なため、手順を確立しておけば本番への影響時間を最小化できます。診断・修復・検証の3ステップを体系的に押さえ、自動化フローの中にチェーン確認を組み込んでおくことが、安定した TLS 運用の基盤となります。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
PR・広告
コマンド操作から基本運用までを手を動かして学べる定番書。記事で触れた技術の土台固めに。
※ Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。
