はじめに
今やインターネット通信の大半はHTTPSが前提となり、SASEやゼロトラストを扱うエンジニアにとって証明書の仕組みを理解することは必須の知識になっています。
特に、SSL/TLS証明書・認証局(CA)・TLS 復号といった概念は「なんとなく知っている」では済まされず、仕組みとして理解しておくことが当たり前となっているように思います。
SSL/TLS証明書や認証局について解説しているサイトや本は山ほどありますが、ここでは文字での説明ベースに実際の画面やSASE製品としてCloudflareを導入した時の動きを見ながら、証明書とは何なのか、どのように使われ、どのように検証され、どのように通信を保護しているのかをできるだけシンプルに整理して理解できるようにまとめました。
HTTPSとは
まず、HTTPSとはHTTPの通信をTLSという暗号化プロトコルで保護し、安全に通信できるようにした仕組みです。
HTTPは平文で通信するため、通信内容が盗み見られたり、改ざんされたりするリスクがあります。
そこでTLSを使って 通信内容を暗号化し、第三者から見えないようにするわけです。
さらにTLSは暗号化だけでなく、証明書を使ってサーバーが本物であるかどうかを確認する役割も担っています。この記事では、暗号化ではなくサーバーの身分確認に焦点を当てています。
TLSによるHTTPS 通信が確立するまでの流れは次の通りです。(詳細は後ほど解説します)
(1)ブラウザ⇒サーバーへ証明書の要求
ブラウザは、アクセス先のサーバーが本物かどうか確認するために証明書を要求します。
サーバーはこれに対してサーバー証明書を返します。
(2)ブラウザが証明書を検証する
受け取った証明書について、ブラウザは以下を確認します。
・発行元の CA(認証局)は信頼できるか
・証明書が有効期限内か
・アクセス先のドメイン名と一致しているか
・改ざんされていないか
これがいわゆる 証明書チェーンの検証です。
(3)鍵交換を行う
上記の確認にすべて合格するとサーバーが本物だと判断され、ブラウザはサーバー証明書内の公開鍵を利用して共通鍵を生成します。
この共通鍵は実際の通信データを暗号化するために使われます。
(4)共通鍵を利用して暗号化通信を開始
以降の通信はすべて共通鍵で暗号化され、盗聴・改ざんされない安全なHTTPS通信が成立します。
SSL/TLS証明書とは
SSL/TLS証明書とは、本記事で主に扱うサーバー証明書のことです。
通信相手が本物であることを証明する「デジタル身分証明書」として利用されます。
証明書には以下の情報が含まれています。
・サーバーの公開鍵
・証明書の所有者(例:www.example.com)
・有効期限
・発行した認証局(CA)
・改ざんされていないことを示す電子署名
SSL/TLS証明書には無償のものと有償のものがあります。
代表的な無償の証明書として、Let's Encryptによって発行されたものがあり、多くのWebサイトで利用されています。証明書を信頼する仕組みは同じですが、有償証明書では、以下の付加価値が提供されます。
・サポート対応
・長期間の証明書管理
・組織情報の確認(OV証明書)
・企業実在性の厳格な確認(EV証明書)
・保証制度
無償証明書はCA(Let's Encryptなど)にwww.example.comの証明書を発行してくださいと申請したら、あなたは本当にドメインwww.exaple.comの管理者ですか?という確認を行うためにDNS認証(TXTレコードの作成)などのドメイン所有確認を求めます。ドメイン管理者は、DNSに指示されたTXTレコードを登録し、CAがそれを確認出来たら証明書を発行します。(発行したCAの署名付きで、後述の証明書チェーンに利用される)
有料証明書は、上記の本当にドメインを管理しているかの確認に加え、OV(Organization Validation)やEV(Extended Validation)の組織確認を行います。
認証局(CA)とは
認証局(CA)とは、証明書を発行し、その証明書が正しい相手に発行された本物であることを保証する第三者機関のことです。CAの仕事は以下の通りです。
・サーバーやクライアントの公開鍵に署名して証明書を発行
・証明書自体が改ざんされていないことを保証
・証明書の失効を管理
サーバーが本物であることを証明する証明書が偽物だったら元も子もないので、CAが第三者として証明書を発行し、その正当性を保証します。
証明書チェーンとは
証明書チェーンとは、サーバー証明書に付与された中間CAの署名を中間CA証明書によって検証し、さらに中間CA証明書に付与されたルートCAの署名をルートCA証明書によって検証することで、「信頼の連鎖」をたどる仕組みのことです。
ブラウザはサーバー証明書だけを見ているわけではなく、その証明書がどの中間CA(認証局)によって発行(署名)され、そのCAはさらにどの上位CAによって発行されているか、という証明書の階層構造を上にたどっていきます。
ルートCA証明書は自分自身で署名しているため、さらに上位のCA証明書で検証するのではなく、OSやブラウザの信頼ストアに登録されているルートCA証明書に到達し、そのルートCA証明書を信頼できると確認できれば、「この証明書チェーン全体は信頼できる」と判断されます。
ちなみに、Linux環境では利用するアプリケーションなどによって証明書ストアの管理方法が異なるため、ルートCA証明書が自動的に登録されず、手動でインポートが必要になる場合があります。
なお、中間CAはルートCAの秘密鍵を直接利用することなく証明書の発行を行うことで、ルートCAの鍵を保護しつつ運用を分離する役割があります。
実際にブラウザで確認してみる
HTTPS接続の確認
qiita.com へアクセスし、アドレスバー左のマークを押すと「この接続は保護されています」と表示されます。これは、ブラウザとサーバー間の通信がTLSによって暗号化されたHTTPS通信として確立していることを示しています。

さらに「この接続は保護されています」を押すと、「このサイトに送信した情報が第三者にみられることはありません」と表示され、通信内容が暗号化されていることが確認できます。

サーバ証明書(SSL/TLS証明書)の確認
その下の「証明書は有効です」を押すと、サーバー証明書の詳細が確認できます。
証明書ビューアを見ると、qiita.comのサーバー証明書は「Amazon RSA 2048 M03」という中間CAによって署名・発行されていることがわかります。

証明書チェーンの確認
証明書ビューアの「詳細」タブを見ると、中間CA(Amazon RSA 2048 M03)の証明書はAmazon Root CA 1というルートCAによって署名されていることがわかります。
つまり、証明書チェーンは以下のように構成されています。
ブラウザはこのチェーンを上位にたどり、最終的に信頼できるルートCA証明書に到達すれば「この証明書チェーンは信頼できる」と判断します。
Amazon Root CA 1(ルートCA証明書)
└─ Amazon RSA 2048 M03(中間CA証明書)
└─ qiita.com(サーバー証明書)
ルートCAの確認
先ほどルートCA証明書はOSやブラウザの信頼ストアに登録されていると説明しました。しかし、ChromeはOSのルートストアに加え、独自のChrome Root Storeも利用しています。
Chromeのルートストアは以下の手順で確認できます。
設定のプライバシーとセキュリティを開き、「証明書の管理」を押します。

証明書マネージャが表示されるので、画面左のメニューから「Chrome Root Store」を開きます。
Amazon Root CA 1がありますね。
このことから、Chromeは証明書チェーンをたどった結果、Chrome ルートストアに登録されているAmazon Root CA 1まで到達できるため、qiita.comの証明書を信頼できると判断しています。
ブラウザはqiita.comの証明書を直接信頼しているわけではなく、信頼済みのAmazon Root CA 1まで証明書チェーンをたどれるため、qiita.comの証明書を信頼しています。

ちなみに、windows OSにプリインストールされているルートCA証明書の確認方法は以下の通りです。
win+Rを押しcertmgr.mscを検索します。

証明書マネージャから、「信頼されたルート証明機関」の「証明書」にOSが信頼するルートCA証明書が一覧表示されます。

TLS復号(TLS Inspection)とは
TLS復号とは、HTTPSの暗号化された通信を一度復号し、中身を検査したうえで再度暗号化して転送する仕組みのことです。
CloudflareやCatoなどのSASE製品の機能としてあるURLフィルタリングやマルウェア検査などは、暗号化されたままでは行えません。そこで、TLS復号を使って一度中身を見られる状態にする必要があります。
通信の流れは以下のようになります。
①クライアント→CloudflareにTLS接続
クライアントはCloudflareが提示する「仮のサーバー証明書」を信頼してTLSを張る。
②Cloudflare が通信を復号して中身を検査
URLフィルタリング、マルウェアスキャン、DLPなどを実施。
③Cloudflare→本物のWebサーバーへ再度TLS接続
Cloudflareは本物のサーバーと別のTLSセッションを張る。
④検査後の通信をクライアントへ返す
つまり、Cloudflareがブラウザとサーバーの間でTLSを二重に張るという構造になります。
仮のサーバー証明書が必要になる理由は、ブラウザがexample.comにアクセスする際、直接サーバーに行かず一度Cloudflareを通して通信内容のチェックを行うために一時的にCloudflareがブラウザに対して「私はexample.comのサーバーです」と偽装する必要があるからです。
そうするためには、下記が必要となります。
・CloudflareのルートCA証明書をOSにインストール
・CloudflareがそのCAを使って仮のサーバー証明書を発行
これにより、ブラウザはCloudflareが発行した仮のサーバー証明書を信頼できると判断し、TLS通信を確立できます。
Cloudflareと本物のWebサーバー間は、Cloudflare未利用時のブラウザとサーバー間と同様の流れでTLS接続します。
端末とCloudflare間の通信経路を保護するために、Cloudflare One Client(旧:WARP)が利用されます。Cloudflare One ClientはWireGuardやMASQUEを利用して、端末とCloudflare間に暗号化されたトンネルを構築します。ブラウザが生成したHTTP通信は、このトンネルの中を通ってCloudflareへ送られます。
とても複雑に思えますが、ブラウザから見ると通常のHTTPS通信とほぼ同じように動作します。違いは、通信経路の途中にCloudflareが入り、一度通信を復号・検査してから再暗号化している点です。
このようにSASEは、HTTPSによる安全な通信を維持しつつ、TLS復号によって通信内容を検査することで、従来は確認できなかった暗号化トラフィックに対してもSSEによるセキュリティ対策を適用できるようにしています。

実際にCloudflare(SASE)を導入し、ブラウザで確認してみる
サーバ証明書の確認
Cloudflareのエージェントを端末にインストールし、Cloudflareとトンネルを張った状態で先ほどと同じ確認をしてみようと思います。
同様の手順でブラウザからサーバ証明書を確認すると、今度はqiita.comのサーバー証明書がCloudflare のGateway CAによって署名されていることがわかります。
これは、Cloudflare GatewayのTLS復号(TLS Inspection)が有効になっているためです。
CloudflareはTLS復号を行う際、ブラウザに対して自分がqiita.comであるように振る舞う必要があります。
そのため、CloudflareはGateway CAによってqiita.comという仮のサーバ証明書を発行します。


このようにしてCloudflareはブラウザとのTLSを復号し、中身を検査したうえで、改めて本物のqiita.comとTLSを張り直して通信を転送します。
CloudflareのGateway CAとは
また、CloudflareのGateway CAは公的なルートCAではなくプライベートなものであり、OSやブラウザの標準の信頼ストアには登録されていません。
なので、端末に手動でインストールする必要があります。Cloudflareは、エージェント(Cloudflare One Client)をインストールするのと同時に自動でGateway CA証明書もOSのルートストアに追加してくれています。
確認方法は先ほどの手順どおりで、証明書マネージャの「信頼されたルート証明機関」を見るとGateway CAがインストールされていることがわかります。

試しにこのルートCA証明書を削除してみたらどうなるでしょうか。
ブラウザはCloudflareが提示した仮のサーバー証明書の証明書チェーンをブラウザが信頼済みのルートCA証明書までたどれなくなり、証明書チェーンの検証ができずに証明書エラーとなります。

ちなみに、Cloudflareのエージェントを通してインストールされるGateway CAはCloudflareのダッシュボードのトラフィックの設定から確認できます。

TLS復号の確認
通常のHTTPS通信では通信内容は暗号化されているため、途中経路の機器からは確認できません。しかしTLS復号を有効にすると、Cloudflareが一度通信を復号するため、URLやリクエスト情報などを確認できるようになります。
許可・拒否などのポリシー制御や、DLP検査なども可能になります。

TLS復号除外、証明書ピンニングとは
TLS復号除外とは、特定の通信においてTLS復号を行わず、そのまま暗号化された状態で通過させる設定のことです。この設定を行った通信はCloudflareなどのSASE製品によるURLフィルタリング、マルウェアスキャン、DLPなどを行うことができません。
本来であれば、セキュリティの観点から可能な限りTLS復号を行い、通信内容を検査することが望ましいです。
しかし、実際にはTLS復号を行ってはいけない通信や、プライバシーや技術的制約から復号できない通信が存在します。
後者の技術的に復号できない通信の代表例は、「証明書ピンニング」です。
クライアント側が特定のCA、特定の公開鍵、特定の証明書を固定(Pin)している場合、Cloudflareが発行した仮のサーバー証明書は受け入れられません。これを「証明書ピンニング」と呼び、この場合はTLS復号除外の設定をしてアクセスする必要があります。
TLS復号除外の確認
CloudflareのHTTPポリシーでqiita.com宛の通信は検査しない(復号しない)というポリシーを作成します。

そうすると、CloudflareはTLS復号を行わず、ブラウザとqiita.com間のTLS通信をそのまま通過させます。そのため、ブラウザから見えるサーバー証明書はCloudflare Gatewayの仮の証明書ではなく、qiita.com本来のサーバー証明書となります。

Cloudflareのログ上でもBYPASSとなっており、通信内容の情報は取得できていません。ブロックやDLP検査などもできなくなります。
ブラウザとサーバー間で直接TLS接続し、暗号化されたHTTPS通信を行うため、Cloudflareは中身をみれないためです。

クライアント証明書とは
今まではサーバーが持つSSL/TLS証明書にフォーカスしていましたが、クライアントが持ち、サーバーに提示するクライアント証明書というものもあります。
サーバーとクライアント相互に確認するので、Mutual TLS(相互認証)証明書、デバイスを識別するデバイス証明書と呼ぶことがあります。
通常のHTTPS通信では利用しませんが、SASE導入時など、クライアント側の正当性確認やアクセス制限を設けたいときに利用します。
Cloudflareでのクライアント証明書を利用したアクセス制御方法については↓記事にまとめました。
おわりに
証明書の仕組みは、普段は目に見えないため最初は直感的に理解しづらい部分が多い分野です。
しかし、SASEやセキュリティに携わるエンジニアにとっては、通信の安全性を支える基盤として欠かせない知識でもあります。
今回のように、実際にブラウザやOSの証明書ストアを確認しながら動作を追っていくと、「なぜこの証明書が信頼されるのか」「CloudflareがどのようにTLSを扱っているのか」といった仕組みが、一気に立体的に理解できるようになりました。
この記事で扱った内容を土台に、これからも知識を深め、より良い設計や検証ができるエンジニアを目指して精進していきたいと思います!

