Compartir a través de


Use el cifrado del lado cliente con Always Encrypted para Azure Cosmos DB

SE APLICA A: NoSQL

Importante

Se ha introducido un cambio importante con la versión 1.0 de nuestros paquetes de cifrado. Si creó claves de cifrado de datos y contenedores habilitados para cifrado con versiones anteriores, deberá volver a crear las bases de datos y los contenedores después de migrar el código de cliente a los paquetes 1.0.

Always Encrypted es una característica diseñada para proteger la información confidencial, como números de tarjeta de crédito o números de identificación nacional o regional (por ejemplo, los números del seguro social de EE. UU.), almacenada en Azure Cosmos DB. Always Encrypted permite a los clientes cifrar información confidencial en aplicaciones cliente y nunca revela las claves de cifrado a la base de datos.

Always Encrypted ofrece las funcionalidades de cifrado del lado cliente a Azure Cosmos DB. Es posible que sea necesario cifrar los datos del lado del cliente en los siguientes escenarios:

  • Protección de datos confidenciales que tienen características de confidencialidad específicas: Always Encrypted permite a los clientes cifrar datos confidenciales dentro de sus aplicaciones y nunca revelar los datos de texto sin formato o las claves de cifrado al servicio Azure Cosmos DB.
  • Implementar el control de acceso por propiedad: dado que el cifrado se controla con claves que posee y administra el usuario desde Azure Key Vault, este puede aplicar directivas de acceso para controlar a qué propiedades confidenciales tienen acceso los clientes.

Conceptos

Always Encrypted para Azure Cosmos DB presenta nuevos conceptos que intervienen en la configuración del cifrado del lado cliente.

Claves de cifrado

Claves de cifrado de datos

Con Always Encrypted, los datos se cifran con claves de cifrado de datos (DEK) que deben crearse con antelación. Estas claves de cifrado de datos se almacenan en el servicio Azure Cosmos DB y se definen en el nivel de base de datos, por lo que se pueden compartir entre varios contenedores. La creación de las claves de cifrado de datos se realiza en el lado cliente mediante el SDK de Azure Cosmos DB.

Puede hacer lo siguiente:

  • Cree una clave de cifrado de datos por propiedad para cifrar, o
  • utilice la misma clave para cifrar múltiples propiedades.

Claves administradas por el cliente

Antes de que se almacenen en Azure Cosmos DB, las claves de cifrado de datos se encapsulan mediante una clave administrada por el cliente (CMK). Al controlar el encapsulado y desencapsulado de las claves de cifrado de datos, las claves administradas por el cliente controlan eficazmente el acceso a los datos cifrados con sus claves de cifrado de datos correspondientes. El almacenamiento de las claves administradas por el cliente está diseñado como extensible, con una implementación predeterminada que espera que se almacenen en Azure Key Vault.

Claves de cifrado

Directiva de cifrado

Similar a una directiva de indexación, una directiva de cifrado es una especificación de nivel de contenedor que describe cómo deben cifrarse las propiedades JSON. Esta directiva, que es inmutable, debe proporcionarse cuando se crea el contenedor. En la versión actual, no se puede actualizar la directiva de cifrado.

Para cada propiedad que quiera cifrar, la directiva de cifrado define lo siguiente:

  • La ruta de acceso de la propiedad en forma de /property. Actualmente solo se admiten rutas de acceso de nivel superior; no se admiten rutas de acceso anidadas como /path/to/property.
  • El identificador de la clave de cifrado de datos que se usará al cifrar y descifrar la propiedad.
  • Un tipo de cifrado. Puede ser aleatorio o determinista.
  • El algoritmo de cifrado que se usará al cifrar la propiedad. El algoritmo especificado puede invalidar el algoritmo definido al crear la clave si son compatibles.

Cifrado aleatorio frente a cifrado determinista

El servicio de Azure Cosmos DB nunca ve el texto sin formato de las propiedades cifradas con Always Encrypted. Sin embargo, sigue siendo compatible con algunas funcionalidades de consulta sobre los datos cifrados, en función del tipo de cifrado que se utiliza para una propiedad. Always Encrypted es compatible con los dos tipos de cifrado siguientes:

  • El cifrado determinista genera siempre el mismo valor cifrado para cualquier valor de texto sin formato determinado y configuración de cifrado. El uso del cifrado determinista permite que las consultas realicen filtros de igualdad en propiedades cifradas. Sin embargo, puede permitir a los atacantes averiguar información sobre los valores cifrados mediante el análisis de patrones en la propiedad cifrada. Esto sucede especialmente cuando hay un conjunto pequeño de posibles valores cifrados, como verdadero o falso, o región norte, sur, este u oeste.

  • Cifrado aleatorio: usa un método que cifra los datos de una manera menos predecible. El cifrado aleatorio es más seguro, pero evita que las consultas se filtren por propiedades cifradas.

Consulte Generación del vector de inicialización (IV) para obtener más información sobre el cifrado determinista y aleatorio en Always Encrypted.

Configuración de Azure Key Vault

Para empezar a trabajar con Always Encrypted, lo primero que debe hacer es crear sus CMK en Azure Key Vault:

  1. Cree una instancia nueva de Azure Key Vault o busque una que ya exista.
  2. Cree una clave nueva en la sección Claves.
  3. Una vez creada la clave, busque la versión actual y copie el identificador de clave completo:
    https://<my-key-vault>.vault.azure.net/keys/<key>/<version>. Si omite la versión de la clave al final del identificador, se utiliza la versión más reciente de la clave.

A continuación, debe configurar el acceso del SDK de Azure Cosmos DB a su instancia de Azure Key Vault. Esta autenticación se realiza a través de una identidad de Microsoft Entra. Aunque se podría usar cualquier tipo de identidad, lo más probable es que utilice la identidad de una aplicación de Microsoft Entra o una identidad administrada como proxy entre el código de cliente y su instancia de Azure Key Vault. Siga estos pasos para usar la identidad de Microsoft Entra como proxy:

  1. Vuelva a su instancia de Azure Key Vault, vaya a la sección Directivas de acceso y agregue una nueva directiva:

    1. En Permisos de clave, seleccione Obtener, Enumerar, Desencapsular clave, Encapsular clave, Comprobar y Firmar.
    2. En Seleccionar entidad de seguridad, busque la identidad de Microsoft Entra.

Protección de la CMK frente a eliminaciones accidentales

Para asegurarse de que no pierde acceso a los datos cifrados después de una eliminación accidental de la CMK, se recomienda establecer dos propiedades en la instancia de Azure Key Vault: Eliminación temporal y Protección de purgas.

Si crea una nueva instancia de Azure Key Vault, habilite estas propiedades durante la creación:

Captura de pantalla de las propiedades de eliminación temporal y protección contra purga para una nueva instancia de Azure Key Vault.

Si usa una instancia de Azure Key Vault existente y desea verificar si estas propiedades estén habilitadas, puede consultar la sección Propiedades en Azure Portal. Si alguna de estas propiedades no está habilitada, consulte las secciones "Habilitar la eliminación temporal" y "Habilitación de la protección de purgas" en cualquiera de los siguientes artículos:

Inicializar el SDK

Nota

Always Encrypted para Azure Cosmos DB es actualmente compatible con

Para utilizar Always Encrypted, debe adjuntar una instancia de KeyResolver a su instancia de SDK de Azure Cosmos DB. Esta clase, definida en el espacio de nombres Azure.Security.KeyVault.Keys.Cryptography, se usa para interactuar con el almacén de claves que hospeda sus CMK.

Los siguientes fragmentos de código usan la clase DefaultAzureCredential para recuperar la identidad de Microsoft Entra que se usará al acceder a la instancia de Azure Key Vault. Puede encontrar ejemplos de creación de diferentes tipos de clases TokenCredentialaquí.

Nota

Necesitará el paquete Azure.Identity adicional para acceder a las clases TokenCredential.

var tokenCredential = new DefaultAzureCredential();
var keyResolver = new KeyResolver(tokenCredential);
var client = new CosmosClient("<connection-string>")
    .WithEncryption(keyResolver, KeyEncryptionKeyResolverName.AzureKeyVault);

Cree una clave de cifrado de datos

Para poder cifrar los datos en un contenedor, debe crearse una clave de cifrado de datos en la base de datos primaria.

La creación de una nueva clave de cifrado de datos se realiza llamando al método CreateClientEncryptionKeyAsync y pasando lo siguiente:

  • un identificador de cadena que identificará de forma única la clave en la base de datos y
  • el algoritmo de cifrado previsto para utilizar con la clave. Actualmente, solo se admite un algoritmo.
  • El identificador de clave de la CMK almacenada en Azure Key Vault. Este parámetro se pasa en un objeto EncryptionKeyWrapMetadata genérico donde:
    • type define el tipo de resolución de clave (por ejemplo, Azure Key Vault).
    • name puede ser cualquier nombre descriptivo que desee.
    • value debe ser el identificador de clave.

    Importante

    Una vez creada la clave, busque la versión actual y copie su identificador de clave completo: https://<my-key-vault>.vault.azure.net/keys/<key>/<version>. Si omite la versión de la clave al final del identificador, se utiliza la versión más reciente de la clave.

    • algorithm define qué algoritmo se usará para encapsular la clave de cifrado de claves con la clave administrada por el cliente.
var database = client.GetDatabase("my-database");
await database.CreateClientEncryptionKeyAsync(
    "my-key",
    DataEncryptionAlgorithm.AeadAes256CbcHmacSha256,
    new EncryptionKeyWrapMetadata(
        KeyEncryptionKeyResolverName.AzureKeyVault,
        "akvKey",
        "https://<my-key-vault>.vault.azure.net/keys/<key>/<version>",
        EncryptionAlgorithm.RsaOaep.ToString()));

Creación de un contenedor con directiva de cifrado

Especifique la directiva de cifrado de nivel de contenedor al crear el contenedor.

var path1 = new ClientEncryptionIncludedPath
{
    Path = "/property1",
    ClientEncryptionKeyId = "my-key",
    EncryptionType = EncryptionType.Deterministic.ToString(),
    EncryptionAlgorithm = DataEncryptionAlgorithm.AeadAes256CbcHmacSha256
};
var path2 = new ClientEncryptionIncludedPath
{
    Path = "/property2",
    ClientEncryptionKeyId = "my-key",
    EncryptionType = EncryptionType.Randomized.ToString(),
    EncryptionAlgorithm = DataEncryptionAlgorithm.AeadAes256CbcHmacSha256
};
await database.DefineContainer("my-container", "/partition-key")
    .WithClientEncryptionPolicy()
    .WithIncludedPath(path1)
    .WithIncludedPath(path2)
    .Attach()
    .CreateAsync();

Lectura y escritura de datos cifrados

¿Cómo se cifran los datos?

Cada vez que se escribe un documento en Azure Cosmos DB, el SDK busca la directiva de cifrado para averiguar qué propiedades se deben cifrar y de qué manera. El resultado del cifrado es una cadena de base 64.

Cifrado de tipos complejos:

  • Si la propiedad que se va a cifrar es una matriz JSON, se cifran todas las entradas de la matriz.

  • Si la propiedad que se va a cifrar es un objeto JSON, solo se cifran los valores hoja del objeto. Los nombres de subpropiedades intermedias se quedan como texto sin formato.

Lectura de elementos cifrados

No se requiere ninguna acción explícita para descifrar las propiedades cifradas al emitir lecturas puntuales (captura de un solo elemento a través de su identificador y clave de partición), consultas o al leer la fuente de cambios. El motivo es el siguiente:

  • El SDK busca la directiva de cifrado para averiguar qué propiedades deben descifrarse.
  • El resultado del cifrado inserta el tipo JSON original del valor.

Tenga en cuenta que la resolución de las propiedades cifradas y su posterior descifrado se basan solo en los resultados devueltos por las solicitudes. Por ejemplo, si property1 está cifrado pero se proyecta en property2 (SELECT property1 AS property2 FROM c), no se identificará como una propiedad cifrada cuando lo reciba el SDK.

Consultas de filtro por propiedades cifradas

Al escribir consultas que filtran por propiedades cifradas, debe utilizarse un método específico para pasar el valor del parámetro de consulta. Este método toma los argumentos siguientes:

  • Nombre del parámetro de consulta.
  • Valor que se usará en la consulta.
  • Ruta de acceso de la propiedad cifrada (como se define en la directiva de cifrado).

Importante

Las propiedades cifradas solo se pueden usar en filtros de igualdad (WHERE c.property = @Value). Cualquier otro uso devolverá resultados de consulta impredecibles e incorrectos. Esta restricción se aplicará mejor en las próximas versiones del SDK.

var queryDefinition = container.CreateQueryDefinition(
    "SELECT * FROM c where c.property1 = @Property1");
await queryDefinition.AddParameterAsync(
    "@Property1",
    1234,
    "/property1");

Lectura de documentos cuando solo se puede descifrar un subconjunto de propiedades

En situaciones en las que el cliente no tiene acceso a todas las CMK utilizadas para cifrar las propiedades, solo se puede descifrar un subconjunto de propiedades cuando se leen los datos. Por ejemplo, si property1 se cifra con key1 y property2 se cifra con key2, una aplicación cliente que solo tiene acceso a key1 puede seguir leyendo datos, pero property2 no. En este caso, el usuario debe leer sus datos a través de consultas SQL y proyectar las propiedades que el cliente no puede descifrar: SELECT c.property1, c.property3 FROM c.

Rotación de CMK

Es posible que quiera "girar" la CMK (es decir, usar una CMK nueva en lugar de la actual) si sospecha que la CMK actual se ha visto comprometida. Girar la CMK con regularidad es una práctica de seguridad común. Para realizar esta rotación, solo tiene que proporcionar el identificador de clave de la nueva CMK que se debe usar para encapsular una DEK específica. Tenga en cuenta que esta operación no afecta al cifrado de los datos, sino a la protección de la DEK. El acceso a la CMK anterior no debe revocarse hasta que se complete la rotación.

await database.RewrapClientEncryptionKeyAsync(
    "my-key",
    new EncryptionKeyWrapMetadata(
        KeyEncryptionKeyResolverName.AzureKeyVault,
        "akvKey",
        "https://<my-key-vault>.vault.azure.net/keys/<new-key>/<version>",
        EncryptionAlgorithm.RsaOaep.ToString()));

Rotación de DEK

La realización de una rotación de una clave de cifrado de datos no se ofrece como funcionalidad inmediata. Esto se debe a que la actualización de una clave de cifrado requiere un examen de todos los contenedores en los que se usa esta clave y un nuevo cifrado de todas las propiedades cifradas con esta clave. Esta operación solo puede realizarse en el lado cliente, ya que el servicio Azure Cosmos DB no almacena ni accede nunca al valor de texto sin formato de la clave de cifrado.

En la práctica, se puede llevar a cabo una rotación de DEK realizando una migración de datos desde los contenedores afectados a otros nuevos. Los nuevos contenedores se pueden crear exactamente de la misma forma que los originales. Para ayudarle con esta migración de datos, puede encontrar una herramienta de migración independiente en GitHub.

Incorporación de propiedades cifradas adicionales

No se admite la incorporación de propiedades cifradas adicionales a una directiva de cifrado existente por los mismos motivos explicados en la sección anterior. Esta operación requiere un examen completo del contenedor para asegurarse de que todas las instancias de las propiedades están correctamente cifradas, y se trata de una operación que solo puede producirse en el lado cliente. Al igual que una rotación de DEK, la incorporación de propiedades cifradas adicionales se puede llevar a cabo realizando una migración de datos a un nuevo contenedor con una directiva de cifrado adecuada.

Si tiene flexibilidad en la medida en que se pueden agregar nuevas propiedades cifradas desde el punto de vista de un esquema, también puede aprovechar la naturaleza independiente del esquema de Azure Cosmos DB. Si usa una propiedad definida en la directiva de cifrado como "contenedor de propiedades", puede agregar más propiedades a continuación sin ninguna restricción. Por ejemplo, imaginemos que property1se define en la directiva de cifrado y que escribe inicialmente property1.property2 en los documentos. Si, en una fase posterior, tiene que agregar property3 como propiedad cifrada, puede empezar a escribir property1.property3 en los documentos y la nueva propiedad también se cifrará automáticamente. Este enfoque no requiere ninguna migración de datos.

Pasos siguientes