

# CloudFront Functions と KeyValueStore を使用して相互 TLS (ビューワー) の証明書失効を実装します
<a name="implement-certificate-revocation"></a>

KeyValueStore で CloudFront Connection Functions を使用して、証明書失効チェックを実装できます。これにより、失効した証明書のシリアル番号のリストを維持し、TLS ハンドシェイク中にクライアント証明書とこのリストを確認できます。

証明書失効を実装するには、次のコンポーネントが必要です。
+ ビューワー mTLS で設定されたディストリビューション
+ 失効した証明書のシリアル番号を含む KeyValueStore
+ KeyValueStore にクエリを実行して証明書のステータスを確認する Connection Function

クライアントが接続されると、CloudFront はトラストストアに対して証明書を検証し、Connection Function を実行します。関数は証明書のシリアル番号と KeyValueStore を確認し、接続を許可または拒否します。

**Topics**
+ [ステップ 1: 失効した証明書の KeyValueStore を作成する](create-kvs-revoked-certificates.md)
+ [ステップ 2: 失効 Connection Function を作成する](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>

mTLS 接続中に Connection Function が確認できる失効した証明書のシリアル番号を保存する KeyValueStore を作成します。

まず、失効した証明書のシリアル番号を 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: 失効 Connection Function を作成する
<a name="create-revocation-connection-function"></a>

証明書のシリアル番号と KeyValueStore を確認し、証明書が失効しているかどうかを決定する Connection Function を作成します。

証明書のシリアル番号と KeyValueStore を確認する Connection Function を作成します。

```
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 コンソールを使用し、サンプル証明書を使用して Connection Function をテストします。コンソールの Connection Function に移動し、[テスト] タブを使用します。

**サンプル証明書を使用してテストする**

1. PEM 形式のサンプル証明書をテストインターフェイスに貼り付ける

1. オプションで、IP ベースのロジックをテストするクライアント IP アドレスを指定します。

1. **[関数をテスト]** を選択して、実行結果を表示します。

1. 実行ログを確認し、関数ロジックを検証する

有効な証明書と失効した証明書の両方を使用してテストし、関数が両方のシナリオを正しく処理することを確認します。実行ログには、console.log 出力と、関数の実行中に発生したエラーが表示されます。

# ステップ 4: 関数をディストリビューションに関連付ける
<a name="associate-function-distribution"></a>

Connection Function を発行したら、mTLS が有効なディストリビューションに関連付けて、証明書失効チェックを有効にします。

関数は、ディストリビューション設定ページ、または Connection Function の関連付けられたディストリビューションテーブルから関連付けることができます。ディストリビューション設定に移動し、**[ビューワーの相互認証 (mTLS)]** セクションまでスクロールし、Connection Function を選択して変更を保存します。

# 高度な失効シナリオ
<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
```

ステップ 1 の説明に従って、フォーマットされたファイルを S3 にアップロードし、KeyValueStore を作成します。

## 複数の認証局を処理する
<a name="handle-multiple-cas"></a>

TrustStore に複数の認証局 (CA) が含まれている場合は、同じシリアル番号を持つ異なる CA からの証明書間の競合を避けるために、KeyValueStore キーに発行者情報を含めます。

マルチ 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();
    }
}
```

**注記**  
発行者識別子とシリアル番号を使用すると、キーが長くなるため、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();
}
```

カスタムデータは、有効な UTF-8 テキスト 800 バイトに制限されています。この制限を超えると、CloudFront はデータを最も近い有効な UTF-8 境界に切り捨てます。

**注記**  
カスタムデータログ記録は、ディストリビューションで接続ログが有効になっている場合にのみ機能します。接続ログが設定されていない場合、logCustomData メソッドは no-op です。

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

認証局は 2 種類の CRL を発行できます。
+ **完全な CRL**: 失効したすべての証明書の完全なリストを含みます
+ **デルタ CRL**: 前回の完全な CRL 以降に失効した証明書のみを一覧表示します

完全な CRL を更新するには、更新されたデータを使用して新しい KeyValueStore を作成し、Connection Function の関連付けを新しい 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 万個のキーと値のペアをサポートします。キー形式とデータサイズに基づいて、失効リストの容量を計画します。
+ **シリアル番号のみ**: シンプルな失効チェックのための効率的なストレージ
+ **発行者識別子とシリアル番号**: マルチ CA 環境のための長いキー

大規模な失効リストの場合は、異なる証明書カテゴリまたは期間に対して別々の KeyValueStores を維持する階層型アプローチの実装を検討してください。