Tutorial: Cifrado y descifrado de blobs con Azure Key Vault

En este tutorial aprenderá a usar el cifrado del lado cliente para cifrar y descifrar blobs mediante una clave almacenada con Azure Key Vault.

Azure Blob Storage admite el cifrado del lado servicio y del lado cliente. En la mayoría de los escenarios, Microsoft recomienda usar características de cifrado del servicio para facilitar su uso en la protección de los datos. Para aprender más sobre el cifrado del lado servicio, consulte Cifrado de Azure Storage para datos en reposo.

La biblioteca cliente de Azure Blob Storage para .NET permite el cifrado de los datos del lado cliente en las aplicaciones antes de cargarlos en Azure Storage, y el descifrado de datos mientras estos se descargan al cliente. La biblioteca también admite la integración con Azure Key Vault para la administración de las claves.

En este tutorial se muestra cómo realizar las siguientes acciones:

  • Configuración de permisos para un recurso de Azure Key Vault
  • Creación de una aplicación de consola para interactuar con los recursos mediante bibliotecas cliente de .NET
  • Incorporación de una clave a un almacén de claves
  • Configuración de las opciones de cifrado del lado cliente mediante una clave almacenada en un almacén de claves
  • Creación de un objeto de cliente de Blob service con el cifrado del lado cliente habilitado
  • Carga de un blob cifrado y su posterior descarga y descrifrado

Requisitos previos

Asignación de un rol al usuario de Microsoft Entra

Al desarrollar en el entorno local, asegúrese de que la cuenta de usuario que accede al almacén de claves tenga los permisos correctos. Necesitará el rol Agente criptográfico de Key Vault para crear una clave y realizar acciones en las claves de un almacén de claves. Puede asignar roles RBAC de Azure a un usuario mediante Azure Portal, la CLI de Azure o Azure PowerShell. Puede obtener más información sobre los ámbitos disponibles para las asignaciones de roles en la página de información general del ámbito.

En este escenario, asignará permisos a la cuenta de usuario, cuyo ámbito es el almacén de datos, con el fin de seguir el principio de privilegios mínimos. Esta práctica solo proporciona a los usuarios los permisos mínimos necesarios y crea entornos de producción más seguros.

En el ejemplo siguiente se muestra cómo asignar el rol Agente criptográfico de Key Vault a su cuenta de usuario, que proporciona el acceso que necesitará para completar este tutorial.

Importante

En la mayoría de los casos, la asignación de roles tardará un minuto o dos en propagarse en Azure, pero en casos excepcionales puede tardar hasta ocho minutos. Si recibe errores de autenticación al ejecutar por primera vez el código, espere unos instantes e inténtelo de nuevo.

  1. En Azure Portal, busque el almacén de claves mediante la barra de búsqueda principal o el panel de navegación de la izquierda.

  2. En la página de información general, seleccione Control de acceso (IAM) en el menú de la izquierda.

  3. En la página Control de acceso (IAM), seleccione la pestaña Asignación de roles.

  4. Seleccione + Agregar en el menú superior y, a continuación, Agregar asignación de roles en el menú desplegable resultante.

    A screenshot showing how to assign a role in Azure portal.

  5. Puede usar el cuadro de búsqueda para filtrar los resultados por el rol deseado. En este ejemplo, busque Agente criptográfico de Key Vault, seleccione el resultado coincidente y elija Siguiente.

  6. En la pestaña Asignar acceso a, seleccione Usuario, grupo o entidad de servicio y, a continuación, elija + Seleccionar miembros.

  7. En el cuadro de diálogo, busque el nombre de usuario de Microsoft Entra (normalmente su dirección de correo electrónico de user@domain) y, a continuación, elija Seleccionar en la parte inferior del cuadro de diálogo.

  8. Seleccione Revisar y asignar para ir a la página final y, a continuación, de nuevo Revisar y asignar para completar el proceso.

Configurar su proyecto

  1. En una ventana de consola (por ejemplo, PowerShell o Bash), use el comando dotnet new para crear una nueva aplicación de consola con el nombre BlobEncryptionKeyVault. Este comando crea un sencillo proyecto "Hola mundo" de C# con un solo archivo de origen: Program.cs.

    dotnet new console -n BlobEncryptionKeyVault
    
  2. Cambie al directorio BlobEncryptionKeyVault recién creado.

    cd BlobEncryptionKeyVault
    
  3. Abra el proyecto en el editor de código deseado. Para abrir el proyecto en:

    • Visual Studio, busque y haga doble clic en el archivo BlobEncryptionKeyVault.csproj.
    • Visual Studio Code, ejecute el siguiente comando:
    code .
    

Para interactuar con los servicios de Azure en este ejemplo, instale las siguientes bibliotecas cliente mediante dotnet add package.

dotnet add package Azure.Identity
dotnet add package Azure.Security.KeyVault.Keys
dotnet add package Azure.Storage.Blobs

Agregue las siguientes directivas using y asegúrese de agregar una referencia a System.Configuration al proyecto.

using Azure;
using Azure.Core;
using Azure.Identity;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;

Establecimiento de una variable de entorno

Esta aplicación busca una variable de entorno denominada KEY_VAULT_NAME para recuperar el nombre del almacén de claves. Para establecer la variable de entorno, abra una ventana de consola y siga las instrucciones de su sistema operativo. Reemplace <your-key-vault-name> por el nombre del almacén de claves.

Windows:

Puede establecer variables de entorno para Windows desde la línea de comandos. Sin embargo, al usar este enfoque, los valores son accesibles para todas las aplicaciones que se ejecutan en ese sistema operativo y pueden causar conflictos si no tiene cuidado. Las variables de entorno se pueden establecer en el nivel de usuario o del sistema:

setx KEY_VAULT_NAME "<your-key-vault-name>"

Después de agregar la variable de entorno en Windows, debe iniciar una nueva instancia de la ventana de comandos. Si usa Visual Studio en Windows, es posible que tenga que volver a iniciar Visual Studio después de crear la variable de entorno para que se detecte el cambio.

Linux:

export KEY_VAULT_NAME=<your-key-vault-name>

Incorporación de una clave en Azure Key Vault

En este ejemplo se crea una clave y se agrega al almacén de claves mediante la biblioteca cliente de Azure Key Vault. También puede crear y agregar una clave a un almacén de claves mediante la CLI de Azure, Azure Portal o PowerShell.

En el ejemplo siguiente creamos un objeto KeyClient para el almacén especificado. El objeto KeyClient se usa para crear una nueva clave RSA en el almacén especificado.

var keyName = "testRSAKey";
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");

// URI for the key vault resource
var keyVaultUri = $"https://{keyVaultName}.vault.azure.net";

TokenCredential tokenCredential = new DefaultAzureCredential();

// Create a KeyClient object
var keyClient = new KeyClient(new Uri(keyVaultUri), tokenCredential);

// Add a key to the key vault
var key = await keyClient.CreateKeyAsync(keyName, KeyType.Rsa);

Creación de instancias de clave y de resolución de claves

A continuación, usaremos la clave que acabamos de agregar al almacén para crear las instancias del cliente de criptografía y de resolución de claves. CryptographyClient implementa IKeyEncryptionKey y se usa para realizar operaciones criptográficas con claves que se almacenan en Azure Key Vault. KeyResolver implementa IKeyEncryptionResolver y recupera las claves de cifrado de claves del identificador de clave y resuelve esta.

// Cryptography client and key resolver instances using Azure Key Vault client library
CryptographyClient cryptoClient = keyClient.GetCryptographyClient(key.Value.Name, key.Value.Properties.Version);
KeyResolver keyResolver = new (tokenCredential);

Si tiene una clave existente en el almacén con la que desea cifrar, puede crear las instancias de clave y de resolución de claves pasando el URI:

var keyVaultKeyUri = $"https://{keyVaultName}.vault.azure.net/keys/{keyName}";
CryptographyClient cryptoClient = new CryptographyClient(new Uri(keyVaultKeyUri), tokenCredential);

Configuración de las opciones de cifrado

Ahora es necesario configurar las opciones de cifrado que se usarán para la carga y descarga de blobs. Para usar el cifrado del lado cliente, primero creamos un objeto ClientSideEncryptionOptions y lo establecemos en la creación de cliente con SpecializedBlobClientOptions.

La clase ClientSideEncryptionOptions proporciona las opciones de configuración de cliente para la conexión a Blob Storage mediante el cifrado del lado cliente. KeyEncryptionKey es necesario para las operaciones de carga y se usa para encapsular la clave de cifrado de contenido generada. KeyResolver es necesario para las operaciones de descarga y captura la clave de cifrado de claves correcta para desencapsular la clave de cifrado de contenido descargada. KeyWrapAlgorithm es necesario para las cargas y especifica el identificador de algoritmo que se va a usar al encapsular la clave de cifrado de contenido.

Importante

Debido a una vulnerabilidad de seguridad de la versión 1, se recomienda construir el objeto ClientSideEncryptionOptions mediante ClientSideEncryptionVersion.V2_0 para el parámetro version. Para más información sobre cómo mitigar la vulnerabilidad en las aplicaciones, consulte Mitigación de la vulnerabilidad de seguridad en las aplicaciones. Para más información sobre esta vulnerabilidad de seguridad, consulte Actualización de Azure Storage del cifrado del lado cliente en el SDK para abordar la vulnerabilidad de seguridad.

// Configure the encryption options to be used for upload and download
ClientSideEncryptionOptions encryptionOptions = new (ClientSideEncryptionVersion.V2_0)
{
    KeyEncryptionKey = cryptoClient,
    KeyResolver = keyResolver,
    // String value that the client library will use when calling IKeyEncryptionKey.WrapKey()
    KeyWrapAlgorithm = "RSA-OAEP"
};

// Set the encryption options on the client options.
BlobClientOptions options = new SpecializedBlobClientOptions() { ClientSideEncryption = encryptionOptions };

Configuración del objeto de cliente para usar el cifrado del lado cliente

En este ejemplo aplicamos las opciones de configuración de cifrado del lado cliente a un objeto BlobServiceClient. Cuando se aplican en el nivel de cliente de servicio, estas opciones de cifrado se pasan del cliente de servicio a los clientes de contenedor y de los clientes de contenedor a los clientes de blob. Cuando el objeto BlobClient realiza una operación de carga o descarga, las bibliotecas cliente de Azure Blob Storage usan el cifrado de sobre para cifrar y descifrar los blobs del lado cliente. El cifrado de sobres cifra una clave con una o varias claves adicionales.

// Create a blob client with client-side encryption enabled.
// Attempting to construct a BlockBlobClient, PageBlobClient, or AppendBlobClient from a BlobContainerClient
// with client-side encryption options present will throw, as this functionality is only supported with BlobClient.
Uri blobUri = new (string.Format($"https://{accountName}.blob.core.windows.net"));
BlobClient blob = new BlobServiceClient(blobUri, tokenCredential, options).GetBlobContainerClient("test-container").GetBlobClient("testBlob");

Cifrado y carga de blob

Cuando el objeto BlobClient llama a un método de carga, se producen varios pasos para realizar el cifrado del lado cliente:

  1. La biblioteca cliente de Azure Storage genera un vector de inicialización (IV) aleatorio de 16 bytes y una clave de cifrado de contenido (CEK) aleatoria de 32 bytes, y realiza el cifrado de sobre de los datos de blob con esta información.
  2. Los datos de blob se cifran mediante la CEK.
  3. A continuación, la CEK se encapsula (cifrada) mediante la clave de cifrado de claves (KEK) especificada en ClientSideEncryptionOptions. En este ejemplo, KEK es un par de claves asimétricas almacenado en el recurso de Azure Key Vault especificado. El propio cliente de blob nunca tiene acceso a la KEK, simplemente invoca el algoritmo de encapsulado de claves proporcionado por Key Vault.
  4. En ese momento, los datos cifrados del blob se cargan en la cuenta de almacenamiento.

Agregue el código siguiente para cifrar un blob y cargarlo en la cuenta de almacenamiento de Azure:

// Upload the encrypted contents to the blob
Stream blobContent = BinaryData.FromString("Ready for encryption, Captain.").ToStream();
await blob.UploadAsync(blobContent);

Una vez cargado el blob, podrá observarlo en la cuenta de almacenamiento para ver el contenido cifrado junto con los metadatos de cifrado.

Descifrado y carga del blob

La biblioteca cliente de Azure Storage asume que el usuario administra la KEK, desde ya sea el entorno local o un almacén de claves. El usuario no necesita conocer la clave específica que se usó para el cifrado. El solucionador de claves especificado en ClientSideEncryptionOptions se usará para resolver los identificadores de clave cuando se descargan y descifran los datos del blob.

Cuando el objeto BlobClient llama a un método de descarga, se producen varios pasos para descifrar los datos cifrados del blob:

  1. La biblioteca cliente descarga los datos cifrados del blob, incluidos los metadatos de cifrado, de la cuenta de almacenamiento.
  2. A continuación, la CEK encapsulada se desencapsula (descifra) mediante la KEK. La biblioteca cliente no tiene acceso a la KEK durante este proceso, sino que solo invoca el algoritmo de desencapsulado de claves especificado en ClientSideEncryptionOptions. La clave privada del par de claves RSA permanece en el almacén de claves, por lo que la clave cifrada de los metadatos del blob que contiene la CEK se envía al almacén de claves para el descifrado.
  3. La biblioteca cliente usa la CEK para descifrar los datos de blob cifrados.

Agregue el código siguiente para descargar y descifrar el blob que cargó previamente.

// Download and decrypt the encrypted contents from the blob
Response<BlobDownloadInfo>  response = await blob.DownloadAsync();
BlobDownloadInfo downloadInfo = response.Value;
Console.WriteLine((await BinaryData.FromStreamAsync(downloadInfo.Content)).ToString());

Pasos siguientes

En este tutorial ha aprendido a usar bibliotecas cliente de .NET para realizar el cifrado del lado cliente para las operaciones de carga y descarga de blobs.

Para información general sobre el cifrado del lado cliente para blobs, incluidas las instrucciones para migrar datos cifrados a la versión 2, consulte Cifrado de cliente para blobs.

Para más información sobre Azure Key Vault, consulte la página de introducción a Azure Key Vault.