相互 TLS(mTLS)認証 ↗ では、TLS ハンドシェイク中にクライアントとサーバーの両方が証明書を提示します。Cloudflare Access の実装では、アップロードした CA でクライアント証明書を検証します(サーバー証明書の検証は通常の TLS が担当します)。Access の mTLS には次の 2 つの用途があります。
- ID プロバイダーを使わないデバイスを認証する — 自動化システムや IoT デバイスは、IdP でログインする代わりにクライアント証明書を提示して身元を証明できます。
- 2 つ目の認証要素を追加する — IdP でログインするチームメンバーにも、有効なクライアント証明書の提示を求め、セキュリティを一段厚くできます。
ルート認証局(CA)を Access にアップロードすると、一致するクライアント証明書を持つデバイスからのリクエストだけが通過します。リクエストがアプリケーションに届くと、Access はクライアントに証明書の提示を求めます。有効な証明書を提示できない場合、リクエストはブロックされます。有効な証明書を提示した場合、Access は鍵交換を完了して検証します。
- mTLS で保護したいホスト名の Access アプリケーション
- デバイス向けのクライアント証明書を発行する CA
-
CA 証明書は、公開信頼されている CA のもの、または自己署名のものを使用できます。
-
証明書の
Basic Constraintsでは、属性CAをTRUEに設定する必要があります。 -
証明書は、次のいずれかの署名アルゴリズムを使用する必要があります。
使用できる署名アルゴリズム
x509.SHA1WithRSAx509.SHA256WithRSAx509.SHA384WithRSAx509.SHA512WithRSAx509.ECDSAWithSHA1x509.ECDSAWithSHA256x509.ECDSAWithSHA384x509.ECDSAWithSHA512
-
-
Cloudflare ダッシュボード ↗ で Zero Trust > Access controls > Service credentials > Mutual TLS を開きます。
-
Add mTLS Certificate を選択します。
-
ルート CA の名前を任意で入力します。
-
Certificate content にルート CA の内容を貼り付けます。
クライアント証明書がルート CA で直接署名されている場合は、ルートだけをアップロードします。クライアント証明書が中間証明書で署名されている場合は、CA チェーン全体(中間とルート)をアップロードする必要があります。例:
-----BEGIN CERTIFICATE----- <intermediate.pem> -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- <rootCA.pem> -----END CERTIFICATE-----SSL/TLS のサーバー証明書は含めないでください。Access はユーザーのデバイスと Cloudflare 間の接続を検証するために、CA チェーンだけを使います。
-
Associated hostnames に、この証明書を使う完全修飾ドメイン名(FQDN)を入力します。
これらの FQDN は、Access ポリシー で保護するリソースのホスト名になります。ルート CA は、保護対象アプリケーションが使う FQDN に関連付ける必要があります。
-
ポリシーを保存します。
-
Access controls > Policies を開きます。
-
次のいずれかの セレクター を使って Access ポリシーを作成 します。
- Valid Certificate: ルート CA で認証できるクライアント証明書なら、どれでも続行を許可します。
- Common Name: 特定のコモンネームを持つクライアント証明書だけを続行許可します。
-
IdP でログインする必要がないクライアント向けの場合は、ポリシーの Action を Service Auth に設定します。
mTLS ポリシーの例
アクション ルールタイプ セレクター 値 Service Auth Include Common Name John Doe -
ポリシーを保存し、Access controls > Applications を開きます。
-
mTLS を適用したいアプリケーションを選び、Configure を選択します。アプリケーションは、手順 5 の Associated hostnames 一覧に含まれている必要があります。
-
Policies タブで、mTLS ポリシーを追加します。
-
アプリケーションを保存します。
これで、クライアント証明書を使ってアプリケーションに認証できます。クライアント証明書の提示方法は、mTLS をテストする を参照してください。
mTLS ポリシーで保護したアプリケーションをテストするには、次の手順を行います。
-
まず、クライアント証明書なしでサイトに curl します。 この curl の例は、
https://auth.example.comに Access アプリケーションとポリシー を設定したサイトexample.com向けです。curl -sv https://auth.example.comリクエストにクライアント証明書がないと、
403 forbiddenが返り、サイトにアクセスできません。 -
次に、クライアント証明書と鍵をリクエストに追加します。
curl -sv https://auth.example.com --cert example.pem --key key.pem
認証が成功すると、応答に CF_Authorization Set-Cookie ヘッダーが返ります。
ブラウザーで mTLS 保護のアプリケーションにアクセスするには、クライアント証明書をブラウザーの証明書マネージャーにインポートする必要があります。手順はブラウザーによって異なります。ブラウザーは、OS のルートストアを使う場合と、独自の内部トラストストアを使う場合があります。
次の例では、クライアント証明書を macOS のシステムキーチェーンに追加する方法を示します。
- クライアント証明書と鍵があるディレクトリに移動します。
- Keychain Access で
client.pemファイルを開きます。求められた場合は、ローカルのパスワードを入力します。 - Keychain で、用途に合うアクセスオプションを選び、Add を選択します。
- 証明書の一覧で、いまインストールした証明書を探します。Keychain Access は、この証明書を信頼されていない状態として表示します。証明書を右クリックし、Get Info を選択します。
- Trust を選択します。When using this certificate で Always Trust を選びます。
- Keychain Access で
ブラウザーが macOS のシステムストアを使う場合は、これでブラウザーから mTLS アプリケーションに接続できます。
オープンソースの公開鍵基盤(PKI)ツールを使って、Cloudflare Access の mTLS 機能をテストするための証明書を生成できます。
このセクションでは、OpenSSL ↗ でルート証明書と中間証明書を生成し、CA チェーンで認証できるクライアント証明書を発行する方法を説明します。
-
ルート CA の秘密鍵を生成します。
openssl genrsa -aes256 -out rootCA.key 4096求められたら、
rootCA.keyに使うパスワードを入力します。 -
rootCA.pemという自己署名ルート証明書を作成します。openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.pem秘密鍵のパスワードと、任意のフィールドの入力を求められます。テスト目的なら、任意フィールドは空のままで構いません。
-
中間 CA の秘密鍵を生成します。
openssl genrsa -aes256 -out intermediate.key 4096求められたら、
intermediate.keyに使うパスワードを入力します。 -
中間証明書の証明書署名要求(CSR)を作成します。
openssl req -new -sha256 -key intermediate.key -out intermediate.csr秘密鍵のパスワードと、任意のフィールドの入力を求められます。テスト目的なら、任意フィールドは空のままで構いません。
-
v3_intermediate_ca.extという CA 拡張ファイルを作成します。例:subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, cRLSign, keyCertSignbasicConstraintsにCA:trueプロパティが含まれていることを確認してください。このプロパティがあると、中間証明書が CA として動作し、クライアント証明書に署名できます。 -
ルート CA で中間証明書に署名します。
openssl x509 -req -in intermediate.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out intermediate.pem -days 1825 -sha256 -extfile v3_intermediate_ca.ext
-
中間証明書とルート証明書を 1 つのファイルにまとめます。
cat intermediate.pem rootCA.pem > ca-chain.pemファイルの先頭に中間証明書を置き、そのあとに署名した証明書を続けます。
-
ca-chain.pemの内容を Cloudflare Access にアップロードします。手順は Access アプリケーションに mTLS を追加する を参照してください。
-
クライアント用の秘密鍵を生成します。
openssl genrsa -out client.key 2048 -
クライアント証明書の CSR を作成します。
openssl req -new -key client.key -out client.csr任意のフィールドの入力を求められます。テスト目的なら、Common Name を
John Doeなどに設定できます。 -
中間証明書でクライアント証明書に署名します。
openssl x509 -req -in client.csr -CA intermediate.pem -CAkey intermediate.key -CAcreateserial -out client.pem -days 365 -sha256 -
証明書チェーンに対してクライアント証明書を検証します。
openssl verify -CAfile ca-chain.pem client.pemclient.pem: OK
これで、クライアント証明書(client.pem)とその鍵(client.key)を使って mTLS をテスト できます。
このガイドでは、Cloudflare の PKI ツールキット ↗ を使い、JSON ファイルからルート CA とクライアント証明書を生成します。
この手順では、Cloudflare の PKI ツールキットから次の 2 つのパッケージが必要です。
cf-sslcfssljson
これらのパッケージは Cloudflare SSL の GitHub リポジトリ ↗ からインストールできます。Go 1.12 以降の動作する環境が必要です。または、パッケージを直接ダウンロード ↗ することもできます。 Installation の手順に従ってツールキットをインストールし、ツールキット内のユーティリティプログラムをすべてインストールしてください。
-
ルート CA を保存する新しいディレクトリを作成します。
-
そのディレクトリ内に、次の 2 つのファイルを作成します。
-
CSR。
ca-csr.jsonというファイルを作成し、次の JSON を追加して保存します。{ "CN": "Access Testing CA", "key": { "algo": "rsa", "size": 4096 }, "names": [ { "C": "US", "L": "Austin", "O": "Access Testing", "OU": "TX", "ST": "Texas" } ] } -
config。
ca-config.jsonというファイルを作成し、次の JSON を追加して保存します。{ "signing": { "default": { "expiry": "8760h" }, "profiles": { "server": { "usages": ["signing", "key encipherment", "server auth"], "expiry": "8760h" }, "client": { "usages": ["signing", "key encipherment", "client auth"], "expiry": "8760h" } } } }
-
-
次のコマンドを実行し、それらのファイルでルート CA を生成します。
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
コマンドはルート証明書(
ca.pem)とその鍵(ca-key.pem)を出力します。lsca-config.json ca-csr.json ca-key.pem ca.csr ca.pem -
ca.pemの内容を Cloudflare Access にアップロードします。手順は Access アプリケーションに mTLS を追加する を参照してください。
アップロードしたルート CA で認証できるクライアント証明書を生成するには、次の手順を行います。
-
client-csr.jsonというファイルを作成し、次の JSON を追加します。{ "CN": "James Royal", "hosts": [""], "key": { "algo": "rsa", "size": 4096 }, "names": [ { "C": "US", "L": "Austin", "O": "Access", "OU": "Access Admins", "ST": "Texas" } ] } -
次のコマンドで、Cloudflare PKI ツールキットを使ってクライアント証明書を生成します。
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client-csr.json | cfssljson -bare client
コマンドはクライアント証明書ファイル(client.pem)とその鍵(client-key.pem)を出力します。これらのファイルで mTLS をテスト できます。
Cloudflare PKI ツールキットで、証明書失効リスト(CRL)も生成できます。このリストには失効したクライアント証明書が入ります。
-
先に生成したクライアント証明書からシリアル番号を取得します。そのシリアル番号、または失効させたいほかの番号を、16 進形式でテキストファイルに追加します。この例では
serials.txtというファイルを使います。 -
次のコマンドで CRL を作成します。
cfssl gencrl serials.txt ../mtls-test/ca.pem ../mtls-test/ca-key.pem | base64 -D > ca.crl
CRL はサーバーに追加するか、Cloudflare Worker で失効を強制する必要があります。Worker スクリプトの例は Cloudflare の GitHub リポジトリ ↗ にあります。
RFC 9440 ↗ は、クライアント証明書の情報をオリジンサーバーへ渡すための HTTP ヘッダーフィールド Client-Cert と Client-Cert-Chain を定義しています。これらのヘッダーは、リクエストヘッダー変更ルール と次の Ruleset Engine フィールドを使って組み立てできます。
cf.tls_client_auth.cert_rfc9440— RFC 9440 形式でエンコードしたクライアントのリーフ証明書です(リファレンスを参照)。cf.tls_client_auth.cert_chain_rfc9440— RFC 9440 形式でエンコードした証明書チェーンです(リーフ証明書は含みません。リファレンスを参照)。
フィールド定義のとおり、これらのフィールドは空文字列、または有効な RFC 9440 エンコードのいずれかになります。適切に使うには、以降のセクションで説明するいくつかの点を確認します。
cert_rfc9440 と cert_chain_rfc9440 フィールドは、証明書の検証結果に関係なく 値が入ります。つまり、クライアントが無効、期限切れ、または自己署名の証明書を提示しても、フィールドにはエンコードされた証明書データが入ります。値を信頼する前に、必ず次のフィールドを確認します。
cf.tls_client_auth.cert_verified— クライアント証明書が有効なときにtrueを返します。cf.tls_client_auth.cert_revoked— クライアント証明書が失効しているときにtrueを返します。
クライアントは、リクエストに独自の Client-Cert または Client-Cert-Chain ヘッダーを付けて、任意の値を注入できます。RFC 9440 のセキュリティ上の考慮事項 ↗ にあるとおり、証明書の有効性に関係なく、受信リクエストから既存の Client-Cert および Client-Cert-Chain ヘッダーを無条件に削除する必要があります。これにより、オリジンが信頼してしまう偽造証明書データの注入を防げます。
mTLS と証明書検証の設定方法は、mTLS を有効にする を参照してください。
エンコード後のリーフ証明書は 10 KiB、エンコード後のチェーンは 16 KiB が上限です。エンコード値が上限を超えると、対応するフィールドは空文字列になります。この状態は、次のフィールドで確認できます。
cf.tls_client_auth.cert_rfc9440_too_large— エンコードした証明書が 10 KiB を超えるときにtrueを返します。cf.tls_client_auth.cert_chain_rfc9440_too_large— エンコードしたチェーンが 16 KiB を超えるときにtrueを返します。
ここでは、これらのフィールドを安全に使い、信頼できる Client-Cert および Client-Cert-Chain ヘッダーを組み立ててオリジンへ転送する例を示します。
オリジンは、ヘッダーがあることをもって、クライアントが有効な証明書を提示したと判断できます。
注: クライアントが中間証明書を提示せず、リーフ証明書だけを提示した場合、Client-Cert-Chain ヘッダーは省略できます。
次のリクエストヘッダー変更ルールを作成します。 Remove ルールは Set dynamic ルールより前に置く必要があります。 クライアントが注入したヘッダーを、検証済みの値を設定する前に、すべてのリクエストから取り除くためです。
このルールは、クライアントが送った Client-Cert ヘッダーを無条件に削除します。
Expression Editor のテキスト:
trueModify request header で選ぶ操作: Remove
Header name: Client-Cert
このルールは、クライアントが送った Client-Cert-Chain ヘッダーを無条件に削除します。
Expression Editor のテキスト:
trueModify request header で選ぶ操作: Remove
Header name: Client-Cert-Chain
このルールは、クライアントが有効かつ未失効で、サイズ制限内の証明書を提示した場合にだけ、Client-Cert ヘッダーを設定します。
Expression Editor のテキスト:
cf.tls_client_auth.cert_verified
and not cf.tls_client_auth.cert_revoked
and not cf.tls_client_auth.cert_rfc9440_too_largeModify request header で選ぶ操作: Set dynamic
Header name: Client-Cert
Value: cf.tls_client_auth.cert_rfc9440
このルールは、クライアントが有効かつ未失効の証明書を提示し、チェーンが空でなくサイズ制限内である場合にだけ、Client-Cert-Chain ヘッダーを設定します。
Expression Editor のテキスト:
cf.tls_client_auth.cert_verified
and not cf.tls_client_auth.cert_revoked
and cf.tls_client_auth.cert_chain_rfc9440 ne ""
and not cf.tls_client_auth.cert_chain_rfc9440_too_largeModify request header で選ぶ操作: Set dynamic
Header name: Client-Cert-Chain
Value: cf.tls_client_auth.cert_chain_rfc9440
Cloudflare Worker でも、受信リクエストの tlsClientAuth プロパティを使い、RFC 9440 ヘッダーを組み立てできます。
上記と同じセキュリティ上の考慮事項が適用されます。
ホストに mTLS 認証を適用するだけでなく、クライアント証明書を HTTP ヘッダーとしてオリジンサーバーへ転送できます。この構成は、サーバーログに使うことがよくあります。
すべてのリクエストに証明書を付けないように、証明書は mTLS 接続の最初のリクエストでのみ転送されます。
証明書を転送する最も一般的な方法は、Cloudflare API で mTLS 証明書のホスト名設定を更新 することです。
Required API token permissions
At least one of the following token permissions is required:Access: Mutual TLS Certificates Write
curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/access/certificates/settings" \
--request PUT \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"settings": [
{
"hostname": "<HOSTNAME>",
"china_network": false,
"client_certificate_forwarding": true
}
]
}'client_certificate_forwarding を true に設定すると、mTLS 接続内のすべてのリクエストに次のヘッダーが付きます。
Cf-Client-Cert-Der-Base64Cf-Client-Cert-Sha256
Managed Transforms で HTTP レスポンスヘッダーを変更 し、TLS クライアント認証ヘッダー を渡すこともできます。
加えて、Workers では クライアント証明書 に関する詳細を取得できます。
const tlsHeaders = {
"X-CERT-ISSUER-DN": request.cf.tlsClientAuth.certIssuerDN,
"X-CERT-SUBJECT-DN": request.cf.tlsClientAuth.certSubjectDN,
"X-CERT-ISSUER-DN-L": request.cf.tlsClientAuth.certIssuerDNLegacy,
"X-CERT-SUBJECT-DN-L": request.cf.tlsClientAuth.certSubjectDNLegacy,
"X-CERT-SERIAL": request.cf.tlsClientAuth.certSerial,
"X-CERT-FINGER": request.cf.tlsClientAuth.certFingerprintSHA1,
"X-CERT-VERIFY": request.cf.tlsClientAuth.certVerify,
"X-CERT-NOTBE": request.cf.tlsClientAuth.certNotBefore,
"X-CERT-NOTAF": request.cf.tlsClientAuth.certNotAfter,
};mTLS は現在、次の構成では動作しません。
相互 TLS 証明書の期限切れ前に、Cloudflare は次の 通知 を送ります。
Access mTLS Certificate Expiration Alert
対象相互 TLS 認証にクライアント証明書を使う Access のお客様向けです。証明書の有効期限の 30 日前と 14 日前に通知します。
その他のオプション / フィルタなし。
含まれるプランAccess および / または Cloudflare for SaaS の購入。
受け取ったときの対応更新した証明書 をアップロードします。