ゆるっと Tech Blog

日々学んだことをアウトプットします。

ALBへのクロスルート証明書インポートでインフラ基礎を学び直す

クロスルート証明書を扱う機会があり、仕組みを理解しようとインフラ基礎をお勉強し直したのでメモです。
全部盛りしたらえらい長さになりましたがご容赦ください。

TL;DR

ALBにクロスルート証明書をインポートするには、証明書チェーン欄に以下を設定してあげればいい。

—–BEGIN CERTIFICATE—–
・ 中間CA証明書の文字列
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
・ クロスルート設定用証明書の文字列
—–END CERTIFICATE—–

こんな情報はググれば出てくるので、仕組みを理解します。

クロスルート証明書とは

クロスルート方式とは、従来の証明書階層で使用するルート証明書に加えて、クロスルート用の中間証明書を設定することにより、別のルート証明書にも接続可能とする仕組みです。

(引用元 : https://www.cybertrust.co.jp/sureserver/support/faq/442g976c4sgy.html )

この絵がとてもわかりやすいですね。(※図1)

crossrootcirt

証明書インポートのオーダー内容

「今回から認証局側で仕様が変わって、証明書がクロスルートになってます。証明書の更新作業お願いします。」という依頼とともに、計5種類のファイルを受領。
送られてきたファイルはこんな感じです。

証明書
|--{FQDN}.crt
|--クロスルート証明書
|  |--CrossSignedRoot.crt
|--ルート証明書
|  |--DigiCertGlobalRootCA.crt
|  |--TrustedRoot.crt
|--中間証明書
|  |--DigiCertCA.crt

図1に出てくる証明書の枚数と、 .crt ファイルの枚数は一致してるので必要なものは揃っていそうです。 分からないのは、ルート証明書が2枚あるので、2つある証明書チェーンのどちらのルート証明書であるか、という点です。
まずはこれを調べてみます。

証明書の階層関係を調べる

以下のコマンドで、手元にある証明書の情報を出力することが可能です。

openssl x509 -text -noout -in {CrtFileName}

色んな情報が表示されますが、注目するのは「Issuer」と「Subject」という項目です。
それぞれ「発行元」と「発行先」を示しており、誰が誰に対して発行した証明書なのかを確認することができます。

それぞれのファイルに対してコマンド実行し、該当の項目を抜粋した結果が以下です。

## {FQDN}.crt

Issuer: C = US, O = "DigiCert, Inc.", CN = DigiCert G5 TLS RSA4096 SHA384 2021 CA1 ★1
Subject: jurisdictionC = JP, businessCategory = Private Organization, serialNumber = xxxx-xx-xxxxxx, C = JP, ST = xxx, L = xxx, O = xxx, CN = abc.yyy.jp


## CrossSignedRoot.crt

Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA ★2
Subject: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 ★3


## DigiCertGlobalRootCA.crt

Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA  ★2 
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA ★2


## TrustedRoot.crt

Issuer: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 ★3
Subject: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 ★3


## DigiCertCA.crt

Issuer: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 ★3
Subject: C = US, O = "DigiCert, Inc.", CN = DigiCert G5 TLS RSA4096 SHA384 2021 CA1 ★1

同じ文言には、★で同一の番号を振っています。
DigiCertGlobalRootCA.crtTrustedRoot.crt は、発行元と発行先が同じなので、自己証明書 = ルート証明書であることが分かります。
(受領したファイルのディレクトリ構成通りですが。)

また、ある証明書の発行元が、ある証明書の発行先であったりすることがわかります。
例えば、
{FQDN}.crt の 発行元 が ★1 で、
DigiCertCA.crt 発行先 が★1 なので、
DigiCertCA.crt -> {FQDN}.crt の階層順になることが分かります。

この情報から階層関係を整理すると、以下の感じになります。 まずは、階層関係を読み解くことができました。

証明書チェーンに何を記載するか

AWSの場合、ACMというサービスを利用して証明書をインポートします。 画面はこんな感じになってます。

証明書本文である {FQDN}.crt を除いて残り4種の証明書があるわけですが、
前述の通り、ググると、中間証明書 -> クロスルート用証明書の形式でインポートすればよいと書いてあります。
とはいえ、「今回はルート証明書も連携されてきているけど、それはインポートしなくてもいいのか。。?」という一抹の不安が残るので、もう一段深めます。

証明書チェーンの仕組み

結論、ルート証明書はサーバ側に設定する必要はありません。
なぜかを説明するために、まずデジタル証明書の仕組みを軽くおさらいします。
(引用元:https://www.infraexpert.com/study/security6.html )

上記サイトから要約して抜粋。

  1. Webサーバ側で公開鍵と秘密鍵を生成する。

  2. 公開鍵と各種証明書を認証局に渡し、デジタル証明書を発行依頼する。

  3. 認証局は、秘密鍵による署名付きのデジタル証明書を発行する。Webサーバでデジタル証明書をインストールする。

  4. クライアントPCからWebサーバに対して接続要求を行う。

  5. クライアントPCに対して、Webサーバはデジタル証明書を送付する。

  6. クライアントPCは、受信したデジタル証明書が正しいものかを確認するために、認証局の公開鍵を使用して、秘密鍵による署名部分の復号を行い、検証する。

認証局の公開鍵を含んだデジタル証明書は、代表的な認証局のデジタル証明書の場合、クライアントPCのブラウザにインストールされている。インストールされていない場合、ブラウザで警告表示される。

上図は中間認証局が存在していないですが仕組みは同じです。
大事なのは最後の記載です。

認証局の公開鍵を含んだデジタル証明書は、代表的な認証局のデジタル証明書の場合、クライアントPCのブラウザにインストールされている。インストールされていない場合、ブラウザで警告表示される。

デジタル証明書の正しさは中間認証局によって保証され、中間認証局の正しさはルート認証局によって保証され、ルート認証局の正しさはルート認証局自身によって保証されています。
そして、どのルート認証局を信頼するかは、あらかじめOSやブラウザにインストールされています。
OS/ブラウザへのプリインストール時点で不正が起きるのは考えづらいので、安心して利用ができます。

なお、信頼するルート認証局(=ルート証明書)を自分で追加することも可能です。
企業の場合、独自で認証局を立てるケースも多く、それはOSやブラウザに信頼の対象としてもともと入っているわけがないので、自分で追加する必要があります。(参考)

というわけで、ルート証明書はサーバ側にインストールしなくてもいいことがわかったので、ググった通りにインポートして作業完了です。

クライアントから証明書を確認してみる

インポートできたところで、クライアント側からコマンドで証明書を確認してみます。 サーバにインストール済の証明書を確認するコマンドは以下です。

openssl s_client -connect {FQDN}:443 -showcerts

出力される情報には証明書の階層情報が以下の番号で振られているので、
「0」:サーバー証明書
「1」:中間 CA 証明書
「2」:クロスルート用中間 CA 証明書

0,1,2の数字があれば、正しくクロスルート証明書をインポートできていることになります。(参考)

出力結果がこちら↓

[root@ip-172-16-0-51 ~]# openssl s_client -connect abc.yyy.jp:443 -showcerts
.....
---
Certificate chain
 0 s:/jurisdictionC=JP ... /CN=abc.yyy.jp
.....
 1 s:/C=US ... /CN=abc.yyy.jp
.....
 2 s:/jurisdictionC=JP ... /CN=abc.yyy.jp
.....

バッチリですね〜!!
加えて、今回対象のシステムでは1つのALBに対して、異なるFQDNを持つ2つのアプリをぶら下げているので、もう1つのFQDNに対しても確認しておきます。

[root@ip-172-16-0-51 ~]# openssl s_client -connect def.yyy.jp:443 -showcerts
.....
---
Certificate chain
 0 s:/jurisdictionC=JP ... /CN=abc.yyy.jp
.....
 1 s:/C=US ... /CN=abc.yyy.jp
.....
 2 s:/jurisdictionC=JP ... /CN=abc.yyy.jp
.....

お気づきでしょうか。
階層の数字は正しいのですが、紐づいている CN が、対象のFQDNと対応していません。
なぜ。。

答えは、SNI (Server Name Indicator) という仕組みの中にありました。 SNIとは、

一つのサーバーで複数のドメイン名を使用する場合に、複数のSSL証明書を運用できるようにするSSL/TLSの拡張仕様です。

(引用元 : https://www.stream.co.jp/blog/blogpost-38236/ )

まさしく今回のケースですね。

SSL/TLSの通信は以下のシーケンスで行われ、サーバからクライアントへ証明書が送られるのは「Certificate」メッセージの中ですが、この段階では、サーバは、クライアントがアクセスしたいドメインの情報が分からないため、適切な証明書を送付することができません。 (引用元 : https://milestone-of-se.nesuke.com/nw-basic/tls/https-structure/)

そこで生まれた仕組みがSNIで、前段階でアクセス先ドメインをサーバ側に伝えることによって、単一サーバで複数ドメインを設定できるようになりました。

というわけで、今回も単一のALBに複数のFQDNが紐づいており、単純にコマンドを打っても、ALB側からするとどのFQDNに対してアクセスされているのかが分からないため、明示してあげる必要があります。 servernameオプションで指定ができます。

結果が以下↓

[root@ip-172-16-0-51 ~]# openssl s_client -connect def.yyy.jp:443 -showcerts -servername def.yyy.jp
.....
---
Certificate chain
 0 s:/jurisdictionC=JP ... /CN=def.yyy.jp
.....
 1 s:/C=US ... /CN=abc.yyy.jp
.....
 2 s:/jurisdictionC=JP ... /CN=def.yyy.jp
.....

ばっちりです✌️

なぜクロスルート証明書なのか

ちょっと話がそれますが、今回色々分からなくてたくさんググっていると、目につく関連キーワードが。。

最近の仕様変更でクロスルートになったという話だったのでトレンドなのかと思いきや非推奨だなんて。

もう少し深めてみると、そもそもクロスルート証明書が生まれた理由は暗号鍵の鍵長にあるようです。
コンピュータの計算能力が増すにつれて、解読を防ぐため鍵長はどんどん長くなっていきましたが、クライアント側がそれに追いつけず、最高強度の 2048bit が扱えないケースが生まれました。
そのため、2048bit が扱えるクライアントでは、セキュリティ強度の高い 2048bitで、そうでないクライアントは 1024bit で、と使い分けられるよう、クロスルート証明書が生まれたとのこと。
それも2010年には完全に 2048bit に移行しており、クロスルートを残しておく = 脆弱なルートが残っているということになるため、非推奨ということみたいです。(参考)

ではなぜ DigiCert はこのタイミングでクロスルート証明書に変えたのかという疑問が残りますが、ちゃんとアナウンスがありました。

2023年3月9日(木)、日本時間午前2時より、TLS/SSL証明書を第五世代ルート(G5ルート)および中間CA証明書階層への移行を開始します。(中略) 新しいG5ルートが旧来のデジサートルート証明書同様に普及するまでの間、(中略) デジサートが提供のクロスルート証明書をインストールいただくことを推奨いたします。

新たなG5ルートという証明書チェーンへの移行期間ということでした。謎が解けました。

実機を確認してみる

証明書チェーンの移行期間ということですが、OS/ブラウザにプリインストールされているルート証明書はどうなっているのでしょうか。
「証明書チェーンの仕組み」の項でも記載した通り、信頼するルート認証局の情報はあらかじめインストールされているはずですが、 2023/3月から適用される新しい証明書階層となると、現状の実機がどうなっているか気になります。

配置されている場所はOSによって異なるようですが、今回ログイン対象は AmazonLinux2 です。

[root@ip-172-16-0-51 ~]# cat /etc/pki/tls/certs/ca-bundle.crt | grep Digi
# DigiCert Assured ID Root CA
# DigiCert Assured ID Root G2
# DigiCert Assured ID Root G3
# DigiCert Global Root G2
# DigiCert Global Root G3
# DigiCert High Assurance EV Root CA
# DigiCert Trusted Root G4

「証明書の階層関係を調べる」の項で出力した、2つのルート証明書情報を再度おさらい。

 # DigiCertGlobalRootCA.crt

Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA


# TrustedRoot.crt

Issuer: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 
Subject: C = US, O = "DigiCert, Inc.", CN = DigiCert TLS RSA4096 Root G5 

DigiCertGlobalRootCA.crt の CN に記載の「DigiCert Global Root CA」が、実機の確認結果の中にもありますね!
しかし、もう1つの TrustedRoot.crt の CN に記載の 「DigiCert TLS RSA4096 Root G5 」は実機にはありません。

後者はこれから移行していくG5ルートのルート証明書であり、既存のサーバにはまだ情報がないってことですね。
クロスルートの場合、どちらか一方のルートが確認できれば正常にアクセスできるため、片方が成り立ってなくても問題はありません。

まとめ

クロスルート証明書のインポートをテーマに、インフラ基礎を深掘ってみました。
最後に、思っていることを小声で書きます。

デジタル証明書の目的は大きく2つです。

  1. 通信データの暗号化
  2. 運営者の実在性の確認

証明書にはEV, OV, DVと3種類あります。
(引用元 : https://www.cybertrust.co.jp/blog/ssl/knowledge/certificates-types.html )

違いは、認証方法にあります。EVが最も多くの認証を必要とするので、認証レベルは高いです。
しかし、これら3種の証明書のセキュリティ強度には、違いはありません。

DV証明書利用の場合、「2. 運営者の実在性の確認」の観点では、相対的に認証レベルが低くなります。 が、EV証明書利用の場合、かつてはアドレスバーの鍵マークが緑色になっていたり、組織名が表示されたり、利用者にとって分かりやすい表示になっていましたが、今はそれもなくなっているケースが多いです。(参考)

ユーザーは、わざわざ鍵マークをクリックしないと違いは分かりません。
かつ、EV証明書の発行には十数万かかり、これが毎年発生します。

さらに、AWS であれば、AWS 発行の証明書 (DV) を利用することができ、これを使えば証明書はAWSが勝手に更新してくれます。
兼ね合いではありますが、できるだけマネージドにした方が楽だなあと思います。

とはいえ、今回はインポート作業を経て、個人的にはとても勉強になりました。
日々のタスクをこなすことも大事ですが、分かるまで深めてみる時間もまた良いです。
丁寧に教えてくださったプロジェクトの皆様に大感謝でした!