寫入 CloudFront 連線函數程式碼以進行交互 TLS (檢視器) 驗證 - Amazon CloudFront

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

寫入 CloudFront 連線函數程式碼以進行交互 TLS (檢視器) 驗證

CloudFront Connection Functions 可讓您撰寫輕量型 JavaScript 函數,以進行 mTLS 憑證驗證和自訂身分驗證邏輯。您的 Connection Function 程式碼可以驗證用戶端憑證、實作裝置特定的身分驗證規則、處理憑證撤銷案例,以及針對全球 CloudFront 節點的 TLS 連線做出允許/拒絕決策。

連線函數提供一種強大的方法,使用您自己的商業邏輯來擴展 CloudFront 的內建憑證驗證。與處理 HTTP 資料的檢視器請求和檢視器回應函數不同,Connection Functions 會在 TLS 層運作,並可存取憑證資訊、用戶端 IP 地址和 TLS 連線詳細資訊。這使得它們非常適合用於實作零信任安全模型、裝置身分驗證系統和超出標準 PKI 驗證的自訂憑證驗證政策。

您的 Connection Function 程式碼會在安全、隔離且啟動時間低於毫秒的環境中執行,並且可以擴展以處理每秒數百萬個連線。執行時間已針對憑證驗證工作負載進行最佳化,並提供與 CloudFront KeyValueStore 的內建整合,以進行即時資料查詢操作,實現複雜的身分驗證案例,例如憑證撤銷清單檢查和裝置允許清單驗證。

為了協助您撰寫有效的連線函數程式碼,請參閱下列主題。如需完整的程式碼範例和step-by-step教學課程,請參閱本指南中的教學課程章節,並探索 CloudFront 主控台中提供的連線函數範例。

CloudFront Connection Function 使用案例和用途

撰寫 CloudFront Connection Function 之前,請仔細判斷您需要實作的憑證驗證或身分驗證邏輯類型。連線函數是專為需要超出標準 PKI 憑證檢查自訂驗證的特定使用案例而設計。了解您的使用案例可協助您設計符合您安全需求的高效程式碼,同時維持最佳效能。

常見的連線函數使用案例包括:

  • 憑證撤銷處理 – 實作自訂政策來處理撤銷的憑證,包括憑證輪換的寬限期、內部裝置的信任網路例外狀況,或撤銷的憑證可能需要暫時存取的緊急存取案例。

  • 選用的 mTLS 支援 – 使用不同的身分驗證政策處理 mTLS 和非 mTLS 連線,可讓您為支援憑證的用戶端提供增強的安全性,同時保持與舊版用戶端的相容性。

  • 以 IP 為基礎的身分驗證 – 結合憑證驗證與用戶端 IP 地址檢查,以提高安全性,例如限制來自特定地理區域、公司網路或已知惡意 IP 範圍的存取。

  • 多租戶憑證驗證 – 實作租戶特定的驗證規則,其中根據用戶端憑證發行者或主體屬性,套用不同的憑證授權單位或驗證條件。

  • 以時間為基礎的存取控制 – 強制執行以時間為基礎的限制,其中憑證僅在特定時段、維護時段或商業期間內有效,即使憑證本身尚未過期。

在 CloudFront 執行標準憑證驗證 (信任鏈驗證、過期檢查和簽章驗證) 之後,但在建立 TLS 連線之前執行連線函數。此時間可讓您靈活地新增自訂驗證條件,同時受益於 CloudFront 的內建憑證驗證。您的函數會收到標準驗證的結果,並可以根據標準和自訂條件,做出是否允許或拒絕連線的明智決策。

設計連線函數時,請考慮驗證邏輯的效能影響。函數具有 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(); } }

與檢視器請求和檢視器回應函數不同,連線函數無法修改 HTTP 請求或回應。他們只能允許或拒絕 TLS 連線。

CloudFront Connection Functions JavaScript 執行期功能

CloudFront Connection Functions 使用 CloudFront Functions JavaScript 執行期 2.0,可提供專為憑證驗證工作負載最佳化的安全且高效能環境。執行時間的設計是為了在幾毫秒內開始,並處理 CloudFront 全球邊緣網路中數百萬個並行執行。

執行期環境包含完整的 JavaScript 語言支援:

  • ECMAScript 2020 (ES11) 支援 – 現代 JavaScript 功能,包括用於處理大型憑證序號的選用鏈結 (?.)、 nullish coalescing (??) 和 BigInt

  • 內建物件 – 物件、陣列、JSON、數學和日期等標準 JavaScript 物件

  • 主控台記錄 – 使用 console.log() 進行偵錯和監控憑證驗證決策。日誌可在測試期間即時提供,有助於疑難排解開發中的驗證邏輯

  • KeyValueStore 整合 – 原生存取 CloudFront KeyValueStore 以進行超快速的資料查詢操作,啟用即時憑證撤銷檢查、裝置允許清單驗證和租戶特定組態擷取

連線函數已針對憑證驗證案例的高效能進行最佳化。執行時間會自動處理記憶體管理、垃圾收集和資源清理,以確保數百萬個並行連線的效能一致。所有操作的設計都具有決定性和快速性,KeyValueStore 查詢通常在微秒內完成。

執行時間環境在函數執行之間完全隔離,確保不同用戶端連線之間的資料不會洩漏。每個函數執行一開始都是清除狀態,而且無法存取先前的執行結果或來自其他連線的用戶端資料。

CloudFront Connection Function 協助程式方法和 APIs

CloudFront Connection Functions 提供專門的協助程式方法,旨在簡化憑證驗證決策並增強可觀測性。這些方法針對連線驗證工作流程進行最佳化,並與 CloudFront 的連線記錄和監控系統無縫整合。

  • connection.allow() – 允許 TLS 連線繼續。此方法會通知 CloudFront 完成 TLS 交握,並允許用戶端建立連線。當憑證驗證通過且滿足任何自訂身分驗證邏輯時,請使用此選項

  • 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 對 Connection Functions 特別強大,因為它可在所有 CloudFront 節點提供全域、最終一致的資料存取,以及微秒的查詢時間。這使得它非常適合用於維護 TLS 交握期間需要存取的憑證撤銷清單、裝置允許清單、租戶組態和其他驗證資料。

KeyValueStore 整合專為高效能連線驗證工作流程而設計:

  • kvsHandle.exists(key) – 檢查 KeyValueStore 中是否存在金鑰,而不擷取值。這是二進位驗證案例最有效的方法,例如憑證撤銷檢查,您只需知道憑證序號是否在撤銷清單中

  • kvsHandle.get(key) – 針對更複雜的驗證案例,從 KeyValueStore 擷取值。當您需要存取與憑證或裝置識別符相關聯的組態資料、驗證規則或中繼資料時,請使用此選項

KeyValueStore 操作是非同步的,必須搭配非同步/等待語法使用。KeyValueStore 的總大小限制為 10MB,並支援最多 1,000 萬個鍵值對。KeyValueStore 資料最終在所有節點保持一致,更新通常會在幾秒鐘內傳播。

為了獲得最佳效能,請建構您的 KeyValueStore 金鑰,將查詢操作降至最低。使用憑證序號做為簡易撤銷檢查的金鑰,或建立合併多 CA 環境發行者雜湊和序號的複合金鑰。設計資料結構時,請考慮金鑰複雜性與 KeyValueStore 容量之間的權衡。

使用非同步並等待

連線函數支援使用非同步/等待語法的非同步操作,這對於使用 KeyValueStore 操作或其他非同步任務至關重要。非同步/等待模式可確保函數在做出連線決策之前等待 KeyValueStore 查詢完成,同時維持 TLS 交握處理所需的高效能特性。

適當的非同步/等待用量對於連線函數至關重要,因為 KeyValueStore 操作雖然速度非常快,但仍是需要跨 CloudFront 分散式基礎設施協調的網路操作。執行時間會自動處理承諾解析度,並確保您的函數在 5 毫秒的執行限制內完成。

範例 :使用 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 方法或其他非同步操作時,一律使用非同步/等待。Connection Function 執行時間會自動處理 promise 解析,並確保在 TLS 交握處理的嚴格時間限制內執行流程正確。避免使用 .then() 或回呼模式,因為非同步/等待可在連線函數環境中提供更明確的錯誤處理和更好的效能。

設計非同步連線函數時,請建構程式碼以盡可能減少 KeyValueStore 操作的數量,並儘早在驗證邏輯中執行這些操作。這可確保最大效能,並降低高流量期間逾時問題的風險。請考慮批次處理相關的驗證檢查,並針對您的使用案例使用最有效率的 KeyValueStore 方法 (exists() vs get())。

連線函數程式碼範例

下列範例示範適用於不同驗證案例的常見連線函數模式。使用這些範例做為您自己的連線函數實作的起點。

範例 :裝置憑證驗證

此範例會驗證 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 範圍內舊版用戶端的相容性。