コンテンツにスキップ

第23章: mTLS(クライアント証明書)サービス間認証(実践チュートリアル)

APIキーやBearerトークンによる認証は、「ヘッダーの漏洩」や「リバースプロキシでの平文傍受」のリスクが常に伴います。 mTLS(Mutual TLS: 相互TLS認証) を導入すると、リクエスト送信側(Workers)が正規の暗号化クライアント証明書を提示しない限り、TCP/TLSハンドシェイクの段階で通信が物理的に遮断されます。

本章では、OpenSSLによるプライベートCAと証明書の作成から、WranglerによるCloudflareへの登録、セキュア通信の実行までをステップバイステップで習得します。


本チュートリアルのゴール

  • OpenSSL: 自作プライベートCAとクライアント証明書・秘密鍵の生成
  • Wrangler CLI: wrangler mtls-certificates upload による証明書のクラウド登録
  • Workers 実装: mTLSクライアント証明書を付与して厳重な保護下にある社内APIへ通信
【mTLSの暗号通信フロー】
[ Cloudflare Workers ]
│ 1. サーバー証明書の検証 (通常のTLS)
│ 2. クライアント証明書を提示 (mTLS)
[ 社内セキュアサーバー ] (証明書が不一致なら即座にTCP切断!)

Step 1: OpenSSLによる証明書の作成(ローカル)

まずはターミナルで、テスト用の認証局(CA)とクライアント証明書を作成します。

Terminal window
mkdir mtls-certs && cd mtls-certs
# 1. プライベートCA秘密鍵の生成
openssl genrsa -out ca.key 2048
# 2. ルートCA証明書(有効期限1年)の作成
openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
-subj "/CN=MyEnterpriseRootCA"
# 3. Cloudflare Worker用のクライアント秘密鍵と署名要求(CSR)を作成
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
-subj "/CN=CloudflareWorkerClient"
# 4. ルートCAで署名し、クライアント証明書(client.crt)を発行
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key \
-set_serial 01 -out client.crt

生成されたファイル:

  • client.crt(クライアント証明書)
  • client.key(クライアント秘密鍵)

Step 2: Wrangler CLIで証明書をアップロード

生成したクライアント証明書と秘密鍵を、Cloudflareアカウントへ登録します。

Terminal window
npx wrangler mtls-certificates upload \
--cert client.crt \
--key client.key \
--name "worker-internal-mtls"

出力例:

Uploaded mTLS Certificate 'worker-internal-mtls'
ID: "7a8b9c0d-1234-5678-90ab-cdef12345678"

発行された証明書IDをメモします。


Step 3: wrangler.jsonc へのバインディング

Workerプロジェクトの wrangler.jsonc を開き、mtls_certificates を設定します。

{
"name": "mtls-client-service",
"main": "src/index.ts",
"compatibility_date": "2024-09-01",
"mtls_certificates": [
{
"binding": "INTERNAL_API_CERT",
"certificate_id": "7a8b9c0d-1234-5678-90ab-cdef12345678"
}
]
}

型定義を更新します。

Terminal window
npx wrangler types

Step 4: mTLS通信コードの実装(src/index.ts

通常の fetch() ではなく、バインディングされた証明書オブジェクトの fetch() を呼び出すだけで、自動的にクライアント証明書が付与されます。

import { Hono } from 'hono';
type Bindings = {
INTERNAL_API_CERT: {
fetch: typeof fetch;
};
};
const app = new Hono<{ Bindings: Bindings }>();
app.get('/api/sync-internal', async (c) => {
try {
// クライアント証明書を提示してセキュアオリジンへリクエスト
const response = await c.env.INTERNAL_API_CERT.fetch(
'https://secure-internal.example.com/api/classified-data',
{
method: 'GET',
headers: { 'User-Agent': 'Cloudflare-Worker-mTLS' },
}
);
if (!response.ok) {
return c.json({ error: `通信エラー: ${response.status}` }, 502);
}
const data = await response.json();
return c.json({ success: true, data });
} catch (err: any) {
return c.json({ error: `mTLSハンドシェイク失敗: ${err.message}` }, 500);
}
});
export default app;

Step 5: 証明書の管理と一覧確認(CLI)

Terminal window
# 登録済み mTLS 証明書の一覧表示
npx wrangler mtls-certificates list
# 不要になった証明書の削除
npx wrangler mtls-certificates delete <CERTIFICATE_ID>

まとめ

  • ネットワーク層での遮断: 不正なアクセス元はTLSハンドシェイク時点で拒絶されるため、アプリケーションサーバーのCPUを一切浪費しません。
  • 専用線不要: パブリックなインターネット経由でありながら、金融機関レベルのゼロトラストサービス間通信が実現できます。

💡 用語解説コラム

[!NOTE] mTLS (相互TLS認証 / Mutual TLS)
通常はクライアントがサーバーの証明書を検証しますが、mTLSでは「サーバー側もクライアントの証明書を検証」します。許可されたクライアント証明書を持たない端末は通信開始すらできません。

[!NOTE] PKI (公開鍵暗号基盤)
認証局(CA)がデジタル証明書を発行・管理することで、ネットワーク上の相手が本物であることを保証するセキュリティの基幹技術。