

# Implementación de la revocación de certificados para TLS mutua (espectador) con CloudFront Functions y KeyValueStore
<a name="implement-certificate-revocation"></a>

Puede utilizar funciones de conexión de CloudFront con KeyValueStore para implementar la comprobación de revocación de certificados. Esto permite mantener una lista de números de serie de los certificados revocados y comparar los certificados de los clientes con esta lista durante el establecimiento de comunicación de TLS.

Para implementar la revocación de certificados, necesita estos componentes:
+ Una distribución configurada con un mTLS de espectador
+ Un KeyValueStore que contenga números de serie de certificados revocados
+ Una función de conexión que consulta el KeyValueStore para comprobar el estado del certificado

Cuando un cliente se conecta, CloudFront valida el certificado con el almacén de confianza y, a continuación, ejecuta la función de conexión. La función compara el número de serie del certificado con el KeyValueStore y permite o deniega la conexión.

**Topics**
+ [Paso 1: crear un KeyValueStore para los certificados revocados](create-kvs-revoked-certificates.md)
+ [Paso 2: crear la función de conexión de revocación](create-revocation-connection-function.md)
+ [Paso 3: probar la función de revocación](test-revocation-function.md)
+ [Paso 4: asocie la función a la distribución](associate-function-distribution.md)
+ [Escenarios de revocación avanzada](advanced-revocation-scenarios.md)

# Paso 1: crear un KeyValueStore para los certificados revocados
<a name="create-kvs-revoked-certificates"></a>

Cree un KeyValueStore para almacenar los números de serie de los certificados revocados que la función de conexión pueda comprobar durante las conexiones de mTLS.

En primer lugar, prepare los números de serie de los certificados revocados en formato JSON:

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

Cargue este archivo JSON en un bucket de S3 y, a continuación, cree el 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"
  }'
```

Espere a que el KeyValueStore termine de aprovisionarse. Compruebe el estado con:

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

# Paso 2: crear la función de conexión de revocación
<a name="create-revocation-connection-function"></a>

Cree una función de conexión que compruebe los números de serie de los certificados con los de KeyValueStore para determinar si los certificados se revocan.

Cree una función de conexión que compruebe los números de serie de los certificados con el 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
```

El archivo de configuración especifica la asociación de 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"
      }
    ]
  }
}
```

El código de la función de conexión comprueba KeyValueStore por si hay certificados revocados:

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

# Paso 3: probar la función de revocación
<a name="test-revocation-function"></a>

Utilice la consola de CloudFront para probar la función de conexión con certificados de ejemplo. Navegue hasta la función de conexión en la consola y utilice la pestaña Probar.

**Prueba con certificados de ejemplo**

1. Pegue un certificado de ejemplo en formato PEM en la interfaz de prueba.

1. Si lo desea, especifique una dirección IP de cliente para probar la lógica basada en IP.

1. Elija **Función de prueba** para consultar los resultados de ejecución.

1. Revise los registros de ejecución para verificar la lógica de la función.

Realice pruebas con certificados válidos y revocados para asegurarse de que la función gestiona ambos escenarios correctamente. Los registros de ejecución muestran el resultado de console.log y cualquier error que se produzca durante la ejecución de la función.

# Paso 4: asocie la función a la distribución
<a name="associate-function-distribution"></a>

Una vez que publique la función de conexión, asóciela a la distribución compatible con mTLS para activar la comprobación de revocación de certificados.

Puede asociar la función desde la página de configuración de distribución o desde la tabla de distribuciones asociadas a la función de conexión. Vaya a la configuración de distribución, vaya a la sección **Autenticación mutua del espectador (mTLS)**, seleccione la función de conexión y guarde los cambios.

# Escenarios de revocación avanzada
<a name="advanced-revocation-scenarios"></a>

Para requisitos de revocación de certificados más complejos, considere estas configuraciones adicionales:

**Topics**
+ [Convierta las listas de revocación de certificados (CRL) al formato KeyValueStore.](#convert-crl-kvs-format)
+ [Gestión de varias autoridades de certificación](#handle-multiple-cas)
+ [Agregación de datos personalizados a los registros de conexión](#add-custom-data-logs)
+ [Actualizaciones de CRL administradas](#manage-crl-updates)
+ [Planificación de la capacidad de KeyValueStore](#plan-kvs-capacity)

## Convierta las listas de revocación de certificados (CRL) al formato KeyValueStore.
<a name="convert-crl-kvs-format"></a>

Si tiene un archivo de lista de revocación de certificados (CRL), puede convertirlo al formato JSON de KeyValueStore mediante OpenSSL y jq:

**Convierta el CRL al formato KeyValueStore**

Extraiga los números de serie del archivo CRL:

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

Convierta los números de serie al formato JSON de KeyValueStore:

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

Cargue el archivo formateado en S3 y cree el KeyValueStore tal y como se describe en el paso 1.

## Gestión de varias autoridades de certificación
<a name="handle-multiple-cas"></a>

Si su TrustStore contiene varias autoridades de certificación (CA), incluya la información del emisor en las claves de KeyValueStore para evitar conflictos entre certificados de distintas autoridades de certificación que puedan tener el mismo número de serie.

En escenarios con varias autoridades de certificación, utilice como clave una combinación del hash SHA1 del emisor y el número de serie:

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

**nota**  
Al utilizar el identificador del emisor y el número de serie, se crean claves más largas, lo que puede reducir el número total de entradas que puede almacenar en KeyValueStore.

## Agregación de datos personalizados a los registros de conexión
<a name="add-custom-data-logs"></a>

Las funciones de conexión pueden agregar datos personalizados a los registros de conexión de CloudFront mediante el método logCustomData. Esto permite incluir los resultados de las comprobaciones de revocación, la información sobre los certificados u otros datos relevantes en los registros.

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

Los datos personalizados están limitados a 800 bytes de texto UTF-8 válido. Si supera este límite, CloudFront trunca los datos hasta el límite UTF-8 válido más cercano.

**nota**  
El registro de datos personalizado solo funciona cuando los registros de conexión están habilitados para la distribución. Si los registros de conexión no están configurados, el método logCustomData no es operativo.

## Actualizaciones de CRL administradas
<a name="manage-crl-updates"></a>

Las autoridades de certificación pueden emitir dos tipos de CRL:
+ **CRL completas**: contienen una lista completa de todos los certificados revocados
+ **CRL de Delta**: solo se muestran los certificados revocados desde la última CRL completa

Para obtener actualizaciones completas de la CRL, cree un KeyValueStore nuevo con los datos actualizados y redirija la asociación de la función de conexión al nuevo KeyValueStore. Este enfoque es más sencillo que calcular las diferencias y realizar actualizaciones incrementales.

Para las actualizaciones de CRL delta, utilice el comando update-keys para agregar nuevos certificados revocados al KeyValueStore existente:

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

## Planificación de la capacidad de KeyValueStore
<a name="plan-kvs-capacity"></a>

KeyValueStore tiene un límite de tamaño total de 5 MB y admite hasta 10 millones de pares clave-valor. Planifique la capacidad de la lista de revocación en función del formato de la clave y del tamaño de los datos:
+ **Solo número de serie**: almacenamiento eficiente para una comprobación sencilla de las revocaciones
+ **Identificador del emisor \$1 número de serie**: claves más largas para entornos con varias autoridades de certificación

En el caso de listas de revocación de gran tamaño, considere la posibilidad de implementar un enfoque escalonado en el que mantenga almacenes KeyValueStores independientes para diferentes categorías de certificados o periodos de tiempo.