

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

# 使用 CloudFront Functions 和 KeyValueStore 實作交互 TLS （檢視器） 的憑證撤銷
<a name="implement-certificate-revocation"></a>

您可以使用 CloudFront Connection Functions 搭配 KeyValueStore 來實作憑證撤銷檢查。這可讓您維護撤銷的憑證序號清單，並在 TLS 交握期間針對此清單檢查用戶端憑證。

若要實作憑證撤銷，您需要這些元件：
+ 使用檢視器 mTLS 設定的分佈
+ 包含已撤銷憑證序號的 KeyValueStore 
+ 查詢 KeyValueStore 以檢查憑證狀態的連線函數

當用戶端連線時，CloudFront 會根據信任存放區驗證憑證，然後執行連線函數。您的函數會根據 KeyValueStore 檢查憑證序號，並允許或拒絕連線。

**Topics**
+ [步驟 1：為已撤銷的憑證建立 KeyValueStore](create-kvs-revoked-certificates.md)
+ [步驟 2：建立撤銷連線函數](create-revocation-connection-function.md)
+ [步驟 3：測試您的撤銷函數](test-revocation-function.md)
+ [步驟 4：將函數與分佈建立關聯](associate-function-distribution.md)
+ [進階撤銷案例](advanced-revocation-scenarios.md)

# 步驟 1：為已撤銷的憑證建立 KeyValueStore
<a name="create-kvs-revoked-certificates"></a>

建立 KeyValueStore，以存放連線函數在 mTLS 連線期間可以檢查的撤銷憑證序號。

首先，以 JSON 格式準備您撤銷的憑證序號：

```
{
  "data": [
    {
      "key": "ABC123DEF456",
      "value": ""
    },
    {
      "key": "789XYZ012GHI", 
      "value": ""
    }
  ]
}
```

將此 JSON 檔案上傳至 S3 儲存貯體，然後建立 KeyValueStore：

```
aws s3 cp revoked-serials.json s3://your-bucket-name/revoked-serials.json
aws cloudfront create-key-value-store \
  --name revoked-serials-kvs \
  --import-source '{
    "SourceType": "S3",
    "SourceARN": "arn:aws:s3:::your-bucket-name/revoked-serials.json"
  }'
```

等待 KeyValueStore 完成佈建。使用 檢查狀態：

```
aws cloudfront get-key-value-store --name "revoked-serials-kvs"
```

# 步驟 2：建立撤銷連線函數
<a name="create-revocation-connection-function"></a>

建立連線函數，根據 KeyValueStore 檢查憑證序號，以判斷憑證是否遭到撤銷。

建立連線函數，根據 KeyValueStore 檢查憑證序號：

```
aws cloudfront create-connection-function \
  --name "revocation-control" \
  --connection-function-config file://connection-function-config.json \
  --connection-function-code file://connection-function-code.txt
```

組態檔案會指定 KeyValueStore 關聯：

```
{
  "Runtime": "cloudfront-js-2.0",
  "Comment": "A function that implements revocation control via KVS",
  "KeyValueStoreAssociations": {
    "Quantity": 1,
    "Items": [
      {
        "KeyValueStoreArn": "arn:aws:cloudfront::account-id:key-value-store/kvs-id"
      }
    ]
  }
}
```

Connection Function 程式碼會檢查 KeyValueStore 是否有已撤銷的憑證：

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    
    // Get parsed client serial number from client certificate
    const clientSerialNumber = connection.clientCertInfo.serialNumber;
    
    // Check KVS to see if serial number exists as a key
    const serialNumberExistsInKvs = await kvsHandle.exists(clientSerialNumber);
    
    // Deny connection if serial number exists in KVS
    if (serialNumberExistsInKvs) {
        console.log("Connection denied - certificate revoked");
        return connection.deny();
    }
    
    // Allow connections that don't exist in kvs
    console.log("Connection allowed");
    return connection.allow();
}
```

# 步驟 3：測試您的撤銷函數
<a name="test-revocation-function"></a>

使用 CloudFront 主控台以範例憑證測試連線函數。導覽至 主控台中的連線函數，並使用測試索引標籤。

**使用範例憑證進行測試**

1. 將 PEM 格式的範例憑證貼入測試界面

1. 選擇性地指定用戶端 IP 地址以測試 IP 型邏輯

1. 選擇**測試函數**以查看執行結果

1. 檢閱執行日誌以驗證您的函數邏輯

使用有效和已撤銷的憑證進行測試，以確保您的函數正確處理這兩個案例。執行日誌會顯示 console.log 輸出和函數執行期間發生的任何錯誤。

# 步驟 4：將函數與分佈建立關聯
<a name="associate-function-distribution"></a>

發佈連線函數後，請將其與啟用 mTLS 的分佈建立關聯，以啟用憑證撤銷檢查。

您可以從分佈設定頁面或從連線函數的關聯分佈資料表建立函數的關聯。導覽至您的分佈設定，捲動至**檢視器交互驗證 (mTLS)** 區段，選取連線函數，然後儲存變更。

# 進階撤銷案例
<a name="advanced-revocation-scenarios"></a>

如需更複雜的憑證撤銷要求，請考慮下列其他組態：

**Topics**
+ [將憑證撤銷清單 (CRL) 轉換為 KeyValueStore 格式](#convert-crl-kvs-format)
+ [處理多個憑證授權機構](#handle-multiple-cas)
+ [將自訂資料新增至連線日誌](#add-custom-data-logs)
+ [管理 CRL 更新](#manage-crl-updates)
+ [規劃 KeyValueStore 容量](#plan-kvs-capacity)

## 將憑證撤銷清單 (CRL) 轉換為 KeyValueStore 格式
<a name="convert-crl-kvs-format"></a>

如果您有憑證撤銷清單 (CRL) 檔案，您可以使用 OpenSSL 和 jq 將其轉換為 KeyValueStore JSON 格式：

**將 CRL 轉換為 KeyValueStore 格式**

從 CRL 檔案擷取序號：

```
openssl crl -text -noout -in rfc5280_CRL.crl | \
  awk '/Serial Number:/ {print $3}' | \
  cut -d'=' -f2 | \
  sed 's/../&:/g;s/:$//' >> serialnumbers.txt
```

將序號轉換為 KeyValueStore JSON 格式：

```
jq -R -s 'split("\n") | map(select(length > 0)) | {data: map({"key": ., "value": ""})}' \
  serialnumbers.txt >> serialnumbers_kvs.json
```

將格式化檔案上傳至 S3，並建立 KeyValueStore，如步驟 1 所述。

## 處理多個憑證授權機構
<a name="handle-multiple-cas"></a>

當您的 TrustStore 包含多個憑證授權機構 CAs) 時，請在 KeyValueStore 金鑰中包含發行者資訊，以避免來自可能具有相同序號之不同 CAs憑證之間發生衝突。

對於多 CA 案例，請使用發行者的 SHA1 雜湊和序號的組合做為金鑰：

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    const clientCert = connection.clientCertInfo;
    
    // Create composite key with issuer hash and serial number
    const issuer = clientCert.issuer.replace(/[^a-zA-Z0-9]/g, '').substring(0, 20);
    const serialno = clientCert.serialNumber;
    const compositeKey = `${issuer}_${serialno}`;
    
    const cert_revoked = await kvsHandle.exists(compositeKey);
    
    if (cert_revoked) {
        console.log(`Blocking revoked cert: ${serialno} from issuer: ${issuer}`);
        connection.deny();
    } else {
        connection.allow();
    }
}
```

**注意**  
使用發行者識別符 \$1 序號會建立較長的金鑰，這可能會減少您可以存放在 KeyValueStore 中的項目總數。

## 將自訂資料新增至連線日誌
<a name="add-custom-data-logs"></a>

連線函數可以使用 logCustomData 方法將自訂資料新增至 CloudFront 連線日誌。這可讓您在日誌中包含撤銷檢查結果、憑證資訊或其他相關資料。

```
async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    const clientSerialNumber = connection.clientCertInfo.serialNumber;
    const serialNumberExistsInKvs = await kvsHandle.exists(clientSerialNumber);
    
    if (serialNumberExistsInKvs) {
        // Log revocation details to connection logs
        connection.logCustomData(`REVOKED:${clientSerialNumber}:DENIED`);
        console.log("Connection denied - certificate revoked");
        return connection.deny();
    }
    
    // Log successful validation
    connection.logCustomData(`VALID:${clientSerialNumber}:ALLOWED`);
    console.log("Connection allowed");
    return connection.allow();
}
```

自訂資料限制為 800 個位元組的有效 UTF-8 文字。如果您超過此限制，CloudFront 會將資料截斷到最近的有效 UTF-8 邊界。

**注意**  
自訂資料記錄只有在為您的分佈啟用連線日誌時才有效。如果未設定連線日誌，logCustomData 方法是無操作。

## 管理 CRL 更新
<a name="manage-crl-updates"></a>

憑證授權機構可以發出兩種類型的 CRLs：
+ **完整 CRLs**：包含所有已撤銷憑證的完整清單
+ **Delta CRLs**：僅列出自上次完整 CRL 以來撤銷的憑證

如需完整的 CRL 更新，請使用更新的資料建立新的 KeyValueStore，並將連線函數關聯重新導向至新的 KeyValueStore。這種方法比計算差異和執行增量更新更簡單。

對於差異 CRL 更新，請使用 update-keys 命令將新的撤銷憑證新增至現有的 KeyValueStore：

```
aws cloudfront update-key-value-store \
  --name "revoked-serials-kvs" \
  --if-match "current-etag" \
  --put file://delta-revoked-serials.json
```

## 規劃 KeyValueStore 容量
<a name="plan-kvs-capacity"></a>

KeyValueStore 的大小限制為 5 MB，並支援最多 1，000 萬個鍵值對。根據您的金鑰格式和資料大小來規劃撤銷清單容量：
+ **僅限序號**：簡單撤銷檢查的高效儲存
+ **發行者識別符 \$1 序號**：多 CA 環境的較長金鑰

對於大型撤銷清單，請考慮實作分層方法，在其中針對不同的憑證類別或期間維護個別的 KeyValueStores。