相互 TLS (ビューワー) 検証用の CloudFront Connection Function コードを記述する - Amazon CloudFront

相互 TLS (ビューワー) 検証用の CloudFront Connection Function コードを記述する

CloudFront Connection Functions により、mTLS 証明書の検証とカスタム認証ロジックのための軽量な JavaScript 関数を記述できます。Connection Function コードは、クライアント証明書の検証、デバイス固有の認証ルールの実装、証明書失効シナリオの処理、世界中の CloudFront エッジロケーションでの TLS 接続の許可/拒否の決定を行うことができます。

接続関数は、CloudFront の組み込み証明書検証を独自のビジネスロジックで拡張する強力な方法を提供します。HTTP データを処理するビューワーリクエストおよびビューワーレスポンス関数とは異なり、Connection Functions は TLS レイヤーで動作し、証明書情報、クライアント IP アドレス、TLS 接続の詳細にアクセスできます。これは、標準 PKI 検証を超えるゼロトラストセキュリティモデル、デバイス認証システム、カスタム証明書検証ポリシーの実装に適しています。

Connection Function コードは、1 ミリ秒未満のスタートアップ時間で安全に隔離された環境で実行され、1 秒あたり数百万の接続を処理するようにスケーリングできます。ランタイムは証明書検証ワークロードのために最適化されており、CloudFront KeyValueStore との組み込み統合によりリアルタイムのデータ検索オペレーションが可能になり、証明書失効リストのチェックやデバイス許可リストの検証などの高度な認証シナリオが可能になります。

効果的な Connection Function コードを記述するには、以下のトピックを参照してください。完全なコード例とステップバイステップのチュートリアルについては、このガイドのチュートリアルセクションを参照し、CloudFront コンソールで利用可能な Connection Function の例を確認してください。

CloudFront Connection Function のユースケースと目的

CloudFront Connection Function を記述する前に、実装する必要がある証明書の検証または認証ロジックのタイプを慎重に決定してください。接続関数は、標準の PKI 証明書チェックを超えたカスタム検証を必要とする特定のユースケース向けに設計されています。ユースケースを理解すると、最適なパフォーマンスを維持しながら、セキュリティ要件を満たす効率的なコードを設計できます。

Connection Function の一般的なユースケースは次のとおりです。

  • 証明書失効の処理 - 失効した証明書を処理するためのカスタムポリシーを実装します。これには、証明書のローテーションの猶予期間、内部デバイスの信頼されたネットワークの例外、失効した証明書に一時的なアクセスが必要になる可能性がある緊急アクセスシナリオが含まれます。

  • オプションの mTLS サポート - mTLS 接続と非 mTLS 接続の両方を異なる認証ポリシーで処理するため、レガシークライアントとの互換性を維持しながら、証明書をサポートするクライアントのセキュリティを強化できます。

  • IP ベースの認証 - 証明書の検証をクライアント IP アドレスのチェックと組み合わせて、特定の地理的リージョン、企業ネットワーク、既知の悪意のある IP 範囲からのアクセスを制限するなど、セキュリティを強化します。

  • マルチテナント証明書の検証 - クライアント証明書の発行者またはサブジェクト属性に基づいて異なる認証局または検証基準が適用されるテナント固有の検証ルールを実装します。

  • 時間ベースのアクセスコントロール - 証明書自体の有効期限が切れていない場合でも、証明書が特定の時間、メンテナンスウィンドウ、または事業期間中にのみ有効な時間ベースの制限を適用します。

接続関数は、CloudFront が標準証明書検証 (信頼チェーンの検証、有効期限のチェック、署名の検証) を実行した後、TLS 接続が確立される前に実行されます。このタイミングにより、CloudFront の組み込み証明書検証のメリットを享受しながら、カスタム検証基準を柔軟に追加できます。関数は標準検証の結果を受け取り、標準基準とカスタム基準の両方に基づいて接続を許可または拒否するかどうかについて、情報に基づいた決定を行うことができます。

Connection Function を設計する場合、検証ロジックのパフォーマンスへの影響を検討してください。関数の実行制限は 5 ミリ秒であるため、複雑なオペレーションは速度に合わせて最適化する必要があります。複雑な計算ではなく高速なデータ検索に KeyValueStore を使用し、無効な証明書のフェイルファストに検証ロジックを構築します。

CloudFront Connection Function のイベント構造とレスポンス形式

CloudFront Connection Functions は、ビューワーリクエストおよびビューワーレスポンス関数とは異なるイベント構造を受け取ります。HTTP リクエスト/レスポンスデータの代わりに、接続関数は認証の決定に使用できる証明書と接続情報を受け取ります。

Connection Functions のイベント構造

Connection Functions は、証明書と接続情報を含むイベントオブジェクトを受け取ります。関数のイベント構造を以下に示します。

{ "clientCertificate": { "certificates": { "leaf": { "serialNumber": "string", "issuer": "string", "subject": "string", "validity": { "notBefore": "string", "notAfter": "string", }, "sha256Fingerprint": "string" } } }, "clientIp": "string", "endpoint": "string", "distributionId": "string", "connectionId": "string" }

以下に、イベントオブジェクトの構造の例を示します。

{ "clientCertificate": { "certificates": { "leaf": { "serialNumber": "00:9e:2a:af:16:56:e5:47:25:7d:2e:38:c3:f9:9d:57:fa", "issuer": "C=US, O=Ram, OU=Edge, ST=WA, CN=mTLS-CA, L=Snoqualmie", "subject": "C=US, O=Ram, OU=Edge, ST=WA, CN=mTLS-CA, L=Snoqualmie", "validity": { "notBefore": "2025-09-10T23:43:10Z", "notAfter": "2055-09-11T00:43:02Z" }, "sha256Fingerprint": "_w6bJ7aOAlGOj7NUhJxTfsfee-ONg_xop3_PTgTJpqs=" } } }, "clientIp": "127.0.0.1", "endpoint": "d3lch071jze0cb.cloudfront.net", "distributionId": "E1NXS4MQZH501R", "connectionId": "NpvTe1925xfj24a67sPQr7ae42BIq03FGhJJKfrQYWZcWZFp96SIIg==" }

Connection Functions のレスポンス形式

Connection Function は、接続を許可または拒否するかを示すレスポンスオブジェクトを返す必要があります。ヘルパーメソッドを使用して接続の決定を行います。

function connectionHandler(connection) { // Helper methods to allow or deny connections if (/* some logic to determine if function should allow connection */) { connection.allow(); } else { connection.deny(); } }

ビューワーリクエストおよびビューワーレスポンス関数とは異なり、Connection Functions は HTTP リクエストまたはレスポンスを変更できません。TLS 接続のみを許可または拒否できます。

CloudFront Connection Functions の JavaScript ランタイムの機能

CloudFront Connection Functions は CloudFront Functions JavaScript ランタイム 2.0 を使用します。これは、証明書検証ワークロード用に特別に最適化された安全で高性能な環境を提供します。ランタイムは、ミリ秒未満で開始し、CloudFront のグローバルエッジネットワーク全体で数百万の同時実行を処理するように設計されています。

ランタイム環境には、包括的な JavaScript 言語のサポートが含まれています。

  • ECMAScript 2020 (ES11) サポート - オプションの連鎖 (?.)、NULL 合体 (??)、大規模な証明書のシリアル番号を処理する BigInt などの最新の JavaScript 機能

  • 組み込みオブジェクト - オブジェクト、配列、JSON、Math、日付などの標準 JavaScript オブジェクト

  • コンソールログ記録 - console.log() を使用して、証明書検証の決定をデバッグおよびモニタリングします。ログはテスト中にリアルタイムで利用でき、開発中の検証ロジックのトラブルシューティングに役立ちます。

  • KeyValueStore 統合 - 超高速データ検索オペレーションのための CloudFront KeyValueStore へのネイティブアクセスにより、証明書失効のリアルタイムチェック、デバイス許可リストの検証、テナント固有の設定の取得を可能にします。

接続関数は、高性能な証明書検証のシナリオに最適化されています。ランタイムはメモリ管理、ガベージコレクション、リソースクリーンアップを自動的に処理し、数百万の同時接続において安定したパフォーマンスを確保します。すべてのオペレーションは確定的で高速に設計されており、KeyValueStore 検索は通常マイクロ秒で完了します。

ランタイム環境は関数の実行間で完全に分離されるため、異なるクライアント接続間でデータリークが発生することはありません。各関数の実行はクリーン状態から開始され、以前の実行結果や他の接続からのクライアントデータにアクセスすることはありません。

CloudFront Connection Function のヘルパーメソッドと API

CloudFront Connection Functions は、証明書の検証の決定を簡素化し、オブザーバビリティを強化するように設計された特殊なヘルパーメソッドを提供します。これらのメソッドは、接続検証ワークフローに最適化されており、CloudFront の接続ログ記録およびモニタリングシステムとシームレスに統合されます。

  • connection.allow() - TLS 接続の続行を許可します。このメソッドは、TLS ハンドシェイクを完了するよう CloudFront にシグナルを送信し、クライアントが接続を確立できるようにします。これは、証明書の検証に合格し、カスタム認証ロジックが満たされた場合に使用します。

  • connection.deny() - TLS 接続を拒否し、ハンドシェイクを終了します。このメソッドは、すぐに接続を終了し、HTTP トラフィックが流れるのを防ぎます。クライアントは TLS 接続エラーを受け取ります。これは、無効な証明書、認証の失敗、またはポリシー違反に使用します。

  • connection.logCustomData() - 接続ログにカスタムデータを追加します (最大 800 バイトの UTF-8 テキスト)。この方法により、セキュリティのモニタリング、コンプライアンス監査、トラブルシューティングのために、検証結果、証明書の詳細、または決定の根拠を CloudFront 接続ログに含めることができます。

これらのメソッドは、接続の決定を行い、モニタリングとデバッグに関連する情報のログを記録するためのクリーンで宣言型のインターフェイスを提供します。許可/拒否パターンにより、関数のインテントが明確になり、CloudFront が決定に基づいて接続処理を最適化できるようになります。カスタムログ記録データは CloudFront 接続ログですぐに利用でき、セキュリティモニタリングと運用のインサイトのためのログ分析ツールで使用できます。

関数が完了する前に、必ず connection.allow() または connection.deny() を呼び出してください。いずれのメソッドも呼び出されない場合、CloudFront はセキュリティ上の予防策としてデフォルトで接続を拒否します。

CloudFront Connection Function KeyValueStore の統合

CloudFront Connection Functions は CloudFront KeyValueStore を使用して、証明書検証シナリオの超高速データ検索を実行できます。KeyValueStore は、すべての CloudFront エッジロケーションにわたり、マイクロ秒の検索時間でグローバルで結果整合性のあるデータアクセスを提供するため、Connection Functions にとって特に強力です。これにより、証明書失効リスト、デバイスの許可リスト、テナント設定、および TLS ハンドシェイク中にアクセスする必要がある他の検証データを維持するのに最適です。

KeyValueStore 統合は、高性能の接続検証ワークフロー専用に設計されています。

  • kvsHandle.exists(キー) - 値を取得せずに KeyValueStore にキーが存在するかどうかを確認します。これは、証明書のシリアル番号が失効リストにあるかどうかのみを知る必要がある証明書失効チェックなどのバイナリ検証シナリオに最も効率的な方法です。

  • kvsHandle.get(キー) - より複雑な検証シナリオのために KeyValueStore から値を取得します。これは、証明書またはデバイス識別子に関連付けられた設定データ、検証ルール、またはメタデータにアクセスする必要がある場合に使用します。

KeyValueStore オペレーションは非同期であり、非同期/待機構文で使用する必要があります。KeyValueStore の合計サイズ制限は 10 MB で、最大 1,000 万個のキーと値のペアをサポートします。KeyValueStore データはすべてのエッジロケーションで結果的に整合性があり、更新は通常数秒以内に伝播されます。

最適なパフォーマンスを得るには、KeyValueStore キーを構造化して検索オペレーションを最小限にします。シンプルな失効チェックのキーとして証明書のシリアル番号を使用するか、マルチ CA 環境の発行者のハッシュとシリアル番号を組み合わせた複合キーを作成します。データ構造を設計するときは、キーの複雑さと KeyValueStore 容量のトレードオフを考慮してください。

async および await を使用します

接続関数は、async/await 構文を使用した非同期オペレーションをサポートします。これは、KeyValueStore オペレーションや他の非同期タスクを操作するときに必要です。async/await パターンにより、TLS ハンドシェイク処理に必要な高性能の特徴を維持しながら、関数は接続の決定を行う前に KeyValueStore の検索が完了するまで待機します。

KeyValueStore オペレーションは非常に高速ですが、CloudFront の分散インフラストラクチャ全体で調整の必要があるネットワークオペレーションであるため、Connection Functions では適切な async/await の使用が重要です。ランタイムは promise の解決を自動的に処理し、関数が 5 ミリ秒の実行制限内に完了するようにします。

例 : 非同期 の Connection Function と KeyValueStore
import cf from 'cloudfront'; async function connectionHandler(connection) { const kvsHandle = cf.kvs(); // Async operation to check KeyValueStore for certificate revocation const isRevoked = await kvsHandle.exists(connection.clientCertificate.certificates.leaf.serialNumber); if (isRevoked) { // Log the revocation decision with certificate details connection.logCustomData(`REVOKED_CERT:${connection.clientCertificate.certificates.leaf.serialNumber}:${connection.clientCertificate.certificates.leaf.issuer}`); console.log(`Denying connection for revoked certificate: ${connection.clientCertificate.certificates.leaf.serialNumber}`); return connection.deny(); } // Log successful validation for monitoring connection.logCustomData(`VALID_CERT:${connection.clientCertificate.certificates.leaf.serialNumber}`); console.log(`Allowing connection for valid certificate: ${connection.clientCertificate.certificates.leaf.serialNumber}`); return connection.allow(); }

KeyValueStore メソッドや他の非同期オペレーションを呼び出すときは、常に async/await を使用します。Connection Function ランタイムは promise の解決を自動的に処理し、TLS ハンドシェイク処理の厳密なタイミング制約内で適切な実行フローを確保します。async/await により Connection Function 環境でのよりクリーンなエラー処理とパフォーマンスが向上しますので、.then() またはコールバックパターンの使用は避けてください。

非同期の Connection Functions を設計するときは、KeyValueStore オペレーションの数が最小限になるようにコードを構築し、検証ロジックのできるだけ早い段階で実行します。これにより、パフォーマンスが最大になり、トラフィックの多い時間帯にタイムアウトの問題が発生するリスクが軽減されます。関連する検証チェックをバッチ処理し、ユースケースに最も効率的な KeyValueStore メソッド (exists() と get()) を使用することを検討してください。

接続関数のコード例

以下の例は、さまざまな検証シナリオで一般的な Connection Function パターンを示しています。これらの例を、独自の Connection Function 実装の開始点として使用します。

例 : デバイスの証明書の検証

この例では、IoT デバイス、ゲームコンソール、および他のクライアント認証シナリオのデバイスのシリアル番号と証明書のサブジェクトフィールドを検証します。

async function connectionHandler(connection) { // Custom validation: check device serial number format const serialNumber = connection.clientCertificate.certificates.leaf.serialNumber; if (!serialNumber.startsWith("DEV")) { connection.logCustomData(`INVALID_SERIAL:${serialNumber}`); return connection.deny(); } // Validate certificate subject contains required organizational unit const subject = connection.clientCertificate.certificates.leaf.subject; if (!subject.includes("OU=AuthorizedDevices")) { connection.logCustomData(`INVALID_OU:${subject}`); return connection.deny(); } // Allow connection for valid devices connection.logCustomData(`VALID_DEVICE:${serialNumber}`); return connection.allow(); }

この関数は、デバイスのシリアル番号形式や組織単位の検証など、標準証明書の検証を超えて複数の検証チェックを実行します。

例 : 混合認証を使用したオプションの mTLS

この例では、異なる認証ポリシーを使用して mTLS 接続と非 mTLS 接続の両方を処理します。

async function connectionHandler(connection) { if (connection.clientCertificate) { // mTLS connection - enhanced validation for certificate holders const subject = connection.clientCertificate.certificates.leaf.subject; connection.logCustomData(`MTLS_SUCCESS:${subject}:${connection.clientIp}`); console.log(`mTLS connection from: ${subject}`); return connection.allow(); } else { // Non-mTLS connection - apply IP-based restrictions const clientIp = connection.clientIp; // Only allow non-mTLS from specific IP ranges if (clientIp.startsWith("203.0.113.") || clientIp.startsWith("198.51.100.")) { connection.logCustomData(`NON_MTLS_ALLOWED:${clientIp}`); console.log(`Non-mTLS connection allowed from: ${clientIp}`); return connection.allow(); } connection.logCustomData(`NON_MTLS_DENIED:${clientIp}`); return connection.deny(); } }

この関数は、信頼できる IP 範囲のレガシークライアントとの互換性を維持しながら、証明書を持つクライアントのセキュリティを強化します。